diff --git a/CVSROOT/checkoutlist b/CVSROOT/checkoutlist deleted file mode 100644 index b04b3501f5efd94313942eb7439457bc82f5a2f5..0000000000000000000000000000000000000000 --- a/CVSROOT/checkoutlist +++ /dev/null @@ -1,13 +0,0 @@ -# The "checkoutlist" file is used to support additional version controlled -# administrative files in $CVSROOT/CVSROOT, such as template files. -# -# The first entry on a line is a filename which will be checked out from -# the corresponding RCS file in the $CVSROOT/CVSROOT directory. -# The remainder of the line is an error message to use if the file cannot -# be checked out. -# -# File format: -# -# [<whitespace>]<filename><whitespace><error message><end-of-line> -# -# comment lines begin with '#' diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo deleted file mode 100644 index b19e7b7a63e8e90cdb49c43f02035646c4a76e0a..0000000000000000000000000000000000000000 --- a/CVSROOT/commitinfo +++ /dev/null @@ -1,15 +0,0 @@ -# The "commitinfo" file is used to control pre-commit checks. -# The filter on the right is invoked with the repository and a list -# of files to check. A non-zero exit of the filter program will -# cause the commit to be aborted. -# -# The first entry on a line is a regular expression which is tested -# against the directory that the change is being committed to, relative -# to the $CVSROOT. For the first match that is found, then the remainder -# of the line is the name of the filter to run. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# If the name "ALL" appears as a regular expression it is always used -# in addition to the first matching regex or "DEFAULT". diff --git a/CVSROOT/config b/CVSROOT/config deleted file mode 100644 index ff43ec005ab332bc2aa7e1378754180e75a4b049..0000000000000000000000000000000000000000 --- a/CVSROOT/config +++ /dev/null @@ -1,14 +0,0 @@ -# Set this to "no" if pserver shouldn't check system users/passwords -#SystemAuth=no - -# Put CVS lock files in this directory rather than directly in the repository. -#LockDir=/var/lock/cvs - -# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top -# level of the new working directory when using the `cvs checkout' -# command. -#TopLevelAdmin=no - -# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the -# history file, or a subset as needed (ie `TMAR' logs all write operations) -#LogHistory=TOFEWGCMAR diff --git a/CVSROOT/cvswrappers b/CVSROOT/cvswrappers deleted file mode 100644 index 0accaf1b1532448d633d8a183cd8e3a5dd3b4a75..0000000000000000000000000000000000000000 --- a/CVSROOT/cvswrappers +++ /dev/null @@ -1,23 +0,0 @@ -# This file affects handling of files based on their names. -# -# The -t/-f options allow one to treat directories of files -# as a single file, or to transform a file in other ways on -# its way in and out of CVS. -# -# The -m option specifies whether CVS attempts to merge files. -# -# The -k option specifies keyword expansion (e.g. -kb for binary). -# -# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) -# -# wildcard [option value][option value]... -# -# where option is one of -# -f from cvs filter value: path to filter -# -t to cvs filter value: path to filter -# -m update methodology value: MERGE or COPY -# -k expansion mode value: b, o, kkv, &c -# -# and value is a single-quote delimited value. -# For example: -#*.gif -k 'b' diff --git a/CVSROOT/editinfo b/CVSROOT/editinfo deleted file mode 100644 index d78886c1522b6eae3470c13da218c3d8e197cf71..0000000000000000000000000000000000000000 --- a/CVSROOT/editinfo +++ /dev/null @@ -1,21 +0,0 @@ -# The "editinfo" file is used to allow verification of logging -# information. It works best when a template (as specified in the -# rcsinfo file) is provided for the logging procedure. Given a -# template with locations for, a bug-id number, a list of people who -# reviewed the code before it can be checked in, and an external -# process to catalog the differences that were code reviewed, the -# following test can be applied to the code: -# -# Making sure that the entered bug-id number is correct. -# Validating that the code that was reviewed is indeed the code being -# checked in (using the bug-id number or a seperate review -# number to identify this particular code set.). -# -# If any of the above test failed, then the commit would be aborted. -# -# Actions such as mailing a copy of the report to each reviewer are -# better handled by an entry in the loginfo file. -# -# One thing that should be noted is the the ALL keyword is not -# supported. There can be only one entry that matches a given -# repository. diff --git a/CVSROOT/loginfo b/CVSROOT/loginfo deleted file mode 100644 index a6a40e011bf383368e4abf36e585859c22e2f895..0000000000000000000000000000000000000000 --- a/CVSROOT/loginfo +++ /dev/null @@ -1,29 +0,0 @@ -# The "loginfo" file controls where "cvs commit" log information -# is sent. The first entry on a line is a regular expression which must match -# the directory that the change is being made to, relative to the -# $CVSROOT. If a match is found, then the remainder of the line is a filter -# program that should expect log information on its standard input. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# If the name ALL appears as a regular expression it is always used -# in addition to the first matching regex or DEFAULT. -# -# You may specify a format string as part of the -# filter. The string is composed of a `%' followed -# by a single format character, or followed by a set of format -# characters surrounded by `{' and `}' as separators. The format -# characters are: -# -# s = file name -# V = old version number (pre-checkin) -# v = new version number (post-checkin) -# -# For example: -#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog -# or -#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog -^sm5$ /cvsroot/sitedocs/CVSROOT/cvstools/syncmail -u %{sVv} smartmontools-cvs@lists.sourceforge.net -^sm5/os_win32$ /cvsroot/sitedocs/CVSROOT/cvstools/syncmail -u %{sVv} smartmontools-cvs@lists.sourceforge.net -^www$ /cvsroot/sitedocs/CVSROOT/cvstools/syncmail -u %{sVv} ballen4705@users.sourceforge.net diff --git a/CVSROOT/modules b/CVSROOT/modules deleted file mode 100644 index cb9e9efc94b342879a5fff24b425473fc11edd01..0000000000000000000000000000000000000000 --- a/CVSROOT/modules +++ /dev/null @@ -1,26 +0,0 @@ -# Three different line formats are valid: -# key -a aliases... -# key [options] directory -# key [options] directory files... -# -# Where "options" are composed of: -# -i prog Run "prog" on "cvs commit" from top-level of module. -# -o prog Run "prog" on "cvs checkout" of module. -# -e prog Run "prog" on "cvs export" of module. -# -t prog Run "prog" on "cvs rtag" of module. -# -u prog Run "prog" on "cvs update" of module. -# -d dir Place module in directory "dir" instead of module name. -# -l Top-level directory only -- do not recurse. -# -# NOTE: If you change any of the "Run" options above, you'll have to -# release and re-checkout any working directories of these modules. -# -# And "directory" is a path to a directory relative to $CVSROOT. -# -# The "-a" option specifies an alias. An alias is interpreted as if -# everything on the right of the "-a" had been typed on the command line. -# -# You can encode a module within a module by using the special '&' -# character to interpose another module into the current module. This -# can be useful for creating a module that consists of many directories -# spread out over the entire source repository. diff --git a/CVSROOT/notify b/CVSROOT/notify deleted file mode 100644 index 34f0bc288808e56e499d0852a9bfc9a3214b02d9..0000000000000000000000000000000000000000 --- a/CVSROOT/notify +++ /dev/null @@ -1,12 +0,0 @@ -# The "notify" file controls where notifications from watches set by -# "cvs watch add" or "cvs edit" are sent. The first entry on a line is -# a regular expression which is tested against the directory that the -# change is being made to, relative to the $CVSROOT. If it matches, -# then the remainder of the line is a filter program that should contain -# one occurrence of %s for the user to notify, and information on its -# standard input. -# -# "ALL" or "DEFAULT" can be used in place of the regular expression. -# -# For example: -#ALL mail %s -s "CVS notification" diff --git a/CVSROOT/rcsinfo b/CVSROOT/rcsinfo deleted file mode 100644 index 49e59f4d0df9b432c5b99c0b806378a77c9cd870..0000000000000000000000000000000000000000 --- a/CVSROOT/rcsinfo +++ /dev/null @@ -1,13 +0,0 @@ -# The "rcsinfo" file is used to control templates with which the editor -# is invoked on commit and import. -# -# The first entry on a line is a regular expression which is tested -# against the directory that the change is being made to, relative to the -# $CVSROOT. For the first match that is found, then the remainder of the -# line is the name of the file that contains the template. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# If the name "ALL" appears as a regular expression it is always used -# in addition to the first matching regex or "DEFAULT". diff --git a/CVSROOT/taginfo b/CVSROOT/taginfo deleted file mode 100644 index 274a46dd5b61069f1cea62395178b09aa3120248..0000000000000000000000000000000000000000 --- a/CVSROOT/taginfo +++ /dev/null @@ -1,20 +0,0 @@ -# The "taginfo" file is used to control pre-tag checks. -# The filter on the right is invoked with the following arguments: -# -# $1 -- tagname -# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d -# $3 -- repository -# $4-> file revision [file revision ...] -# -# A non-zero exit of the filter program will cause the tag to be aborted. -# -# The first entry on a line is a regular expression which is tested -# against the directory that the change is being committed to, relative -# to the $CVSROOT. For the first match that is found, then the remainder -# of the line is the name of the filter to run. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# If the name "ALL" appears as a regular expression it is always used -# in addition to the first matching regex or "DEFAULT". diff --git a/CVSROOT/verifymsg b/CVSROOT/verifymsg deleted file mode 100644 index 86f747ce222390e6aa7a488074e372030d57a479..0000000000000000000000000000000000000000 --- a/CVSROOT/verifymsg +++ /dev/null @@ -1,21 +0,0 @@ -# The "verifymsg" file is used to allow verification of logging -# information. It works best when a template (as specified in the -# rcsinfo file) is provided for the logging procedure. Given a -# template with locations for, a bug-id number, a list of people who -# reviewed the code before it can be checked in, and an external -# process to catalog the differences that were code reviewed, the -# following test can be applied to the code: -# -# Making sure that the entered bug-id number is correct. -# Validating that the code that was reviewed is indeed the code being -# checked in (using the bug-id number or a seperate review -# number to identify this particular code set.). -# -# If any of the above test failed, then the commit would be aborted. -# -# Actions such as mailing a copy of the report to each reviewer are -# better handled by an entry in the loginfo file. -# -# One thing that should be noted is the the ALL keyword is not -# supported. There can be only one entry that matches a given -# repository. diff --git a/sm5/.cvsignore b/sm5/.cvsignore deleted file mode 100644 index 85c60d8adb27e6bc8c0d54b7f511eff2ee64d255..0000000000000000000000000000000000000000 --- a/sm5/.cvsignore +++ /dev/null @@ -1,46 +0,0 @@ -*.gz -*.o -*.rpm -*.tar.gz -*.tar.gz.asc -*~ -.deps -.gdb_history -Makefile -Makefile.in -VERSION -aclocal.m4 -add -autom4te.cache -autotools.diff -build -config.guess -config.h -config.h.in -config.log -config.status -config.sub -configure -core -cvs-script -depcomp -install-sh -missing -mkinstalldirs -smartctl -smartctl.8 -smartctl.1m -smartctl.exe -smartd -smartd.8 -smartd.1m -smartd.conf.5 -smartd.conf.4 -smartd.conf.sample -smartd.initd -smartd.exe -stamp-h -stamp-h.in -stamp-h1 -writelog.c -SMART diff --git a/sm5/AUTHORS b/sm5/AUTHORS deleted file mode 100644 index 6405f856f1a1a1e153949c81c02ae6be6dd07e50..0000000000000000000000000000000000000000 --- a/sm5/AUTHORS +++ /dev/null @@ -1,30 +0,0 @@ -$Id: AUTHORS,v 1.13 2004/07/16 01:41:19 geoffk1 Exp $ - -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 package is meant to be an up-to-date replacement for the -ucsc-smartsuite and smartsuite packages, and is derived from that code. - -Maintainers / Developers: - -Bruce Allen <smartmontools-support@lists.sourceforge.net> -Erik Inge Bols� <knan@mo.himolde.no> -Stanislav Brabec <sbrabec@suse.cz> -Peter Cassidy <pcassidy@mac.com> -Casper Dik <casper@holland.sun.com> -Christian Franke <franke@computer.org> -Guilhem Fr�zou <guilhem.frezou@catii.fr> -Douglas Gilbert <dougg@torque.net> -Guido Guenther <agx@sigxcpu.org> -Geoff Keating <geoffk@geoffk.org> -Dr. David Kirkby <drkirkby@ntlworld.com> -Kai M�kisara <kai.makisara@kolumbus.fi> -Eduard Martinescu <martines@rochester.rr.com> -Fr�d�ric L. W. Meunier <http://www.pervalidus.net/contact.html> -Keiji Sawada <card_captor@users.sourceforge.net> -Sergey Svishchev <svs@ropnet.ru> -Phil Williams <phil@subbacultcha.demon.co.uk> -Richard Zybert <richard.zybert@zybert.co.uk> diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG deleted file mode 100644 index 44b5c6d97458e32ee945b778c71f07fe4a707788..0000000000000000000000000000000000000000 --- a/sm5/CHANGELOG +++ /dev/null @@ -1,1857 +0,0 @@ -CHANGELOG for smartmontools - -$Id: CHANGELOG,v 1.447 2004/08/16 22:44:15 ballen4705 Exp $ - -The most recent version of this file is: -http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?sortby=date&view=markup - -Maintainers / Developers Key: -[BA] Bruce Allen -[EB] Erik Inge Bols� -[SB] Stanislav Brabec -[PC] Peter Cassidy -[CD] Caper Dik -[CF] Christian Franke -[GF] Guilhem Fr�zou -[DG] Douglas Gilbert -[GG] Guido Guenther -[GK] Geoff Keating -[DK] Dr. David Kirkby -[KM] Kai M�kisara -[EM] Eduard Martinescu -[FM] Fr�d�ric L. W. Meunier -[KS] Keiji Sawada -[SS] Sergey Svishchev -[PW] Phil Williams -[RZ] Richard Zybert - -NOTES FOR FUTURE RELEASES: see TODO file. - -<ADDITIONS TO THE CHANGE LOG SHOULD BE ADDED JUST BELOW HERE, PLEASE> - - [BA] Additional modifications of Ed's controller scheme. Fixed - broken 3ware support under linux, problems with scanning - devices in smartd, and other small problems. - - [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 #848 at - http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=query - - 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 diff --git a/sm5/COPYING b/sm5/COPYING deleted file mode 100644 index d60c31a97a544b53039088d14fe9114583c0efc3..0000000000000000000000000000000000000000 --- a/sm5/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General -Public License instead of this License. diff --git a/sm5/INSTALL b/sm5/INSTALL deleted file mode 100644 index 3519156a08c3d057f14f9bb94ae27c84ef3f737a..0000000000000000000000000000000000000000 --- a/sm5/INSTALL +++ /dev/null @@ -1,572 +0,0 @@ -Smartmontools installation instructions -======================================= - -$Id: INSTALL,v 1.54 2004/08/14 20:04:38 chrfranke Exp $ - -Please also see the smartmontools home page: -http://smartmontools.sourceforge.net/ - -Table of contents: - -[1] System requirements -[2] Installing from CVS -[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] Comments -[12] 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.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 - - 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.5.7 and 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 98SE, NT4, 2000 and XP. It should also - work on Windows 95(OSR2), 98, ME and 2003. - - On 9x/ME, only standard (legacy) IDE/ATA devices 0-3 are supported. - The driver SMARTVSD.VXD must be present in WINDOWS\SYSTEM\IOSUBSYS - to get loaded at Windows startup. The default location in a new - installation of some versions of Windows is the WINDOWS\SYSTEM folder. - In this case, move SMARTVSD.VXD to WINDOWS\SYSTEM\IOSUBSYS and reboot - (http://support.microsoft.com/default.aspx?scid=kb;en-us;265854). - - On NT4/2000/XP, also other ATA or SATA devices are supported if - the device driver implements the SMART IOCTL. - - The IDE/ATA read log command (smartctl -l, --log, -a, --all) is - not supported on NT4. On 2000/XP, the undocumented and possibly buggy - IOCTL_IDE_PASS_THROUGH is used for this purpose (see WARNINGS file). - - SCSI devices are supported on all versions of Windows. An installed - ASPI interface (WNASPI32.DLL) is required to access SCSI devices. - - 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. - - There's an important limitation (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 capture mode - - aborting tests - - switching on automatic offline testing - - support for SCSI - - checking the power mode [-n Directive of smartd] (this is not - completely impossible, but not by using a documented API) - - * Are implemented, but don't work due to OS bugs: - - 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) - -The last set have been filed in Apple's bug tracking system and -hopefully will be fixed. - -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. - - -[2] Installing from CVS -======================= - Get the sources from the CVS repository: - cvs -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools login - cvs -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools co sm5 - (when prompted for a password, just press Enter) - - Then type: - ./autogen.sh - and continue with step [3] below, skipping the "unpack the tarball" step. - - Further details of using CVS can be found at the URL above. - - The autogen.sh command is ONLY required when installing from - CVS. You need GNU Autoconf (version 2.50 or greater), GNU Automake - (version 1.6 or greater) and their dependencies installed in order - to run it. You can get these here: - http://www.gnu.org/directory/GNU/autoconf.html - http://www.gnu.org/directory/GNU/automake.html - -[3] Installing from the source tarball -====================================== - - If you are NOT installing from CVS, 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 - --with-docdir=/usr/local/share/doc/smartmontools-VERSION - --with-initscriptdir=/usr/local/etc/rc.d/init.d - --disable-sample - - 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 CFLAGS='your options' before doing - ./configure, or else do: - make CFLAGS='your options' - -[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 \ - --with-initscriptdir=/usr/local/etc/rc.d/init.d \ - --with-docdir=/usr/local/share/doc/smartmontools-VERSION - -Red Hat: - ./configure --sbindir=/usr/sbin \ - --sysconfdir=/etc \ - --mandir=/usr/share/man \ - --with-initscriptdir=/etc/rc.d/init.d \ - --with-docdir=/usr/share/doc/smartmontools-VERSION - -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 \ - --with-initscriptdir=/etc/rc.d \ - --with-docdir=/usr/share/doc/smartmontools-VERSION - - 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 \ - --with-initscriptdir=/etc/init.d \ - --with-docdir=/usr/share/doc/packages/smartmontools-VERSION - -[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 \ - --with-initscriptdir=/usr/local/etc/rc.d/ \ - --with-docdir=/usr/local/share/doc/smartmontools-VERSION \ - --enable-sample - - Also, it is important that you use GNU make (gmake from /usr/ports/devel/gmake) - to build smartmontools, as the default FreeBSD make doesn't know how to build - the man pages. - - 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 - - -[7] Guidelines for NetBSD -========================= - ./configure --prefix=/usr/pkg \ - --with-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 or gcc. To compile - with gcc: - - ./configure [args] - make - - To compile with Sun cc: - - setenv CC cc [csh syntax], or - CC=cc [sh syntax] - ./configure [args] - make - - The correct arguments [args] to configure are: - --sbindir=/usr/sbin \ - --sysconfdir=/etc \ - --mandir=/usr/share/man \ - --with-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: - K<knum>smartd in rcS.d, rc0.d, rc1.d, rc2.d - S<snum>smartd in rc3.d - where <knum> is related to <snum> such that the higher snum is the - lower knum must be. - - On usual configuration, '95' would be suitable for <snum> and '05' - for <knum> 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 \ - --with-initscriptdir=/etc/rc.d/init.d \ - --with-docdir=/usr/share/doc/smartmontools-VERSION - - 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. - -[10] Guidelines for Windows -========================== - -To compile the Windows release with MinGW, use the following on Cygwin: - - ./configure --build=mingw32 - make - - Instead of using "make install", copy the .exe files into - some directory in the PATH. - -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 - - 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. - - It is also possible to compile smartmontools with MSVC 6.0. - The project files (smartmontools_vc6.dsw, smart{ctl,d}_vc6.dsp) are - included in CVS (but not in source tarball). The config_vc6.h is no - longer maintained in CVS. The command: - - make config-vc6 - - builds config_vc6.h from MinGW's config.h. Unlike MinGW, MSVC 6.0 - can also be used to build the syslog message file tool syslogevt.exe. - See smartd man page for usage information about this tool. - - -[11] Comments -============ - -To compile from another directory, you can replace the step - ./configure [options] -by the following: - mkdir objdir - cd objdir - ../configure [options] - -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 RPM packages are available at -http://sourceforge.net/project/showfiles.php?group_id=64297 - -Refer to http://smartmontools.sourceforge.net/index.html#howtodownload -for any additional download and installation instructions. - -The following files are installed if ./configure has no options: - -/usr/local/sbin/smartd [Executable daemon] -/usr/local/sbin/smartctl [Executable command-line utility] -/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-5.X/AUTHORS [Information about the authors and developers] -/usr/local/share/doc/smartmontools-5.X/CHANGELOG [A log of changes. Also see CVS] -/usr/local/share/doc/smartmontools-5.X/COPYING [GNU General Public License Version 2] -/usr/local/share/doc/smartmontools-5.X/INSTALL [Installation instructions: what you're reading!] -/usr/local/share/doc/smartmontools-5.X/NEWS [Significant bugs discovered in old versions] -/usr/local/share/doc/smartmontools-5.X/README [Overview] -/usr/local/share/doc/smartmontools-5.X/TODO [Things that need to be done/fixed] -/usr/local/share/doc/smartmontools-5.X/WARNINGS [Systems where lockups or other serious problems were reported] -/usr/local/share/doc/smartmontools-5.X/smartd.conf [Example configuration file for smartd] -/usr/local/share/doc/smartmontools-5.X/examplescripts [Executable scripts for -M exec of smartd.conf (4 files)] - -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 - - -[12] 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 ---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 ${sysconfdir}/init.d/rc.d Location of init scripts ---with-docdir ${prefix}/share/doc/smartmontools-5.X Location of the documentation ---enable-sample --disable-sample Adds the string '.sample' to the names of the smartd.conf file and the smartd RC file - -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 ---mandir /home/joe/share/man ---sysconfdir /home/joe/etc ---with-initscriptdir /home/joe/etc/init.d/rc.d ---with-docdir /home/joe/doc/smartmontools-5.X - -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 -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-2.57/html_mono/autoconf.html#SEC139 diff --git a/sm5/Makefile.am b/sm5/Makefile.am deleted file mode 100644 index ffb43e784453fbe9559ab8ab62a08c6da869c680..0000000000000000000000000000000000000000 --- a/sm5/Makefile.am +++ /dev/null @@ -1,416 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# $Id: Makefile.am,v 1.60 2004/08/14 20:04:39 chrfranke Exp $ -# - -@SET_MAKE@ - -AM_CPPFLAGS = -DSMARTMONTOOLS_SYSCONFDIR=\"$(sysconfdir)\" - -sbin_PROGRAMS = smartd \ - smartctl - -smartd_SOURCES = smartd.c \ - smartd.h \ - atacmdnames.c \ - atacmdnames.h \ - atacmds.c \ - atacmds.h \ - ataprint.c \ - ataprint.h \ - extern.h \ - int64.h \ - knowndrives.c \ - knowndrives.h \ - scsicmds.c \ - scsicmds.h \ - scsiprint.c \ - scsiprint.h \ - utility.c \ - utility.h - -smartd_LDADD = @os_deps@ @os_libs@ -smartd_DEPENDENCIES = @os_deps@ -EXTRA_smartd_SOURCES = os_darwin.c \ - os_darwin.h \ - os_linux.c \ - os_linux.h \ - os_freebsd.c \ - os_freebsd.h \ - os_netbsd.c \ - os_netbsd.h \ - os_solaris.c \ - os_solaris.h \ - os_solaris_ata.s \ - os_win32.c \ - os_generic.c \ - os_generic.h - - -if OS_WIN32_MINGW - -EXTRA_smartd_SOURCES += \ - posix/regex.h \ - posix/regex.c \ - posix/regcomp.c \ - posix/regexec.c \ - posix/regex_internal.c \ - posix/regex_internal.h \ - os_win32/daemon_win32.h \ - os_win32/daemon_win32.c \ - os_win32/hostname_win32.h \ - os_win32/hostname_win32.c \ - os_win32/syslog.h \ - os_win32/syslog_win32.c - -endif - -smartctl_SOURCES= smartctl.c \ - smartctl.h \ - atacmdnames.c \ - atacmdnames.h \ - atacmds.c \ - atacmds.h \ - ataprint.c \ - ataprint.h \ - extern.h \ - int64.h \ - knowndrives.c \ - knowndrives.h \ - scsicmds.c \ - scsicmds.h \ - scsiprint.c \ - scsiprint.h \ - utility.c \ - utility.h - -smartctl_LDADD = @os_deps@ @os_libs@ -smartctl_DEPENDENCIES = @os_deps@ -EXTRA_smartctl_SOURCES = os_linux.c \ - os_linux.h \ - os_freebsd.c \ - os_freebsd.h \ - os_netbsd.c \ - os_netbsd.h \ - os_solaris.c \ - os_solaris.h \ - os_win32.c \ - os_generic.c \ - os_generic.h - -if OS_WIN32_MINGW - -EXTRA_smartctl_SOURCES += \ - posix/regex.h \ - posix/regex.c \ - posix/regcomp.c \ - posix/regexec.c \ - posix/regex_internal.c \ - posix/regex_internal.h \ - os_win32/syslog.h - -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 \ - COPYING \ - INSTALL \ - NEWS \ - README \ - TODO \ - WARNINGS \ - smartd.conf - -sysconf_DATA = smartd.conf$(smartd_suffix) - -if SMARTD_SUFFIX -smartd.conf$(smartd_suffix): smartd.conf - cp smartd.conf smartd.conf$(smartd_suffix) -endif - -EXTRA_DIST = \ - smartmontools.spec \ - smartd.initd.in \ - smartd.8.in \ - smartctl.8.in \ - smartd.conf.5.in \ - smartd.conf \ - autogen.sh \ - $(docs_DATA) - -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 \ - SMART - - - -smartd.conf.5.in: smartd.8.in - sed '1,/STARTINCLUDE/ D;/ENDINCLUDE/,$$D' < $(srcdir)/smartd.8.in > $(top_builddir)/tmp.directives - sed '/STARTINCLUDE/,$$D' < $(srcdir)/smartd.conf.5.in > $(top_builddir)/tmp.head - sed '1,/ENDINCLUDE/D' < $(srcdir)/smartd.conf.5.in > $(top_builddir)/tmp.tail - cat $(top_builddir)/tmp.head > $(srcdir)/smartd.conf.5.in - echo '.\" STARTINCLUDE' >> $(srcdir)/smartd.conf.5.in - cat $(top_builddir)/tmp.directives >> $(srcdir)/smartd.conf.5.in - echo '.\" ENDINCLUDE' >> $(srcdir)/smartd.conf.5.in - cat $(top_builddir)/tmp.tail >> $(srcdir)/smartd.conf.5.in - rm -f $(top_builddir)/tmp.head $(top_builddir)/tmp.tail $(top_builddir)/tmp.directives - -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 - -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 - @echo -e "\n\n####################################################################\n#" - @echo -e "# PLEASE READ THIS BOX!\n#" - @echo -e "# To manually start the smartd daemon, run:\n# ${initddir}/SMART/SMART start\n#" - @echo -e "# To automatically start smartd on bootup, add the line:\n# SMARTd=-YES-\n# to /etc/hostconfig\n#" - @echo -e "# smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n# man smartd" - @echo -e "# to learn about it. A sample configuration file can be found in:\n# ${docdir}\n#" - @echo -e "####################################################################\n\n" - -else - -initd_DATA = smartd.initd - -initd_install_name = smartd$(smartd_suffix) - -initd_DATA_install = install-initdDATA-generic - -install-initdDATA-generic: $(initd_DATA) - $(mkinstalldirs) $(DESTDIR)$(initddir) - $(INSTALL_SCRIPT) $(top_builddir)/smartd.initd $(DESTDIR)$(initddir)/smartd$(smartd_suffix) - @echo -e "\n\n####################################################################\n#" - @echo -e "# PLEASE READ THIS BOX!\n#" - @echo -e "# To manually start the smartd daemon, run:\n# ${initddir}/smartd start\n#" - @echo -e "# To automatically start smartd on bootup, run:\n# /sbin/chkconfig --add smartd\n#" - @echo -e "# smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n# man smartd" - @echo -e "# to learn about it. A sample configuration file can be found in:\n# ${docdir}\n#" - @echo -e "####################################################################\n\n" - -endif - -install-initdDATA : $(initd_DATA_install) - -uninstall-initdDATA: - rm -rf $(DESTDIR)$(initddir)/$(initd_install_name) - -uninstall-docsDATA: - rm -rf $(DESTDIR)$(docsdir) - -smart%: $(srcdir)/smart%.in Makefile - sed "s|CURRENT_CVS_VERSION|$(releaseversion)|g" $< | \ - sed "s|CURRENT_CVS_DATE|$(smartmontools_release_date)|g" | \ - sed "s|CURRENT_CVS_TIME|$(smartmontools_release_time)|g" | \ - sed "s|/usr/share/man/|$(mandir)/|g" | \ - sed "s|/usr/sbin/|$(sbindir)/|g" | \ - sed "s|/etc/rc\\.d/init.d/|$(initddir)/|g" | \ - sed "s|/usr/share/doc/smartmontools-5\\.1/|$(docsdir)/|g" | \ - sed "s|/etc/smartd\\.conf|$(sysconfdir)/smartd\\.conf|g" > $@ - - -# Commands to convert man pages into .html and .txt -# TODO: configure -MAN2HTML = man2html -#MAN2HTML = groff -man -Thtml -MAN2TXT = groff -man -Tascii -P'-bcou' - -# Remove useless links from man2html output -FIXHTML = sed 's,http://localhost/[-a-z/]*/man2html?\([1-8]\)+\([a-z.]*\),\2.\1.html,g' \ - | sed 's,http://localhost/[-a-z/]*/man2html",.",' \ - | sed 's,<A HREF="[bisfp][adyo][desrp][-a-zP1-8.]*">\([-a-zP.]*\)</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 - -%.5.html: %.5 - $(MAN2HTML) $< | $(FIXHTML) > $@ - -%.8.html: %.8 - $(MAN2HTML) $< | $(FIXHTML) > $@ - -%.5.txt: %.5 - $(MAN2TXT) $< > $@ - -%.8.txt: %.8 - $(MAN2TXT) $< > $@ - - - -if OS_WIN32_MINGW -# Definitions for Windows distribution - -distdir_win32 = $(PACKAGE)-$(VERSION).win32 -distzip_win32 = $(PACKAGE)-$(VERSION).win32.zip - -exedir_win32 = $(distdir_win32)/bin -docdir_win32 = $(distdir_win32)/doc - -FILES_WIN32 = $(exedir_win32)/smartctl.exe \ - $(exedir_win32)/smartd.exe \ - $(docdir_win32)/AUTHORS.txt \ - $(docdir_win32)/CHANGELOG.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)/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 - -CLEANFILES += $(FILES_WIN32) $(exedir_win32)/syslogevt.exe distdir.mkdir syslogevt.check - -# Textfile converter from cygutils -UNIX2DOS = unix2dos -D - -# Build Windows distribution - -dist-win32: $(distzip_win32) - -distdir-win32: distdir.mkdir $(FILES_WIN32) syslogevt.check - -$(distzip_win32): distdir.mkdir $(FILES_WIN32) syslogevt.check - @rm -fv $(distzip_win32) - cd $(distdir_win32) && zip -9Dr ../$(distzip_win32) . - -cleandist-win32: - rm -rf $(distdir_win32) distdir.mkdir syslogevt.check - -distdir.mkdir: - @test -d $(exedir_win32) || mkdir -pv $(exedir_win32) - @test -d $(docdir_win32) || mkdir -pv $(docdir_win32) - touch $@ - -syslogevt.check: - @if [ -f $(srcdir)/os_win32/syslogevt.exe ]; then \ - cp -pv $(srcdir)/os_win32/syslogevt.exe $(exedir_win32)/syslogevt.exe; \ - else echo "Warning: $(srcdir)/os_win32/syslogevt.exe missing."; fi - touch $@ - -$(exedir_win32)/%.exe: %.exe - cp -p $< $@ - strip -p -s $@ - -$(docdir_win32)/%.txt: $(srcdir)/% - $(UNIX2DOS) < $< > $@ - touch -r $< $@ - -$(docdir_win32)/%.conf: $(srcdir)/%.conf - $(UNIX2DOS) < $< > $@ - touch -r $< $@ - -$(docdir_win32)/%: % - $(UNIX2DOS) < $< > $@ - touch -r $< $@ - - -# Build config_vc6.h for MSVC 6 from MinGW config.h - -config-vc6: $(srcdir)/os_win32/config_vc6.h - -$(srcdir)/os_win32/config_vc6.h: config.h - sed '1i/* config_vc6.h. Generated by Makefile. */' $< | \ - sed 's,^#define HAVE_\(INTTYPES_H\|STDINT_H\|STRTOULL\|UNISTD_H\) 1$$,/* #undef HAVE_\1 */,' | \ - sed 's,i.86-pc-mingw32,i686-pc-win32vc6,' > $@ - -endif - -SUBDIRS= . examplescripts diff --git a/sm5/NEWS b/sm5/NEWS deleted file mode 100644 index ce48b03d0c6bca15f5700d62d04e35268226016b..0000000000000000000000000000000000000000 --- a/sm5/NEWS +++ /dev/null @@ -1,170 +0,0 @@ -smartmontools NEWS ------------------- -CVS ID: $Id: NEWS,v 1.23 2004/07/07 14:45:19 ballen4705 Exp $ - -The most up-to-date version of this file is: -http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/NEWS?sortby=date&view=markup - -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://cvs.sourceforge.net/viewcvs.py/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 3389 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. diff --git a/sm5/README b/sm5/README deleted file mode 100644 index 5ecca0b6acbdab96147b8640c002f663f61f6530..0000000000000000000000000000000000000000 --- a/sm5/README +++ /dev/null @@ -1,105 +0,0 @@ -==================================================== -smartmontools - S.M.A.R.T. utility toolset for Linux -==================================================== - -$Id: README,v 1.50 2004/05/03 15:58:33 ballen4705 Exp $ - -== 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-4 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., 675 -Mass Ave, Cambridge, MA 02139, 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/project/showfiles.php?group_id=64297 - -CVS ---- - -cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools login (when prompted for a password, just press Enter) -cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools co sm5 - -This will create a subdirectory called sm5/ containing the code. - -To instead get the 5.1-16 release: - -cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools co -r RELEASE_5_1_16 sm5 - -To update your sources to the 5.1-18 release: - -cd sm5 -cvs up -r RELEASE_5_1_18 - -To update any tagged release to the latest development code: - -cd sm5 -cvs up -A - -You can see what the different tags are by looking at -http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/smartmontools/sm5/ . -You'll see the tag names in the little scroll window where it says "Show -only files with tag". - -== BUILDING/INSTALLING SMARTMONTOOLS == - -Refer to the "INSTALL" file for installation instructions. - -See the "WARNINGS" file for reports of hardware where these utilities -might cause serious problems such as lockups. diff --git a/sm5/TODO b/sm5/TODO deleted file mode 100644 index 13856c06ae0885580830feb8cc3621bfb4290d5d..0000000000000000000000000000000000000000 --- a/sm5/TODO +++ /dev/null @@ -1,108 +0,0 @@ -TODO list for smartmontools: - -$Id: TODO,v 1.54 2004/08/06 13:11:35 chrfranke Exp $ - -SATA devices ------------- -Currently work OK if you use the standard IDE drivers in -drivers/ide. If you use the new libata drivers, it won't work -correctly because libata doesn't yet support the needed -ATA-passthrough ioctl() calls. Jeff Garzik, the libata developer, says -that this support will be added in the future. When this happens, add -support to smartmontools for a new SATA/libata device type '-d sata'. - -USB devices ------------ -Some USB devices can hang smartctl or smartd. This is because these -devices fail to comply with SCSI specifications for their packet -command sets. Work on improving the detection and bail-out procedures -for these flawed devices, so that the user sees an informative error -message and smartd/smartctl don't hang. - -ATA-4 (no kidding!) -------------------- -smartctl: add another -t TESTTYPE option to accomodate old-style ATA-4 -IBM disks (ATA-4 has no self-test commands). See IBM S25L-2426-02 OEM -HARD DISK DRIVE SPECIFICATIONS for DBCA-203240/204860/206480 2.5-Inch -Hard Disk Drive with ATA Interface Revision (1.0) -http://www.hgst.com/tech/techlib.nsf/techdocs/85256AB8006A31E587256A7D00642A1D/$file/dbca_sp.pdf -section 12.30.1.5 for details. These disks offer no self-test option, -and the -t offline command only tests a small part of the disk (a -'segment'). We need a -t multioffline that: - (1) issues auto offline immediate command (tests ONE segment) - (2) waits until estimated completion time - (3) tests if off-line data collection status is set to 0x02 (all - segments completed) - (4) if not, return to (1) - -ATA-6/7 -------- -Support extended error logs -Support extended self-test logs - -smartctl/smartd ---------------- -Add additional -v options (corresponding to comments in -atacmds.c:ataPrintSmartAttribName(). - -Add interface to Megaraid ATA RAID controllers (Erik) - -smartctl: ---------- -Add command line option to issue SMART SAVE ATTRIBUTE VALUES command -Feature Register value ATA_SMART_SAVE 0xd3 - -Perhaps modify the -q option (quiet mode) so that it only warns of ATA -errors if they have (say) taken place in the last 168 hours (week). - -Parse and print additional Attribute flag meanings (IBM ones, eg -performance etc). These are now documented in atacmds.h -- we just -need to modify the format of the Attribute table. - -Modify the SMART self-test log table printing so that we ALSO print -the value of the self-test failure checkpoint byte, if it's one of the -recognized values. See routine SelfTestFailureCodeName and -documentation in atacmds.h. - -smartd: -------- -Perhaps change <nomailer> special argument to -m to have also -<nomailer_fork> which would actually work with -M exec to run the -executable/script in the background rather than in the foreground. -But let's wait for someone to request this. At that point we should -probably use fork/exec rather than system(). - -Perhaps change smartd to look in /proc/ide and /proc/scsi to see what -exists? If something doesn't exit then don't try to open it? This -should probably be the default option if there is no configuration -file. - -Add ability to monitor "worst" value from attributes (sometimes it -gets larger!) and to monitor the threshold value (sometimes it -changes!). - -Add command line option that scans devices then WRITES -/etc/smartd.conf, perhaps as /etc/smartd.conf.output, just for devices -that can be monitored. - -FreeBSD -------- -Get interface for 3ware Escalade controllers working (Eduard). -Modify smartctl -h examples - -Cygwin and Windows ------------------- -Add IDE/ATA selective self test and check power mode. - -Access SCSI devices via IOCTL_SCSI_PASS_THROUGH on 2000/XP -to support systems with missing ASPI driver. - -Windows -------- -Provide some installer. - -Packaging ---------- -Under freebsd and solaris, the following are wrong: -smartd.conf: has linux device paths -smart*.in : man pages have (mostly) linux device paths diff --git a/sm5/WARNINGS b/sm5/WARNINGS deleted file mode 100644 index d4dbb4c889779df8618571653a767a4ffc9888ed..0000000000000000000000000000000000000000 --- a/sm5/WARNINGS +++ /dev/null @@ -1,123 +0,0 @@ -$Id: WARNINGS,v 1.30 2004/07/17 23:19:00 geoffk1 Exp $ - -The most recent version of this file can be found here: -http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/WARNINGS?view=markup - -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 ------------------- - -SYSTEM: Any Windows 2000 or XP system. -PROBLEM: Use of an undocumented system call for IDE/ATA read log - (smartctl -l, --log, -a, --all) may affect system stability. -REPORTER: Christian Franke <smartmontools-support@lists.sourceforge.net> -NOTE: The IOCTL call SMART_RCV_DRIVE_DATA does not support - ATA_SMART_READ_LOG_SECTOR on NT4/2000/XP. The Win32 - implementation of smartctl/smartd uses the undocumented - and possibly buggy IOCTL_IDE_PASS_THROUGH for this purpose. - This IOCTL is not implemented under NT4. - Invalid log output has been reported for at least one - W2K system. - -DARWIN ------- - -SYSTEM: Any system up to at least 7H63 -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. diff --git a/sm5/atacmdnames.c b/sm5/atacmdnames.c deleted file mode 100644 index 05d6f408dbdce3883d7be78d7f69bdf270eb5670..0000000000000000000000000000000000000000 --- a/sm5/atacmdnames.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * atacmdnames.c - * - * 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-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "atacmdnames.h" -#include <stdlib.h> -#include <stdio.h> - -#define COMMAND_TABLE_SIZE 256 - -const char *atacmdnames_c_cvsid="$Id: atacmdnames.c,v 1.11 2004/01/02 16:05:24 ballen4705 Exp $" 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]"; -const char cmd_recalibrate_ret4[]= "RECALIBRATE [RET-4]"; -const char cmd_seek_ret4[] = "SEEK [RET-4]"; - -const char *command_table[COMMAND_TABLE_SIZE] = { -/*-------------------------------------------------- 00h-0Fh -----*/ - "NOP", - cmd_reserved, - cmd_reserved, - "CFA REQUEST EXTENDED ERROR CODE", - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - "DEVICE RESET", - cmd_reserved, - cmd_reserved, - cmd_reserved, - 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 (w/ retry) [OBS-4]", - "READ LONG (w/o retry) [OBS-4]", - "READ SECTOR(S) EXT", - "READ DMA EXT", - "READ DMA QUEUED EXT", - "READ NATIVE MAX ADDRESS EXT", - cmd_reserved, - "READ MULTIPLE EXT", - "READ STREAM DMA", - "READ STREAM PIO", - cmd_reserved, - cmd_reserved, - cmd_reserved, - "READ LOG EXT", -/*-------------------------------------------------- 30h-3Fh -----*/ - "WRITE SECTOR(S)", - "WRITE SECTOR(S) [OBS-5]", - "WRITE LONG(w/ retry) [OBS-4]", - "WRITE LONG(w/o retry) [OBS-4]", - "WRITE SECTORS(S) EXT", - "WRITE DMA EXT", - "WRITE DMA QUEUED EXT", - "SET MAX ADDRESS EXT", - "CFA WRITE SECTORS WITHOUT ERASE", - "WRITE MULTIPLE EXT", - "WRITE STREAM DMA", - "WRITE STREAM PIO", - "WRITE VERIFY [OBS-4]", - "WRITE DMA FUA EXT", - "WRITE DMA QUEUED FUA EXT", - "WRITE LOG EXT", -/*-------------------------------------------------- 40h-4Fh -----*/ - "READ VERIFY SECTOR(S)", - "READ VERIFY SECTOR(S) [OBS-5]", - "READ VERIFY SECTOR(S) EXT", - 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, -/*-------------------------------------------------- 50h-5Fh -----*/ - "FORMAT TRACK [OBS-4]", - "CONFIGURE STREAM", - 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, - cmd_reserved, -/*-------------------------------------------------- 60h-6Fh -----*/ - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - 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, - cmd_seek_ret4, - cmd_seek_ret4, - 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", - cmd_reserved, - "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", - 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", - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, -/*-------------------------------------------------- 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", - "READ DMA", - "READ DMA [OBS-5]", - "WRITE DMA", - "WRITE DMA [OBS-5]", - "WRITE DMA QUEUED", - "CFA WRITE MULTIPLE WITHOUT ERASE", - "WRITE MULTIPLE FUA EXT", - cmd_reserved, -/*-------------------------------------------------- D0h-DFh -----*/ - cmd_reserved, - "CHECK MEDIA CARD TYPE", - cmd_reserved_mcpt, - cmd_reserved_mcpt, - cmd_reserved_mcpt, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - "GET MEDIA STATUS", - "ACKNOWLEDGE MEDIA CHANGE [RET-4]", - "BOOT POST-BOOT [RET-4]", - "BOOT PRE-BOOT [RET-4]", - "MEDIA LOCK", - "MEDIA UNLOCK", -/*-------------------------------------------------- E0h-EFh -----*/ - "STANDBY IMMEDIATE", - "IDLE IMMEDIATE", - "STANDBY", - "IDLE", - "READ BUFFER", - "CHECK POWER MODE", - "SLEEP", - "FLUSH CACHE", - "WRITE BUFFER", - "WRITE SAME [RET-4]", /* Warning! This command is retired but the value of - f_reg is used in look_up_ata_command(). If this - command code is reclaimed in a future standard then - be sure to update look_up_ata_command(). */ - "FLUSH CACHE EXIT", - cmd_reserved, - "IDENTIFY DEVICE", - "MEDIA EJECT", - "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", - "SET MAX", - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific -}; - -/* 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) { - - // check that command table not messed up. The compiler will issue - // warnings if there are too many array elements, but won't issue - // warnings if there are not enough of them. - if (sizeof(command_table) != sizeof(char *)*COMMAND_TABLE_SIZE){ - fprintf(stderr, - "Problem in atacmdnames.c. Command Table command_table[] does\n" - "not have %d entries! It has %d entries. Please fix it.\n", - COMMAND_TABLE_SIZE, (int)(sizeof(command_table)/sizeof(char *))); - abort(); - } - - 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]"; - default: - return "NOP [Reserved subcommand]"; - } - case 0x92: /* DOWNLOAD MICROCODE */ - switch (f_reg) { - case 0x01: - return "DOWNLOAD MICROCODE [Temporary]"; - case 0x07: - return "DOWNLOAD MICROCODE [Save]"; - 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 "[Vendor specific SMART command]"; - else - return "[Reserved SMART command]"; - } - case 0xB1: /* DEVICE CONFIGURATION */ - switch (f_reg) { - case 0xC0: - return "DEVICE CONFIGURATION RESTORE"; - case 0xC1: - return "DEVICE CONFIGURATION FREEZE LOCK"; - case 0xC2: - return "DEVICE CONFIGURATION IDENTIFY"; - case 0xC3: - return "DEVICE CONFIGURATION SET"; - default: - return "DEVICE CONFIGURATION [Reserved command]"; - } - case 0xE9: /* WRITE SAME */ - switch (f_reg) { - case 0x22: - return "WRITE SAME [Start specified] [RET-4]"; - case 0xDD: - return "WRITE SAME [Start unspecified] [RET-4]"; - default: - return "WRITE SAME [Invalid subcommand] [RET-4]"; - } - case 0xEF: /* SET FEATURES */ - switch (f_reg) { - case 0x01: - return "SET FEATURES [Enable 8-bit PIO]"; - 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)]"; - case 0x0A: - return "SET FEATURES [Enable CFA power mode 1]"; - case 0x10: - return "SET FEATURES [Reserved for Serial ATA]"; - 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]"; - case 0x33: - return "SET FEATURES [Disable retry] [OBS-4]"; - case 0x42: - return "SET FEATURES [Enable AAM]"; - case 0x43: - return "SET FEATURES [Set Max Host I/F S Times]"; - case 0x44: - return "SET FEATURES [Length of VS data] [OBS-4]"; - 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]"; - case 0x5E: - return "SET FEATURES [Enable SERVICE interrupt]"; - case 0x66: - return "SET FEATURES [Disable revert defaults]"; - case 0x77: - return "SET FEATURES [Disable ECC] [OBS-4]"; - case 0x81: - return "SET FEATURES [Disable 8-bit PIO]"; - 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 [Reserved for Serial ATA]"; - case 0x95: - return "SET FEATURES [Enable Media Status Notf]"; - 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 0xC2: - return "SET FEATURES [Disable AAM]"; - case 0xCC: - return "SET FEATURES [Enable revert to defaults]"; - case 0xDD: - return "SET FEATURES [Disable release interrupt]"; - case 0xDE: - return "SET FEATURES [Disable SERVICE interrupt]"; - case 0xE0: - return "SET FEATURES [Obsolete subcommand]"; - 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"; - case 0x02: - return "SET MAX LOCK"; - case 0x03: - return "SET MAX UNLOCK"; - case 0x04: - return "SET MAX FREEZE LOCK"; - default: - return "[Reserved SET MAX command]"; - } - default: - return command_table[c_code]; - } -} diff --git a/sm5/atacmdnames.cpp b/sm5/atacmdnames.cpp deleted file mode 100644 index e2bc92607b3df4785b9aa30b6b9fe2fa4ac94d00..0000000000000000000000000000000000000000 --- a/sm5/atacmdnames.cpp +++ /dev/null @@ -1,520 +0,0 @@ -/* - * atacmdnames.c - * - * 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-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "atacmdnames.h" -#include <stdlib.h> -#include <stdio.h> - -#define COMMAND_TABLE_SIZE 256 - -const char *atacmdnames_c_cvsid="$Id: atacmdnames.cpp,v 1.11 2004/01/02 16:05:24 ballen4705 Exp $" 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]"; -const char cmd_recalibrate_ret4[]= "RECALIBRATE [RET-4]"; -const char cmd_seek_ret4[] = "SEEK [RET-4]"; - -const char *command_table[COMMAND_TABLE_SIZE] = { -/*-------------------------------------------------- 00h-0Fh -----*/ - "NOP", - cmd_reserved, - cmd_reserved, - "CFA REQUEST EXTENDED ERROR CODE", - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - "DEVICE RESET", - cmd_reserved, - cmd_reserved, - cmd_reserved, - 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 (w/ retry) [OBS-4]", - "READ LONG (w/o retry) [OBS-4]", - "READ SECTOR(S) EXT", - "READ DMA EXT", - "READ DMA QUEUED EXT", - "READ NATIVE MAX ADDRESS EXT", - cmd_reserved, - "READ MULTIPLE EXT", - "READ STREAM DMA", - "READ STREAM PIO", - cmd_reserved, - cmd_reserved, - cmd_reserved, - "READ LOG EXT", -/*-------------------------------------------------- 30h-3Fh -----*/ - "WRITE SECTOR(S)", - "WRITE SECTOR(S) [OBS-5]", - "WRITE LONG(w/ retry) [OBS-4]", - "WRITE LONG(w/o retry) [OBS-4]", - "WRITE SECTORS(S) EXT", - "WRITE DMA EXT", - "WRITE DMA QUEUED EXT", - "SET MAX ADDRESS EXT", - "CFA WRITE SECTORS WITHOUT ERASE", - "WRITE MULTIPLE EXT", - "WRITE STREAM DMA", - "WRITE STREAM PIO", - "WRITE VERIFY [OBS-4]", - "WRITE DMA FUA EXT", - "WRITE DMA QUEUED FUA EXT", - "WRITE LOG EXT", -/*-------------------------------------------------- 40h-4Fh -----*/ - "READ VERIFY SECTOR(S)", - "READ VERIFY SECTOR(S) [OBS-5]", - "READ VERIFY SECTOR(S) EXT", - 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, -/*-------------------------------------------------- 50h-5Fh -----*/ - "FORMAT TRACK [OBS-4]", - "CONFIGURE STREAM", - 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, - cmd_reserved, -/*-------------------------------------------------- 60h-6Fh -----*/ - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - cmd_reserved_sa, - 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, - cmd_seek_ret4, - cmd_seek_ret4, - 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", - cmd_reserved, - "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", - 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", - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, - cmd_reserved_cf, -/*-------------------------------------------------- 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", - "READ DMA", - "READ DMA [OBS-5]", - "WRITE DMA", - "WRITE DMA [OBS-5]", - "WRITE DMA QUEUED", - "CFA WRITE MULTIPLE WITHOUT ERASE", - "WRITE MULTIPLE FUA EXT", - cmd_reserved, -/*-------------------------------------------------- D0h-DFh -----*/ - cmd_reserved, - "CHECK MEDIA CARD TYPE", - cmd_reserved_mcpt, - cmd_reserved_mcpt, - cmd_reserved_mcpt, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - cmd_reserved, - "GET MEDIA STATUS", - "ACKNOWLEDGE MEDIA CHANGE [RET-4]", - "BOOT POST-BOOT [RET-4]", - "BOOT PRE-BOOT [RET-4]", - "MEDIA LOCK", - "MEDIA UNLOCK", -/*-------------------------------------------------- E0h-EFh -----*/ - "STANDBY IMMEDIATE", - "IDLE IMMEDIATE", - "STANDBY", - "IDLE", - "READ BUFFER", - "CHECK POWER MODE", - "SLEEP", - "FLUSH CACHE", - "WRITE BUFFER", - "WRITE SAME [RET-4]", /* Warning! This command is retired but the value of - f_reg is used in look_up_ata_command(). If this - command code is reclaimed in a future standard then - be sure to update look_up_ata_command(). */ - "FLUSH CACHE EXIT", - cmd_reserved, - "IDENTIFY DEVICE", - "MEDIA EJECT", - "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", - "SET MAX", - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific, - cmd_vendor_specific -}; - -/* 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) { - - // check that command table not messed up. The compiler will issue - // warnings if there are too many array elements, but won't issue - // warnings if there are not enough of them. - if (sizeof(command_table) != sizeof(char *)*COMMAND_TABLE_SIZE){ - fprintf(stderr, - "Problem in atacmdnames.c. Command Table command_table[] does\n" - "not have %d entries! It has %d entries. Please fix it.\n", - COMMAND_TABLE_SIZE, (int)(sizeof(command_table)/sizeof(char *))); - abort(); - } - - 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]"; - default: - return "NOP [Reserved subcommand]"; - } - case 0x92: /* DOWNLOAD MICROCODE */ - switch (f_reg) { - case 0x01: - return "DOWNLOAD MICROCODE [Temporary]"; - case 0x07: - return "DOWNLOAD MICROCODE [Save]"; - 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 "[Vendor specific SMART command]"; - else - return "[Reserved SMART command]"; - } - case 0xB1: /* DEVICE CONFIGURATION */ - switch (f_reg) { - case 0xC0: - return "DEVICE CONFIGURATION RESTORE"; - case 0xC1: - return "DEVICE CONFIGURATION FREEZE LOCK"; - case 0xC2: - return "DEVICE CONFIGURATION IDENTIFY"; - case 0xC3: - return "DEVICE CONFIGURATION SET"; - default: - return "DEVICE CONFIGURATION [Reserved command]"; - } - case 0xE9: /* WRITE SAME */ - switch (f_reg) { - case 0x22: - return "WRITE SAME [Start specified] [RET-4]"; - case 0xDD: - return "WRITE SAME [Start unspecified] [RET-4]"; - default: - return "WRITE SAME [Invalid subcommand] [RET-4]"; - } - case 0xEF: /* SET FEATURES */ - switch (f_reg) { - case 0x01: - return "SET FEATURES [Enable 8-bit PIO]"; - 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)]"; - case 0x0A: - return "SET FEATURES [Enable CFA power mode 1]"; - case 0x10: - return "SET FEATURES [Reserved for Serial ATA]"; - 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]"; - case 0x33: - return "SET FEATURES [Disable retry] [OBS-4]"; - case 0x42: - return "SET FEATURES [Enable AAM]"; - case 0x43: - return "SET FEATURES [Set Max Host I/F S Times]"; - case 0x44: - return "SET FEATURES [Length of VS data] [OBS-4]"; - 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]"; - case 0x5E: - return "SET FEATURES [Enable SERVICE interrupt]"; - case 0x66: - return "SET FEATURES [Disable revert defaults]"; - case 0x77: - return "SET FEATURES [Disable ECC] [OBS-4]"; - case 0x81: - return "SET FEATURES [Disable 8-bit PIO]"; - 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 [Reserved for Serial ATA]"; - case 0x95: - return "SET FEATURES [Enable Media Status Notf]"; - 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 0xC2: - return "SET FEATURES [Disable AAM]"; - case 0xCC: - return "SET FEATURES [Enable revert to defaults]"; - case 0xDD: - return "SET FEATURES [Disable release interrupt]"; - case 0xDE: - return "SET FEATURES [Disable SERVICE interrupt]"; - case 0xE0: - return "SET FEATURES [Obsolete subcommand]"; - 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"; - case 0x02: - return "SET MAX LOCK"; - case 0x03: - return "SET MAX UNLOCK"; - case 0x04: - return "SET MAX FREEZE LOCK"; - default: - return "[Reserved SET MAX command]"; - } - default: - return command_table[c_code]; - } -} diff --git a/sm5/atacmdnames.h b/sm5/atacmdnames.h deleted file mode 100644 index 8b1ba7ecfb9b1de9bd9232a5094a4c3c460bcb77..0000000000000000000000000000000000000000 --- a/sm5/atacmdnames.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef ATACMDNAMES_H_ -#define ATACMDNAMES_H_ - -#define ATACMDNAMES_H_CVSID "$Id: atacmdnames.h,v 1.3 2004/01/02 16:05:24 ballen4705 Exp $\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 diff --git a/sm5/atacmds.c b/sm5/atacmds.c deleted file mode 100644 index b2b8d4cd4216a339e8c577a092a6aca760a8db6f..0000000000000000000000000000000000000000 --- a/sm5/atacmds.c +++ /dev/null @@ -1,1873 +0,0 @@ -/* - * atacmds.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 <errno.h> -#include <stdlib.h> -#include <ctype.h> - -#include "atacmds.h" -#include "config.h" -#include "int64.h" -#include "extern.h" -#include "utility.h" - -const char *atacmds_c_cvsid="$Id: atacmds.c,v 1.160 2004/08/16 22:44:26 ballen4705 Exp $" -ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID UTILITY_H_CVSID; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// for passing global control variables -extern smartmonctrl *con; - -// These Drive Identity tables are taken from hdparm 5.2, and are also -// given in the ATA/ATAPI specs for the IDENTIFY DEVICE command. Note -// that SMART was first added into the ATA/ATAPI-3 Standard with -// Revision 3 of the document, July 25, 1995. Look at the "Document -// Status" revision commands at the beginning of -// http://www.t13.org/project/d2008r6.pdf to see this. -#define NOVAL_0 0x0000 -#define NOVAL_1 0xffff -/* word 81: minor version number */ -#define MINOR_MAX 0x22 -const char *minor_str[] = { /* word 81 value: */ - "Device does not report version", /* 0x0000 */ - "ATA-1 X3T9.2 781D prior to revision 4", /* 0x0001 */ - "ATA-1 published, ANSI X3.221-1994", /* 0x0002 */ - "ATA-1 X3T9.2 781D revision 4", /* 0x0003 */ - "ATA-2 published, ANSI X3.279-1996", /* 0x0004 */ - "ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */ - "ATA-3 X3T10 2008D revision 1", /* 0x0006 */ /* SMART NOT INCLUDED */ - "ATA-2 X3T10 948D revision 2k", /* 0x0007 */ - "ATA-3 X3T10 2008D revision 0", /* 0x0008 */ - "ATA-2 X3T10 948D revision 3", /* 0x0009 */ - "ATA-3 published, ANSI X3.298-199x", /* 0x000a */ - "ATA-3 X3T10 2008D revision 6", /* 0x000b */ /* 1st VERSION WITH SMART */ - "ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */ - "ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */ - "ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */ - "ATA/ATAPI-4 X3T13 1153D revision 7", /* 0x000f */ - "ATA/ATAPI-4 T13 1153D revision 18", /* 0x0010 */ - "ATA/ATAPI-4 T13 1153D revision 15", /* 0x0011 */ - "ATA/ATAPI-4 published, ANSI NCITS 317-1998", /* 0x0012 */ - "ATA/ATAPI-5 T13 1321D revision 3", /* 0x0013 */ - "ATA/ATAPI-4 T13 1153D revision 14", /* 0x0014 */ - "ATA/ATAPI-5 T13 1321D revision 1", /* 0x0015 */ - "ATA/ATAPI-5 published, ANSI NCITS 340-2000", /* 0x0016 */ - "ATA/ATAPI-4 T13 1153D revision 17", /* 0x0017 */ - "ATA/ATAPI-6 T13 1410D revision 0", /* 0x0018 */ - "ATA/ATAPI-6 T13 1410D revision 3a", /* 0x0019 */ - "ATA/ATAPI-7 T13 1532D revision 1", /* 0x001a */ - "ATA/ATAPI-6 T13 1410D revision 2", /* 0x001b */ - "ATA/ATAPI-6 T13 1410D revision 1", /* 0x001c */ - "reserved", /* 0x001d */ - "ATA/ATAPI-7 T13 1532D revision 0", /* 0x001e */ - "reserved", /* 0x001f */ - "reserved", /* 0x0020 */ - "ATA/ATAPI-7 T13 1532D revision 4a", /* 0x0021 */ - "ATA/ATAPI-6 published, ANSI INCITS 361-2002" /* 0x0022 */ -}; - -// NOTE ATA/ATAPI-4 REV 4 was the LAST revision where the device -// attribute structures were NOT completely vendor specific. So any -// disk that is ATA/ATAPI-4 or above can not be trusted to show the -// vendor values in sensible format. - -// Negative values below are because it doesn't support SMART -const int actual_ver[] = { - /* word 81 value: */ - 0, /* 0x0000 WARNING: */ - 1, /* 0x0001 WARNING: */ - 1, /* 0x0002 WARNING: */ - 1, /* 0x0003 WARNING: */ - 2, /* 0x0004 WARNING: This array */ - 2, /* 0x0005 WARNING: corresponds */ - -3, /*<== */ /* 0x0006 WARNING: *exactly* */ - 2, /* 0x0007 WARNING: to the ATA/ */ - -3, /*<== */ /* 0x0008 WARNING: ATAPI version */ - 2, /* 0x0009 WARNING: listed in */ - 3, /* 0x000a WARNING: the */ - 3, /* 0x000b WARNING: minor_str */ - 3, /* 0x000c WARNING: array */ - 4, /* 0x000d WARNING: above. */ - 4, /* 0x000e WARNING: */ - 4, /* 0x000f WARNING: If you change */ - 4, /* 0x0010 WARNING: that one, */ - 4, /* 0x0011 WARNING: change this one */ - 4, /* 0x0012 WARNING: too!!! */ - 5, /* 0x0013 WARNING: */ - 4, /* 0x0014 WARNING: */ - 5, /* 0x0015 WARNING: */ - 5, /* 0x0016 WARNING: */ - 4, /* 0x0017 WARNING: */ - 6, /* 0x0018 WARNING: */ - 6, /* 0x0019 WARNING: */ - 7, /* 0x001a WARNING: */ - 6, /* 0x001b WARNING: */ - 6, /* 0x001c WARNING: */ - 0, /* 0x001d WARNING: */ - 7, /* 0x001e WARNING: */ - 0, /* 0x001f WARNING: */ - 0, /* 0x0020 WARNING: */ - 7, /* 0x0021 WARNING: */ - 6 /* 0x0022 WARNING: */ -}; - -// When you add additional items to this list, you should then: -// 0 -- update this list -// 1 -- modify the following function parse_attribute_def() -// 2 -- if needed, modify ataPrintSmartAttribRawValue() -// 3 - if needed, modify ataPrintSmartAttribName() -// 4 -- add #define PRESET_N_DESCRIPTION at top of knowndrives.c -// 5 -- add drive in question into knowndrives[] table in knowndrives.c -// 6 -- update smartctl.8 -// 7 -- update smartd.8 -// 8 -- do "make smartd.conf.5" to update smartd.conf.5 -// 9 -- update CHANGELOG file -const char *vendorattributeargs[] = { - // 0 defs[9]=1 - "9,minutes", - // 1 defs[9]=3 - "9,seconds", - // 2 defs[9]=2 - "9,temp", - // 3 defs[220]=1 - "220,temp", - // 4 defs[*]=253 - "N,raw8", - // 5 defs[*]=254 - "N,raw16", - // 6 defs[*]=255 - "N,raw48", - // 7 defs[200]=1 - "200,writeerrorcount", - // 8 defs[9]=4 - "9,halfminutes", - // 9 defs[194]=1 - "194,10xCelsius", - // 10 defs[194]=2 - "194,unknown", - // 11 defs[193]=1 - "193,loadunload", - // 12 defs[201]=1 - "201,detectedtacount", - // 13 defs[192]=1 - "192,emergencyretractcyclect", - // 14 defs[198]=1 - "198,offlinescanuncsectorct", - // NULL should always terminate the array - NULL -}; - -// 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; - } -} - -// This is a utility function for parsing pairs like "9,minutes" or -// "220,temp", and putting the correct flag into the attributedefs -// array. Returns 1 if problem, 0 if pair has been recongized. -int parse_attribute_def(char *pair, unsigned char **defsptr){ - int i,j; - char temp[32]; - unsigned char *defs; - - // If array does not exist, allocate it - if (!*defsptr && !(*defsptr=(unsigned char *)calloc(MAX_ATTRIBUTE_NUM, 1))){ - pout("Out of memory in parse_attribute_def\n"); - EXIT(1); - } - - defs=*defsptr; - - // look along list and see if we find the pair - for (i=0; vendorattributeargs[i] && strcmp(pair, vendorattributeargs[i]); i++); - - switch (i) { - case 0: - // attribute 9 is power on time in minutes - defs[9]=1; - return 0; - case 1: - // attribute 9 is power-on-time in seconds - defs[9]=3; - return 0; - case 2: - // attribute 9 is temperature in celsius - defs[9]=2; - return 0; - case 3: - // attribute 220 is temperature in celsius - defs[220]=1; - return 0; - case 4: - // print all attributes in raw 8-bit form - for (j=0; j<MAX_ATTRIBUTE_NUM; j++) - defs[j]=253; - return 0; - case 5: - // print all attributes in raw 16-bit form - for (j=0; j<MAX_ATTRIBUTE_NUM; j++) - defs[j]=254; - return 0; - case 6: - // print all attributes in raw 48-bit form - for (j=0; j<MAX_ATTRIBUTE_NUM; j++) - defs[j]=255; - return 0; - case 7: - // attribute 200 is write error count - defs[200]=1; - return 0; - case 8: - // attribute 9 increments once every 30 seconds (power on time - // measure) - defs[9]=4; - return 0; - case 9: - // attribute 194 is ten times disk temp in Celsius - defs[194]=1; - return 0; - case 10: - // attribute 194 is unknown - defs[194]=2; - return 0; - case 11: - // Hitachi : Attributes 193 has 2 values : 1 load, 1 normal unload - defs[193]=1; - return 0; - case 12: - // Fujitsu - defs[201]=1; - return 0; - case 13: - // Fujitsu - defs[192]=1; - return 0; - case 14: - // Fujitsu - defs[198]=1; - return 0; - default: - // pair not found - break; - } - // At this point, either the pair was not found, or it is of the - // form N,uninterpreted, in which case we need to parse N - j=sscanf(pair,"%d,%14s", &i, temp); - - // if no match to pattern, unrecognized - if (j!=2 || i<0 || i >255) - return 1; - - // check for recognized strings - if (!strcmp(temp, "raw8")) { - defs[i]=253; - return 0; - } - - // check for recognized strings - if (!strcmp(temp, "raw16")) { - defs[i]=254; - return 0; - } - - // check for recognized strings - if (!strcmp(temp, "raw48")) { - defs[i]=255; - return 0; - } - - // didn't recognize the string - return 1; -} - -// Structure used in sorting the array vendorattributeargs[]. -typedef struct vaa_pair_s { - const char *vaa; - const char *padded_vaa; -} vaa_pair; - -// Returns a copy of s with all numbers of less than three digits padded with -// leading zeros. Returns NULL if there isn't enough memory available. The -// memory for the string is dynamically allocated and should be freed by the -// caller. -char *pad_numbers(const char *s) -{ - char c, *t, *u; - const char *r; - int i, len, ndigits = 0; - - // Allocate the maximum possible amount of memory needed. - if (!(t = (char *)malloc(strlen(s)*2+2))) - return NULL; - - // Copy the string s to t, padding any numbers of less than three digits - // with leading zeros. The string is copied backwards to simplify the code. - r = s + strlen(s); - u = t; - while (( r-- >= s)) { - if (isdigit((int)*r)) - ndigits++; - else if (ndigits > 0) { - while (ndigits++ < 3) - *u++ = '0'; - ndigits = 0; - } - *u++ = *r; - } - *u = '\0'; - - // Reverse the string in t. - len = strlen(t); - for (i = 0; i < len/2; i++) { - c = t[i]; - t[i] = t[len-1-i]; - t[len-1-i] = c; - } - - return t; -} - -// Comparison function for qsort(). Used by sort_vendorattributeargs(). -int compare_vaa_pairs(const void *a, const void *b) -{ - vaa_pair *p = (vaa_pair *)a; - vaa_pair *q = (vaa_pair *)b; - - return strcmp(p->padded_vaa, q->padded_vaa); -} - -// Returns a sorted list of vendorattributeargs or NULL if there is not enough -// memory available. The memory for the list is allocated dynamically and -// should be freed by the caller. -// To perform the sort, any numbers in the strings are padded out to three -// digits by adding leading zeros. For example, -// -// "9,minutes" becomes "009,minutes" -// "N,raw16" becomes "N,raw016" -// -// and the original strings are paired with the padded strings. The list of -// pairs is then sorted by comparing the padded strings (using strcmp) and the -// result is then the list of unpadded strings. -// -const char **sort_vendorattributeargs(void) { - const char **ps, **sorted_list = NULL; - vaa_pair *pairs, *pp; - int count, i; - - // Figure out how many strings are in vendorattributeargs[] (not including - // the terminating NULL). - count = (sizeof vendorattributeargs) / sizeof(char *) - 1; - - // Construct a list of pairs of strings from vendorattributeargs[] and their - // padded equivalents. - if (!(pairs = (vaa_pair *)malloc(sizeof(vaa_pair) * count))) - goto END; - for (ps = vendorattributeargs, pp = pairs; *ps; ps++, pp++) { - pp->vaa = *ps; - if (!(pp->padded_vaa = pad_numbers(*ps))) - goto END; - } - - // Sort the array of vaa_pair structures by comparing the padded strings - // using strcmp(). - qsort(pairs, count, sizeof(vaa_pair), compare_vaa_pairs); - - // Construct the sorted list of strings. - if (!(sorted_list = (const char **)malloc(sizeof vendorattributeargs))) - goto END; - for (ps = sorted_list, pp = pairs, i = 0; i < count; ps++, pp++, i++) - *ps = pp->vaa; - *ps = NULL; - -END: - if (pairs) { - for (i = 0; i < count; i++) - if (pairs[i].padded_vaa) - free((void *)pairs[i].padded_vaa); - free((void *)pairs); - } - - // If there was a problem creating the list then sorted_list should now - // contain NULL. - return sorted_list; -} - -// Function to return a multiline string containing a list of the arguments in -// vendorattributeargs[]. The strings are preceeded by tabs and followed -// (except for the last) by newlines. -// This function allocates the required memory for the string and the caller -// must use free() to free it. It returns NULL if the required memory can't -// be allocated. -char *create_vendor_attribute_arg_list(void){ - const char **ps, **sorted; - char *s; - int len; - - // Get a sorted list of vendor attribute arguments. If the sort fails - // (which should only happen if the system is really low on memory) then just - // use the unordered list. - if (!(sorted = (const char **) sort_vendorattributeargs())) - sorted = vendorattributeargs; - - // Calculate the required number of characters - len = 1; // At least one char ('\0') - for (ps = sorted; *ps != NULL; ps++) { - len += 1; // For the tab - len += strlen(*ps); // For the actual argument string - if (*(ps+1)) - len++; // For the newline if required - } - - // Attempt to allocate memory for the string - if (!(s = (char *)malloc(len))) - return NULL; - - // Construct the string - *s = '\0'; - for (ps = sorted; *ps != NULL; ps++) { - strcat(s, "\t"); - strcat(s, *ps); - if (*(ps+1)) - strcat(s, "\n"); - } - - free((char **)sorted); - - // Return a pointer to the string - return s; -} - -// 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; -} - -static char *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" -}; - -void prettyprint(unsigned char *stuff, char *name){ - int i,j; - pout("\n===== [%s] DATA START (BASE-16) =====\n", name); - for (i=0; i<32; 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 (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(int device, smart_command_set command, int select, char *data){ - int retval; - - // 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 (con->reportataioctl){ - // 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: DeviceFD=%d Command=%s", device, 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 reporting is enabled, say what input was sent to the command - if (con->reportataioctl && sendsdata){ - pout("REPORT-IOCTL: DeviceFD=%d Command=%s", device, commandstrings[command]); - // if requested, pretty-print the output data structure - if (con->reportataioctl>1) - prettyprint((unsigned char *)data, commandstrings[command]); - } - - // In case the command produces an error, we'll want to know what it is: - errno=0; - - // now execute the command - switch (con->controller_type) { - case CONTROLLER_3WARE_678K: - case CONTROLLER_3WARE_678K_CHAR: - case CONTROLLER_3WARE_9000_CHAR: - retval=escalade_command_interface(device, con->controller_port-1, con->controller_type, command, select, data); - break; - default: - retval=ata_command_interface(device, command, select, data); - } - - // If reporting is enabled, say what output was produced by the command - if (con->reportataioctl){ - if (errno) - pout("REPORT-IOCTL: DeviceFD=%d Command=%s returned %d errno=%d [%s]\n", - device, commandstrings[command], retval, errno, strerror(errno)); - else - pout("REPORT-IOCTL: DeviceFD=%d Command=%s returned %d\n", - device, commandstrings[command], retval); - - // if requested, pretty-print the output data structure - if (con->reportataioctl>1 && getsdata) { - if (command==CHECK_POWER_MODE) - pout("Sector Count Register (BASE-16): %02x\n", *data); - else - prettyprint((unsigned char *)data, commandstrings[command]); - } - } - return retval; -} - - -// 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(unsigned char *buffer){ - unsigned char sum=0; - int i; - - for (i=0; i<512; i++) - sum+=buffer[i]; - - return sum; -} - -// 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(int 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; -} - - - - -// 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 ataReadHDIdentity (int device, struct ata_identify_device *buf){ - unsigned short *rawshort=(unsigned short *)buf; - unsigned char *rawbyte =(unsigned char *)buf; - - // See if device responds either to IDENTIFY DEVICE or IDENTIFY - // PACKET DEVICE - if ((smartcommandhandler(device, IDENTIFY, 0, (char *)buf))){ - if (smartcommandhandler(device, PIDENTIFY, 0, (char *)buf)){ - return -1; - } - } - - // if machine is big-endian, swap byte order as needed - if (isbigendian()){ - int i; - - // 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)); - } - - // If there is a checksum there, validate it - if ((rawshort[255] & 0x00ff) == 0x00a5 && checksum(rawbyte)) - checksumwarning("Drive Identity Structure"); - - // If this is a PACKET DEVICE, return device type - if (rawbyte[1] & 0x80) - return 1+(rawbyte[1] & 0x1f); - - // Not a PACKET DEVICE - return 0; -} - -// Returns ATA version as an integer, and a pointer to a string -// describing which revision. Note that Revision 0 of ATA-3 does NOT -// support SMART. For this one case we return -3 rather than +3 as -// the version number. See notes above. -int ataVersionInfo (const char** description, struct ata_identify_device *drive, unsigned short *minor){ - unsigned short major; - int i; - - // check that arrays at the top of this file are defined - // consistently - if (sizeof(minor_str) != sizeof(char *)*(1+MINOR_MAX)){ - pout("Internal error in ataVersionInfo(). minor_str[] size %d\n" - "is not consistent with value of MINOR_MAX+1 = %d\n", - (int)(sizeof(minor_str)/sizeof(char *)), MINOR_MAX+1); - fflush(NULL); - abort(); - } - if (sizeof(actual_ver) != sizeof(int)*(1+MINOR_MAX)){ - pout("Internal error in ataVersionInfo(). actual_ver[] size %d\n" - "is not consistent with value of MINOR_MAX = %d\n", - (int)(sizeof(actual_ver)/sizeof(int)), MINOR_MAX+1); - fflush(NULL); - abort(); - } - - // get major and minor ATA revision numbers - major=drive->major_rev_num; - *minor=drive->minor_rev_num; - - // First check if device has ANY ATA version information in it - if (major==NOVAL_0 || major==NOVAL_1) { - *description=NULL; - return -1; - } - - // The minor revision number has more information - try there first - if (*minor && (*minor<=MINOR_MAX)){ - int std = actual_ver[*minor]; - if (std) { - *description=minor_str[*minor]; - return std; - } - } - - // HDPARM has a very complicated algorithm from here on. Since SMART only - // exists on ATA-3 and later standards, let's punt on this. If you don't - // like it, please fix it. The code's in CVS. - for (i=15; i>0; i--) - if (major & (0x1<<i)) - break; - - *description=NULL; - if (i==0) - return 1; - else - return i;; -} - -// returns 1 if SMART supported, 0 if SMART unsupported, -1 if can't tell -int ataSmartSupport(struct 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(struct 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(int device, struct ata_smart_values *data){ - - if (smartcommandhandler(device, READ_VALUES, 0, (char *)data)){ - syserror("Error SMART Values Read failed"); - return -1; - } - - // compute checksum - if (checksum((unsigned char *)data)) - checksumwarning("SMART Attribute Data Structure"); - - // byte swap if needed - if (isbigendian()){ - int i; - swap2((char *)&(data->revnumber)); - swap2((char *)&(data->total_time_to_complete_off_line)); - swap2((char *)&(data->smart_capability)); - 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 -void fixsamsungselftestlog(struct ata_smart_selftestlog *data){ - int i; - - // 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 (i=0; i<21; i++) - swap2((char *)&(data->selftest_struct[i].selftestnumber)); - - return; -} - -// Reads the Self Test Log (log #6) -int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){ - - // get data from device - if (smartcommandhandler(device, READ_LOG, 0x06, (char *)data)){ - syserror("Error SMART Error Self-Test Log Read failed"); - return -1; - } - - // compute its checksum, and issue a warning if needed - if (checksum((unsigned char *)data)) - checksumwarning("SMART Self-Test Log Structure"); - - // fix firmware bugs in self-test log - if (con->fixfirmwarebug == FIX_SAMSUNG) - fixsamsungselftestlog(data); - - // fix 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; -} - - -// Reads the Log Directory (log #0). Note: NO CHECKSUM!! -int ataReadLogDirectory (int device, struct ata_smart_log_directory *data){ - - // get data from device - if (smartcommandhandler(device, READ_LOG, 0x00, (char *)data)){ - return -1; - } - - // swap endian order if needed - if (isbigendian()){ - swap2((char *)&(data->logversion)); - } - - return 0; -} - - -// Reads the selective self-test log (log #9) -int ataReadSelectiveSelfTestLog(int device, struct ata_selective_self_test_log *data){ - - // get data from device - if (smartcommandhandler(device, READ_LOG, 0x09, (char *)data)){ - syserror("Error SMART Read Selective Self-Test Log failed"); - return -1; - } - - // compute its checksum, and issue a warning if needed - if (checksum((unsigned char *)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)); - } - - if (data->logversion != 1) - pout("SMART Selective Self-Test Log Data Structure Revision Number (%d) should be 1\n", data->logversion); - - return 0; -} - -// Writes the selective self-test log (log #9) -int ataWriteSelectiveSelfTestLog(int device, struct ata_smart_values *sv){ - int i; - struct ata_selective_self_test_log sstlog, *data=&sstlog; - unsigned char cksum=0; - unsigned char *ptr=(unsigned char *)data; - - // Read log - if (ataReadSelectiveSelfTestLog(device, data)) { - pout("Since Read failed, will not attempt to WRITE Selective Self-test Log\n"); - return -1; - } - - // Fix logversion if needed - if (data->logversion !=1) { - pout("Error SMART Selective Self-Test Log Data Structure Revision not recognized\n" - "Revision number should be 1 but is %d. To be safe, aborting WRITE LOG\n", data->logversion); - return -2; - } - - // 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("Error SMART Selective or other Self-Test in progress.\n"); - return -4; - } - - // 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<con->smartselectivenumspans; i++){ - data->span[i].start = con->smartselectivespan[i][0]; - data->span[i].end = con->smartselectivespan[i][1]; - } - - // host must initialize to zero before initiating selective self-test - data->currentlba=0; - data->currentspan=0; - - // Perform off-line scan after selective test? - if (1 == con->scanafterselect) - // NO - data->flags &= ~SELECTIVE_FLAG_DOSCAN; - else if (2 == con->scanafterselect) - // 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 (con->pendingtime) - data->pendingtime=(unsigned short)(con->pendingtime-1); - - // Set checksum to zero, then compute checksum - data->checksum=0; - for (i=0; i<512; i++) - cksum+=ptr[i]; - cksum=~cksum; - cksum+=1; - data->checksum=cksum; - - // 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)); - } - - // write new selective self-test log - if (smartcommandhandler(device, WRITE_LOG, 0x09, (char *)data)){ - syserror("Error Write Selective Self-Test Log failed"); - return -3; - } - - return 0; -} - -// This corrects some quantities that are byte reversed in the SMART -// ATA ERROR LOG. -void fixsamsungerrorlog(struct ata_smart_errorlog *data){ - int i,j; - - // 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 (i=0; i<5; i++){ - // step through 5 command data structures - for (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 -void fixsamsungerrorlog2(struct 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 (int device, struct ata_smart_errorlog *data){ - - // get data from device - if (smartcommandhandler(device, READ_LOG, 0x01, (char *)data)){ - syserror("Error SMART Error Log Read failed"); - return -1; - } - - // compute its checksum, and issue a warning if needed - if (checksum((unsigned char *)data)) - checksumwarning("SMART ATA Error Log Structure"); - - // Some disks have the byte order reversed in some SMART Summary - // Error log entries - if (con->fixfirmwarebug == FIX_SAMSUNG) - fixsamsungerrorlog(data); - else if (con->fixfirmwarebug == FIX_SAMSUNG2) - fixsamsungerrorlog2(data); - - // Correct endian order if necessary - 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; -} - -int ataReadSmartThresholds (int device, struct ata_smart_thresholds_pvt *data){ - - // get data from device - if (smartcommandhandler(device, READ_THRESHOLDS, 0, (char *)data)){ - syserror("Error SMART Thresholds Read failed"); - return -1; - } - - // compute its checksum, and issue a warning if needed - if (checksum((unsigned char *)data)) - checksumwarning("SMART Attribute Thresholds Structure"); - - // byte swap if needed - if (isbigendian()) - swap2((char *)&(data->revnumber)); - - return 0; -} - -int ataEnableSmart (int device ){ - if (smartcommandhandler(device, ENABLE, 0, NULL)){ - syserror("Error SMART Enable failed"); - return -1; - } - return 0; -} - -int ataDisableSmart (int device ){ - - if (smartcommandhandler(device, DISABLE, 0, NULL)){ - syserror("Error SMART Disable failed"); - return -1; - } - return 0; -} - -int ataEnableAutoSave(int device){ - if (smartcommandhandler(device, AUTOSAVE, 241, NULL)){ - syserror("Error SMART Enable Auto-save failed"); - return -1; - } - return 0; -} - -int ataDisableAutoSave(int device){ - - if (smartcommandhandler(device, AUTOSAVE, 0, NULL)){ - syserror("Error SMART Disable Auto-save failed"); - 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 (int device ){ - - /* timer hard coded to 4 hours */ - if (smartcommandhandler(device, AUTO_OFFLINE, 248, NULL)){ - syserror("Error SMART Enable Automatic Offline failed"); - return -1; - } - return 0; -} - -// Another Obsolete Command. See comments directly above, associated -// with the corresponding Enable command. -int ataDisableAutoOffline (int device ){ - - if (smartcommandhandler(device, AUTO_OFFLINE, 0, NULL)){ - syserror("Error SMART Disable Automatic Offline failed"); - return -1; - } - return 0; -} - -// If SMART is enabled, supported, and working, then this call is -// guaranteed to return 1, else zero. Silent inverse of -// ataSmartStatus() -int ataDoesSmartWork(int device){ - return !smartcommandhandler(device, STATUS, 0, NULL); -} - -// This function uses a different interface (DRIVE_TASK) than the -// other commands in this file. -int ataSmartStatus2(int 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. -int ataSmartTest(int device, int testtype, struct ata_smart_values *sv) { - char cmdmsg[128],*type,*captive; - int errornum, 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="[Unrecognized] self-test"; - - // If doing a selective self-test, first use WRITE_LOG to write the - // selective self-test log. - if (select && (retval=ataWriteSelectiveSelfTestLog(device, sv))) { - 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) - sprintf(cmdmsg,"Abort SMART off-line mode self-test routine"); - else - sprintf(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 < con->smartselectivenumspans; i++) - pout(" %d %20"PRId64" %20"PRId64"\n", i, - con->smartselectivespan[i][0], - con->smartselectivespan[i][1]); - } - - // Now send the command to test - errornum=smartcommandhandler(device, IMMEDIATE_OFFLINE, testtype, NULL); - - if (errornum && !(cap && errno==EIO)){ - char errormsg[128]; - sprintf(errormsg,"Command \"%s\" failed",cmdmsg); - syserror(errormsg); - pout("\n"); - return -1; - } - - // Since the command succeeded, tell user - if (testtype==ABORT_SELF_TEST) - pout("Self-testing aborted!\n"); - else - pout("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); - return 0; -} - -/* Test Time Functions */ -int TestTime(struct 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: - return (int) data->extend_test_completion_time; - 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 (struct ata_smart_values *data, struct 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 (struct ata_smart_values *data, struct 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(struct 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(struct 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(struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x02; -} -int isSupportOfflineAbort(struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x04; -} -int isSupportOfflineSurfaceScan(struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x08; -} -int isSupportSelfTest (struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x10; -} -int isSupportConveyanceSelfTest(struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x20; -} -int isSupportSelectiveSelfTest(struct ata_smart_values *data){ - return data->offline_data_collection_capability & 0x40; -} - - - -// Loop over all valid attributes. If they are prefailure attributes -// and are at or below the threshold value, then return the ID of the -// first failing attribute found. Return 0 if all prefailure -// attributes are in bounds. The spec says "Bit 0 -// -Pre-failure/advisory - 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 atribute value less than or equal -// to its corresponding attribute threshold indicates a pre-failure -// condition where imminent loss of data is being predicted." - - -// onlyfailed=0 : are or were any age or prefailure attributes <= threshold -// onlyfailed=1: are any prefailure attributes <= threshold now -int ataCheckSmart(struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds, - int onlyfailed){ - int i; - - // loop over all attributes - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ - - // pointers to disk's values and vendor's thresholds - struct ata_smart_attribute *disk=data->vendor_attributes+i; - struct ata_smart_threshold_entry *thre=thresholds->thres_entries+i; - - // consider only valid attributes - if (disk->id && thre->id){ - int failednow,failedever; - - failednow =disk->current <= thre->threshold; - failedever=disk->worst <= thre->threshold; - - if (!onlyfailed && failedever) - return disk->id; - - if (onlyfailed && failednow && ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)) - return disk->id; - } - } - return 0; -} - - - -// This checks the n'th attribute in the attribute list, NOT the -// attribute with id==n. If the attribute does not exist, or the -// attribute is > threshold, then returns zero. If the attribute is -// <= threshold (failing) then we the attribute number if it is a -// prefail attribute. Else we return minus the attribute number if it -// is a usage attribute. -int ataCheckAttribute(struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds, - int n){ - struct ata_smart_attribute *disk; - struct ata_smart_threshold_entry *thre; - - if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !data || !thresholds) - return 0; - - // pointers to disk's values and vendor's thresholds - disk=data->vendor_attributes+n; - thre=thresholds->thres_entries+n; - - if (!disk || !thre) - return 0; - - // consider only valid attributes, check for failure - if (!disk->id || !thre->id || (disk->id != thre->id) || disk->current> thre->threshold) - return 0; - - // We have found a failed attribute. Return positive or negative? - if (ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)) - return disk->id; - else - return -1*(disk->id); -} - - -// This routine prints the raw value of an attribute as a text string -// into out. It also returns this 48-bit number as a long long. The -// array defs[] contains non-zero values if particular attributes have -// non-default interpretations. - -int64_t ataPrintSmartAttribRawValue(char *out, - struct ata_smart_attribute *attribute, - unsigned char *defs){ - int64_t rawvalue; - unsigned word[3]; - int j; - unsigned char select; - - // convert the six individual bytes to a long long (8 byte) integer. - // This is the value that we'll eventually return. - rawvalue = 0; - for (j=0; j<6; j++) { - // This looks a bit roundabout, but is necessary. Don't - // succumb to the temptation to use raw[j]<<(8*j) since under - // the normal rules this will be promoted to the native type. - // On a 32 bit machine this might then overflow. - int64_t temp; - temp = attribute->raw[j]; - temp <<= 8*j; - rawvalue |= temp; - } - - // convert quantities to three two-byte words - for (j=0; j<3; j++){ - word[j] = attribute->raw[2*j+1]; - word[j] <<= 8; - word[j] |= attribute->raw[2*j]; - } - - // if no data array, Attributes have default interpretations - if (defs) - select=defs[attribute->id]; - else - select=0; - - // Print six one-byte quantities. - if (select==253){ - for (j=0; j<5; j++) - out+=sprintf(out, "%d ", attribute->raw[5-j]); - out+=sprintf(out, "%d ", attribute->raw[0]); - return rawvalue; - } - - // Print three two-byte quantities - if (select==254){ - out+=sprintf(out, "%d %d %d", word[2], word[1], word[0]); - return rawvalue; - } - - // Print one six-byte quantity - if (select==255){ - out+=sprintf(out, "%"PRIu64, rawvalue); - return rawvalue; - } - - // This switch statement is where we handle Raw attributes - // that are stored in an unusual vendor-specific format, - switch (attribute->id){ - // Spin-up time - case 3: - out+=sprintf(out, "%d", word[0]); - // if second nonzero then it stores the average spin-up time - if (word[1]) - out+=sprintf(out, " (Average %d)", word[1]); - break; - // Power on time - case 9: - if (select==1){ - // minutes - int64_t tmp1=rawvalue/60; - int64_t tmp2=rawvalue%60; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); - } - else if (select==3){ - // seconds - int64_t hours=rawvalue/3600; - int64_t minutes=(rawvalue-3600*hours)/60; - int64_t seconds=rawvalue%60; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds); - } - else if (select==4){ - // 30-second counter - int64_t tmp1=rawvalue/120; - int64_t tmp2=(rawvalue-120*tmp1)/2; - out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); - } - else - // hours - out+=sprintf(out, "%"PRIu64, rawvalue); //stored in hours - break; - // Load unload cycles - case 193: - if (select==1){ - // loadunload - long load =attribute->raw[0] + (attribute->raw[1]<<8) + (attribute->raw[2]<<16); - long unload=attribute->raw[3] + (attribute->raw[4]<<8) + (attribute->raw[5]<<16); - out+=sprintf(out, "%lu/%lu", load, unload); - } - else - // associated - out+=sprintf(out, "%"PRIu64, rawvalue); - break; - // Temperature - case 194: - if (select==1){ - // ten times temperature in Celsius - int deg=word[0]/10; - int tenths=word[0]%10; - out+=sprintf(out, "%d.%d", deg, tenths); - } - else if (select==2) - // unknown attribute - out+=sprintf(out, "%"PRIu64, rawvalue); - else { - out+=sprintf(out, "%d", word[0]); - if (!(rawvalue==word[0])) { - int min=word[1]<word[2]?word[1]:word[2]; - int max=word[1]>word[2]?word[1]:word[2]; - // The other bytes are in use. Try IBM's model - out+=sprintf(out, " (Lifetime Min/Max %d/%d)", min, max); - } - } - break; - default: - out+=sprintf(out, "%"PRIu64, rawvalue); - } - - // Return the full value - return rawvalue; -} - - -// Note some attribute names appear redundant because different -// manufacturers use different attribute IDs for an attribute with the -// same name. The variable val should contain a non-zero value if a particular -// attributes has a non-default interpretation. -void ataPrintSmartAttribName(char *out, unsigned char id, unsigned char *definitions){ - char *name; - unsigned char val; - - // If no data array, use default interpretations - if (definitions) - val=definitions[id]; - else - val=0; - - switch (id){ - - case 1: - name="Raw_Read_Error_Rate"; - break; - case 2: - name="Throughput_Performance"; - break; - case 3: - name="Spin_Up_Time"; - break; - case 4: - name="Start_Stop_Count"; - break; - case 5: - name="Reallocated_Sector_Ct"; - break; - case 6: - name="Read_Channel_Margin"; - break; - case 7: - name="Seek_Error_Rate"; - break; - case 8: - name="Seek_Time_Performance"; - break; - case 9: - switch (val) { - case 1: - name="Power_On_Minutes"; - break; - case 2: - name="Temperature_Celsius"; - break; - case 3: - name="Power_On_Seconds"; - break; - case 4: - name="Power_On_Half_Minutes"; - break; - default: - name="Power_On_Hours"; - break; - } - break; - case 10: - name="Spin_Retry_Count"; - break; - case 11: - name="Calibration_Retry_Count"; - break; - case 12: - name="Power_Cycle_Count"; - break; - case 13: - name="Read_Soft_Error_Rate"; - break; - case 191: - name="G-Sense_Error_Rate"; - break; - case 192: - switch (val) { - case 1: - // Fujitsu - name="Emergency_Retract_Cycle_Ct"; - break; - default: - name="Power-Off_Retract_Count"; - break; - } - break; - case 193: - name="Load_Cycle_Count"; - break; - case 194: - switch (val){ - case 1: - // Samsung SV1204H with RK100-13 firmware - name="Temperature_Celsius_x10"; - break; - case 2: - // for disks with no temperature Attribute - name="Unknown_Attribute"; - break; - default: - name="Temperature_Celsius"; - break; - } - break; - case 195: - // Fujitsu name="ECC_On_The_Fly_Count"; - name="Hardware_ECC_Recovered"; - break; - case 196: - name="Reallocated_Event_Count"; - break; - case 197: - name="Current_Pending_Sector"; - break; - case 198: - switch (val){ - case 1: - // Fujitsu - name="Off-line_Scan_UNC_Sector_Ct"; - break; - default: - name="Offline_Uncorrectable"; - break; - } - break; - case 199: - name="UDMA_CRC_Error_Count"; - break; - case 200: - switch (val) { - case 1: - // Fujitsu MHS2020AT - name="Write_Error_Count"; - break; - default: - // Western Digital - name="Multi_Zone_Error_Rate"; - break; - } - break; - case 201: - switch (val) { - case 1: - // Fujitsu - name="Detected_TA_Count"; - break; - default: - name="Soft_Read_Error_Rate"; - break; - } - break; - case 202: - // Fujitsu - name="TA_Increase_Count"; - // Maxtor: Data Address Mark Errors - break; - case 203: - // Fujitsu - name="Run_Out_Cancel"; - // Maxtor: ECC Errors - break; - case 204: - // Fujitsu - name="Shock_Count_Write_Opern"; - // Maxtor: Soft ECC Correction - break; - case 205: - // Fujitsu - name="Shock_Rate_Write_Opern"; - // Maxtor: Thermal Aspirates - break; - case 206: - // Fujitsu - name="Flying_Height"; - break; - case 207: - // Maxtor - name="Spin_High_Current"; - break; - case 208: - // Maxtor - name="Spin_Buzz"; - break; - case 209: - // Maxtor - name="Offline_Seek_Performnce"; - break; - case 220: - switch (val) { - case 1: - name="Temperature_Celsius"; - break; - default: - name="Disk_Shift"; - break; - } - break; - case 221: - name="G-Sense_Error_Rate"; - break; - case 222: - name="Loaded_Hours"; - break; - case 223: - name="Load_Retry_Count"; - break; - case 224: - name="Load_Friction"; - break; - case 225: - name="Load_Cycle_Count"; - break; - case 226: - name="Load-in_Time"; - break; - case 227: - name="Torq-amp_Count"; - break; - case 228: - name="Power-off_Retract_Count"; - break; - case 230: - // seen in IBM DTPA-353750 - name="Head_Amplitude"; - break; - case 231: - name="Temperature_Celsius"; - break; - case 240: - name="Head_Flying_Hours"; - break; - case 250: - name="Read_Error_Retry_Rate"; - break; - default: - name="Unknown_Attribute"; - break; - } - sprintf(out,"%3hu %s",(short int)id,name); - return; -} - -// Returns raw value of Attribute with ID==id. This will be in the -// range 0 to 2^48-1 inclusive. If the Attribute does not exist, -// return -1. -int64_t ATAReturnAttributeRawValue(unsigned char id, struct ata_smart_values *data) { - int i; - - // valid Attribute IDs are in the range 1 to 255 inclusive. - if (!id || !data) - return -1; - - // loop over Attributes to see if there is one with the desired ID - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++) { - struct ata_smart_attribute *this = data->vendor_attributes + i; - if (this->id == id) { - // we've found the desired Attribute. Return its value - int64_t rawvalue=0; - int j; - - for (j=0; j<6; j++) { - // This looks a bit roundabout, but is necessary. Don't - // succumb to the temptation to use raw[j]<<(8*j) since under - // the normal rules this will be promoted to the native type. - // On a 32 bit machine this might then overflow. - int64_t temp; - temp = this->raw[j]; - temp <<= 8*j; - rawvalue |= temp; - } // loop over j - return rawvalue; - } // found desired Attribute - } // loop over Attributes - - // fall-through: no such Attribute found - return -1; -} - - diff --git a/sm5/atacmds.h b/sm5/atacmds.h deleted file mode 100644 index 4b5b710bc12b5427934388aa3a7c8dd0d49f49d1..0000000000000000000000000000000000000000 --- a/sm5/atacmds.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * atacmds.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 ATACMDS_H_ -#define ATACMDS_H_ - -#define ATACMDS_H_CVSID "$Id: atacmds.h,v 1.72 2004/07/26 21:15:21 ballen4705 Exp $\n" - -#include "int64.h" - -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_IDENTIFY_DEVICE 0xec -#define ATA_IDENTIFY_PACKET_DEVICE 0xa1 -#define ATA_SMART_CMD 0xb0 -#define ATA_CHECK_POWER_MODE 0xe5 - -// 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]; -}; -#pragma pack() - -/* 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; -}; -#pragma pack() - -// 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) - - -// Last ten bits are reserved for future use - -/* ata_smart_values is format of the read drive Attribute command */ -/* see Table 34 of T13/1321D Rev 1 spec (Device SMART data structure) for *some* info */ -#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; - unsigned char conveyance_test_completion_time; - unsigned char reserved_375_385[11]; - unsigned char vendor_specific_386_510[125]; // Maxtor bytes 508-509 Attribute/Threshold Revision # - unsigned char chksum; -}; -#pragma pack() - -/* 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]; -}; -#pragma pack() - -/* 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; -}; -#pragma pack() - - -// 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; -}; -#pragma pack() - - -// 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; -}; -#pragma pack() - -// 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; -}; -#pragma pack() - -// 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; -}; -#pragma pack() - -// 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]; -}; -#pragma pack() - -// 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; -}; -#pragma pack() - -// 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; -}; -#pragma pack() - -#pragma pack(1) -struct ata_smart_log_directory { - unsigned short int logversion; - struct ata_smart_log_entry entry[255]; -}; -#pragma pack() - -// 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; -}; -#pragma pack() - -#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; -}; -#pragma pack() - -#define SELECTIVE_FLAG_DOSCAN (0x0002) -#define SELECTIVE_FLAG_PENDING (0x0008) -#define SELECTIVE_FLAG_ACTIVE (0x0010) - -// Get information from drive -int ataReadHDIdentity(int device, struct ata_identify_device *buf); -int ataCheckPowerMode(int device); - -/* Read S.M.A.R.T information from drive */ -int ataReadSmartValues(int device,struct ata_smart_values *); -int ataReadSmartThresholds(int device, struct ata_smart_thresholds_pvt *); -int ataReadErrorLog(int device, struct ata_smart_errorlog *); -int ataReadSelfTestLog(int device, struct ata_smart_selftestlog *); -int ataReadSelectiveSelfTestLog(int device, struct ata_selective_self_test_log *data); -int ataSmartStatus(int device); -int ataSetSmartThresholds(int device, struct ata_smart_thresholds_pvt *); -int ataReadLogDirectory(int device, struct ata_smart_log_directory *); - -/* Enable/Disable SMART on device */ -int ataEnableSmart ( int device ); -int ataDisableSmart (int device ); -int ataEnableAutoSave(int device); -int ataDisableAutoSave(int device); - -/* Automatic Offline Testing */ -int ataEnableAutoOffline ( int device ); -int ataDisableAutoOffline (int device ); - -/* S.M.A.R.T. test commands */ -int ataSmartOfflineTest (int device); -int ataSmartExtendSelfTest (int device); -int ataSmartShortSelfTest (int device); -int ataSmartShortCapSelfTest (int device); -int ataSmartExtendCapSelfTest (int device); -int ataSmartSelfTestAbort (int device); - -// Returns the latest compatibility of ATA/ATAPI Version the device -// supports. Returns -1 if Version command is not supported -int ataVersionInfo (const char **description, struct ata_identify_device *drive, unsigned short *minor); - -// If SMART supported, this is guaranteed to return 1 if SMART is enabled, else 0. -int ataDoesSmartWork(int device); - -// returns 1 if SMART supported, 0 if not supported or can't tell -int ataSmartSupport ( struct ata_identify_device *drive); - -// Return values: -// 1: SMART enabled -// 0: SMART disabled -// -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see -int ataIsSmartEnabled(struct ata_identify_device *drive); - -/* Check SMART for Threshold failure */ -// onlyfailed=0 : are or were any age or prefailure attributes <= threshold -// onlyfailed=1: are any prefailure attributes <= threshold now -int ataCheckSmart ( struct ata_smart_values *data, struct ata_smart_thresholds_pvt *thresholds, int onlyfailed); - -int ataSmartStatus2(int device); - -// int isOfflineTestTime ( struct ata_smart_values data) -// returns S.M.A.R.T. Offline Test Time in seconds -int isOfflineTestTime ( struct ata_smart_values *data); - -int isShortSelfTestTime ( struct ata_smart_values *data); - -int isExtendedSelfTestTime ( struct ata_smart_values *data); - -int isSmartErrorLogCapable(struct ata_smart_values *data, struct ata_identify_device *identity); - -int isSmartTestLogCapable(struct ata_smart_values *data, struct ata_identify_device *identity); - -int isGeneralPurposeLoggingCapable(struct ata_identify_device *identity); - -int isSupportExecuteOfflineImmediate ( struct ata_smart_values *data); - -int isSupportAutomaticTimer ( struct ata_smart_values *data); - -int isSupportOfflineAbort ( struct ata_smart_values *data); - -int isSupportOfflineSurfaceScan ( struct ata_smart_values *data); - -int isSupportSelfTest (struct ata_smart_values *data); - -int isSupportConveyanceSelfTest(struct ata_smart_values *data); - -int isSupportSelectiveSelfTest(struct ata_smart_values *data); - -int ataSmartTest(int device, int testtype, struct ata_smart_values *data); - -int TestTime(struct ata_smart_values *data,int testtype); - -// Prints the raw value (with appropriate formatting) into the -// character string out. -int64_t ataPrintSmartAttribRawValue(char *out, - struct ata_smart_attribute *attribute, - unsigned char *defs); - -// Prints Attribute Name for standard SMART attributes. Writes a -// 30 byte string with attribute name into output -void ataPrintSmartAttribName(char *output, unsigned char id, unsigned char *definitions); - -// This checks the n'th attribute in the attribute list, NOT the -// attribute with id==n. If the attribute does not exist, or the -// attribute is > threshold, then returns zero. If the attribute is -// <= threshold (failing) then we the attribute number if it is a -// prefail attribute. Else we return minus the attribute number if it -// is a usage attribute. -int ataCheckAttribute(struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds, - int n); - -// External handler function, for when a checksum is not correct. Can -// simply return if no action is desired, or can print error messages -// as needed, or exit. Is passed a string with the name of the Data -// Structure with the incorrect checksum. -void checksumwarning(const char *string); - -// Returns raw value of Attribute with ID==id. This will be in the -// range 0 to 2^48-1 inclusive. If the Attribute does not exist, -// return -1. -int64_t ATAReturnAttributeRawValue(unsigned char id, struct ata_smart_values *data); - - -// 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. -const char *SelfTestFailureCodeName(unsigned char which); - - -#define MAX_ATTRIBUTE_NUM 256 - -extern const char *vendorattributeargs[]; - -// function to parse pairs like "9,minutes" or "220,temp". See end of -// extern.h for definition of defs[]. Returns 0 if pair recognized, -// else 1 if there is a problem. Allocates memory for array if the -// array address is *defs==NULL. -int parse_attribute_def(char *pair, unsigned char **defs); - -// Function to return a string containing a list of the arguments in -// vendorattributeargs[]. Returns NULL if the required memory can't -// be allocated. -char *create_vendor_attribute_arg_list(void); - - -// These are two of the functions that are defined in os_*.c and need -// to be ported to get smartmontools onto another OS. -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); - -// This function is exported to give low-level capability -int smartcommandhandler(int device, smart_command_set command, int select, char *data); - -// Utility routines. -void swap2(char *location); -void swap4(char *location); -void swap8(char *location); -#endif /* ATACMDS_H_ */ diff --git a/sm5/ataprint.c b/sm5/ataprint.c deleted file mode 100644 index ba736e26e3f4915e28f712440782e6f95dc427cc..0000000000000000000000000000000000000000 --- a/sm5/ataprint.c +++ /dev/null @@ -1,1833 +0,0 @@ -/* - * ataprint.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 <ctype.h> -#include <stdio.h> -#include <string.h> -#include "atacmdnames.h" -#include "atacmds.h" -#include "ataprint.h" -#include "smartctl.h" -#include "int64.h" -#include "extern.h" -#include "utility.h" -#include "knowndrives.h" -#include "config.h" - -const char *ataprint_c_cvsid="$Id: ataprint.c,v 1.155 2004/07/13 14:48:06 ballen4705 Exp $" -ATACMDNAMES_H_CVSID ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// for passing global control variables -extern smartmonctrl *con; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents -// bytes. -void swapbytes(char *out, const char *in, size_t n) -{ - size_t i; - - for (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. -void trim(char *out, const char *in) -{ - int i, first, last; - - // Find the first non-space character (maybe none). - first = -1; - 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--) - ; - last = i; - - strncpy(out, in+first, last-first+1); - out[last-first+1] = '\0'; -} - -// Convenience function for formatting strings from ata_identify_device -void formatdriveidstring(char *out, const char *in, int n) -{ - char tmp[65]; - - n = n > 64 ? 64 : n; - swapbytes(tmp, in, n); - tmp[n] = '\0'; - trim(out, tmp); -} - -// Function for printing ASCII byte-swapped strings, skipping white -// space. Please note that this is needed on both big- and -// little-endian hardware. -void printswap(char *output, char *in, unsigned int n){ - formatdriveidstring(output, in, n); - if (*output) - pout("%s\n", output); - else - pout("[No Information Found]\n"); -} - -/* 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). The string is dynamically allocated - * memory and the return value is a pointer to this string. It is up to the - * caller to free this memory. If there is insufficient memory or if the - * meanings of the flags of the error register are not known for the given - * command then it returns NULL. - * - * 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. - */ -char *construct_st_er_desc(struct ata_smart_errorlog_struct *data) { - unsigned char CR=data->commands[4].commandreg; - unsigned char FR=data->commands[4].featuresreg; - unsigned char ST=data->error_struct.status; - unsigned char ER=data->error_struct.error_register; - char *s; - 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 COMPLETTION 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; - - 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=(int)data->error_struct.sector_count; - 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=(int)data->error_struct.sector_count; - break; - case 0x25: /* READ DMA EXT */ - case 0x26: // READ DMA QUEUED EXT - case 0xC7: // READ DMA QUEUED - case 0xC8: /* READ DMA */ - case 0xC9: - 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=(int)data->error_struct.sector_count; - 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 NULL; - break; - } - break; - case 0xB1: /* DEVICE CONFIGURATION */ - switch (FR) { - case 0xC0: /* DEVICE CONFIGURATION RESTORE */ - error_flag[2] = abrt; - break; - default: - return NULL; - break; - } - break; - case 0xCA: /* WRITE DMA */ - case 0xCB: - 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 - 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=(int)data->error_struct.sector_count; - break; - case 0xE4: // READ BUFFER - case 0xE8: // WRITE BUFFER - error_flag[2] = abrt; - break; - default: - return NULL; - } - - /* 256 bytes -- that'll be plenty (OK, this is lazy!) */ - if (!(s = (char *)malloc(256))) - return s; - - s[0] = '\0'; - - /* We ignore any status flags other than Device Fault and Error */ - - if (uses_device_fault && (ST & (1 << 5))) { - strcat(s, "Device Fault"); - if (ST & 1) // Error flag - strcat(s, "; "); - } - if (ST & 1) { // Error flag - int count = 0; - - strcat(s, "Error: "); - for (i = 7; i >= 0; i--) - if ((ER & (1 << i)) && (error_flag[i])) { - if (count++ > 0) - strcat(s, ", "); - strcat(s, 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) { - char tmp[128]; - int lba; - - // bits 24-27: bits 0-3 of DH - lba = 0xf & data->error_struct.drive_head; - lba <<= 8; - // bits 16-23: CH - lba |= data->error_struct.cylinder_high; - lba <<= 8; - // bits 8-15: CL - lba |= data->error_struct.cylinder_low; - lba <<= 8; - // bits 0-7: SN - lba |= data->error_struct.sector_number; - - // print number of sectors, if known, and append to print string - if (print_sector) { - snprintf(tmp, 128, " %d sectors", print_sector); - strcat(s, tmp); - } - - // print LBA, and append to print string - snprintf(tmp, 128, " at LBA = 0x%08x = %d", lba, lba); - strcat(s, tmp); - } - - return s; -} - -// This returns the capacity of a disk drive and also prints this into -// a string, using comma separators to make it easier to read. If the -// drive doesn't support LBA addressing or has no user writable -// sectors (eg, CDROM or DVD) then routine returns zero. -uint64_t determine_capacity(struct ata_identify_device *drive, char *pstring){ - - unsigned short command_set_2 = drive->command_set_2; - unsigned short capabilities_0 = drive->words047_079[49-47]; - unsigned short sects_16 = drive->words047_079[60-47]; - unsigned short sects_32 = drive->words047_079[61-47]; - unsigned short lba_16 = drive->words088_255[100-88]; - unsigned short lba_32 = drive->words088_255[101-88]; - unsigned short lba_48 = drive->words088_255[102-88]; - unsigned short lba_64 = drive->words088_255[103-88]; - uint64_t capacity_short=0, capacity=0, threedigits, power_of_ten; - int started=0,k=1000000000; - - // if drive supports LBA addressing, determine 32-bit LBA capacity - if (capabilities_0 & 0x0200) { - capacity_short = (unsigned int)sects_32 << 16 | - (unsigned int)sects_16 << 0 ; - - // if drive supports 48-bit addressing, determine THAT capacity - if ((command_set_2 & 0xc000) == 0x4000 && (command_set_2 & 0x0400)) - capacity = (uint64_t)lba_64 << 48 | - (uint64_t)lba_48 << 32 | - (uint64_t)lba_32 << 16 | - (uint64_t)lba_16 << 0 ; - - // choose the larger of the two possible capacities - if (capacity_short>capacity) - capacity=capacity_short; - } - - // turn sectors into bytes - capacity_short = (capacity *= 512); - - // print with comma separators. I know this is anglo-centric: - // tell me what to change to use LOCALE if you want. - power_of_ten = k; - power_of_ten *= k; - - for (k=0; k<7; k++) { - threedigits = capacity/power_of_ten; - capacity -= threedigits*power_of_ten; - if (started) - // we have already printed some digits - pstring += sprintf(pstring, ",%03"PRIu64, threedigits); - else if (threedigits || k==6) { - // these are the first digits that we are printing - pstring += sprintf(pstring, "%"PRIu64, threedigits); - started = 1; - } - if (k!=6) - power_of_ten /= 1000; - } - - return capacity_short; -} - -void ataPrintDriveInfo (struct ata_identify_device *drive){ - int version, drivetype; - const char *description; - char unknown[64], timedatetz[DATEANDEPOCHLEN]; - unsigned short minorrev; - char model[64], serial[64], firm[64], capacity[64]; - - - // print out model, serial # and firmware versions (byte-swap ASCI strings) - pout("Device Model: "); - printswap(model, (char *)drive->model,40); - - pout("Serial Number: "); - printswap(serial, (char *)drive->serial_no,20); - - pout("Firmware Version: "); - printswap(firm, (char *)drive->fw_rev,8); - - if (determine_capacity(drive, capacity)) - pout("User Capacity: %s bytes\n", capacity); - - // See if drive is recognized - drivetype=lookupdrive(model, firm); - pout("Device is: %s\n", drivetype<0? - "Not in smartctl database [for details use: -P showall]": - "In smartctl database [for details use: -P show]"); - - // now get ATA version info - version=ataVersionInfo(&description,drive, &minorrev); - - // unrecognized minor revision code - if (!description){ - if (!minorrev) - sprintf(unknown, "Exact ATA specification draft version not indicated"); - else - sprintf(unknown,"Not recognized. Minor revision code: 0x%02hx", minorrev); - description=unknown; - } - - - // SMART Support was first added into the ATA/ATAPI-3 Standard with - // Revision 3 of the document, July 25, 1995. Look at the "Document - // Status" revision commands at the beginning of - // http://www.t13.org/project/d2008r6.pdf to see this. So it's not - // enough to check if we are ATA-3. Version=-3 indicates ATA-3 - // BEFORE Revision 3. - pout("ATA Version is: %d\n",(int)abs(version)); - pout("ATA Standard is: %s\n",description); - - // print current time and date and timezone - dateandtimezone(timedatetz); - pout("Local Time is: %s\n", timedatetz); - - // Print warning message, if there is one - if (drivetype>=0 && knowndrives[drivetype].warningmsg) - pout("\n==> WARNING: %s\n\n", knowndrives[drivetype].warningmsg); - - if (version>=3) - return; - - pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); - pout("We will try to proceed in spite of this.\n"); - return; -} - - -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\n"; - else - return "is in a Reserved state\n"; - } -} - - - /* prints verbose value Off-line data collection status byte */ - void PrintSmartOfflineStatus(struct 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; -} - -void PrintSmartSelfExecStatus(struct ata_smart_values *data) -{ - 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 15: - 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; - } - -} - - - -void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values *data){ - pout("Total time to complete Offline \n"); - pout("data collection: \t\t (%4d) seconds.\n", - (int)data->total_time_to_complete_off_line); -} - - - -void PrintSmartOfflineCollectCap(struct 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."); - } -} - - - -void PrintSmartCapability ( struct 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"); - } - } -} - -void PrintSmartErrorLogCapability (struct ata_smart_values *data, struct 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); - } -} - -void PrintSmartShortSelfTestPollingTime(struct 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"); -} - -void PrintSmartExtendedSelfTestPollingTime(struct ata_smart_values *data){ - pout("Extended self-test routine\n"); - if (isSupportSelfTest(data)) - pout("recommended polling time: \t (%4d) minutes.\n", - (int)data->extend_test_completion_time); - else - pout("recommended polling time: \t Not Supported.\n"); -} - -void PrintSmartConveyanceSelfTestPollingTime(struct 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"); -} - -// 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 -void PrintSmartAttribWithThres (struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds, - int onlyfailed){ - int i; - int needheader=1; - char rawstring[64]; - - // step through all vendor attributes - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ - char *status; - struct ata_smart_attribute *disk=data->vendor_attributes+i; - struct ata_smart_threshold_entry *thre=thresholds->thres_entries+i; - - // consider only valid attributes - if (disk->id && thre->id){ - char *type, *update; - int failednow,failedever; - char attributename[64]; - - failednow = (disk->current <= thre->threshold); - failedever= (disk->worst <= thre->threshold); - - // These break out of the loop if we are only printing certain entries... - if (onlyfailed==1 && (!ATTRIBUTE_FLAGS_PREFAILURE(disk->flags) || !failednow)) - continue; - - if (onlyfailed==2 && !failedever) - 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"); - } - pout("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE\n"); - needheader=0; - } - - // is this Attribute currently failed, or has it ever failed? - if (failednow) - status="FAILING_NOW"; - else if (failedever) - status="In_the_past"; - else - status=" -"; - - // Print name of attribute - ataPrintSmartAttribName(attributename,disk->id, con->attributedefs); - pout("%-28s",attributename); - - // printing line for each valid attribute - type=ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)?"Pre-fail":"Old_age"; - update=ATTRIBUTE_FLAGS_ONLINE(disk->flags)?"Always":"Offline"; - - pout("0x%04x %.3d %.3d %.3d %-10s%-9s%-12s", - (int)disk->flags, (int)disk->current, (int)disk->worst, - (int)thre->threshold, type, update, status); - - // print raw value of attribute - ataPrintSmartAttribRawValue(rawstring, disk, con->attributedefs); - pout("%s\n", rawstring); - - // print a warning if there is inconsistency here! - if (disk->id != thre->id){ - char atdat[64],atthr[64]; - ataPrintSmartAttribName(atdat, disk->id, con->attributedefs); - ataPrintSmartAttribName(atthr, thre->id, con->attributedefs); - pout("%-28s<== Data Page | WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat); - pout("%-28s<== Threshold Page | INCONSISTENT IDENTITIES IN THE DATA\n",atthr); - } - } - } - if (!needheader) pout("\n"); -} - -void ataPrintGeneralSmartValues(struct ata_smart_values *data, struct ata_identify_device *drive){ - pout("General SMART Values:\n"); - - PrintSmartOfflineStatus(data); - - if (isSupportSelfTest(data)){ - PrintSmartSelfExecStatus (data); - } - - 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); - - pout("\n"); -} - -int ataPrintLogDirectory(struct ata_smart_log_directory *data){ - int i; - char *name; - - pout("SMART Log Directory Logging Version %d%s\n", - data->logversion, data->logversion==1?" [multi-sector log support]":""); - for (i=0; i<=255; i++){ - int numsect; - - // Directory log length - numsect = i? data->entry[i-1].numsectors : 1; - - // If the log is not empty, what is it's name - if (numsect){ - switch (i) { - case 0: - name="Log Directory"; break; - case 1: - name="Summary SMART error log"; break; - case 2: - name="Comprehensive SMART error log"; break; - case 3: - name="Extended Comprehensive SMART error log"; break; - case 6: - name="SMART self-test log"; break; - case 7: - name="Extended self-test log"; break; - case 9: - name="Selective self-test log"; break; - case 0x20: - name="Streaming performance log"; break; - case 0x21: - name="Write stream error log"; break; - case 0x22: - name="Read stream error log"; break; - case 0x23: - name="Delayed sector log"; break; - default: - if (0xa0<=i && i<=0xbf) - name="Device vendor specific log"; - else if (0x80<=i && i<=0x9f) - name="Host vendor specific log"; - else - name="Reserved log"; - break; - } - - // print name and length of log - pout("Log at address 0x%02x has %03d sectors [%s]\n", - i, numsect, name); - } - } - return 0; -} - -// returns number of errors -int ataPrintSmartErrorlog(struct ata_smart_errorlog *data){ - int k; - - 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(con); - // 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 && con->fixfirmwarebug != FIX_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(con); - 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 (k = 4; k >= 0; k-- ) { - char *st_er_desc; - - // The error log data structure entries are a circular buffer - int j, i=(data->error_log_pointer+k)%5; - struct ata_smart_errorlog_struct *elog=data->errorlog_struct+i; - struct ata_smart_errorlog_error_struct *summary=&(elog->error_struct); - - // Spec says: unused error log structures shall be zero filled - if (nonempty((unsigned char*)elog,sizeof(*elog))){ - // Table 57 of T13/1532D Volume 1 Revision 3 - char *msgstate; - int bits=summary->state & 0x0f; - int days = (int)summary->timestamp/24; - - switch (bits){ - case 0x00: msgstate="in an unknown state";break; - case 0x01: msgstate="sleeping"; break; - case 0x02: msgstate="in standby mode"; break; - case 0x03: msgstate="active or idle"; break; - case 0x04: msgstate="doing SMART Offline or Self-test"; break; - default: - if (bits<0x0b) - msgstate="in a reserved state"; - else - msgstate="in a vendor specific state"; - } - - // See table 42 of ATA5 spec - PRINT_ON(con); - 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(con); - 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 - st_er_desc = construct_st_er_desc(elog); - if (st_er_desc) { - pout(" %s", st_er_desc); - free(st_er_desc); - } - 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--){ - struct ata_smart_errorlog_command_struct *thiscommand=elog->commands+j; - - // Spec says: unused data command structures shall be zero filled - if (nonempty((unsigned char*)thiscommand,sizeof(*thiscommand))) { - char timestring[32]; - - // Convert integer milliseconds to a text-format string - MsecToText(thiscommand->timestamp, timestring); - - 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, - timestring, - look_up_ata_command(thiscommand->commandreg, thiscommand->featuresreg)); - } - } - pout("\n"); - } - } - PRINT_ON(con); - if (con->printing_switchable) - pout("\n"); - PRINT_OFF(con); - return data->ata_error_count; -} - -void ataPrintSelectiveSelfTestLog(struct ata_selective_self_test_log *log, struct ata_smart_values *sv) { - int i,field1,field2; - 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("Warning: ATA Specification requires selective self-test log data structure revision number = 1\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 & 0x7), 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; -} - -// 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(struct ata_smart_selftestlog *data,int allentries){ - int i,j,noheaderprinted=1; - int retval=0, hours=0, testno=0; - - if (allentries) - pout("SMART Self-test log structure revision number %d\n",(int)data->revnumber); - if ((data->revnumber!=0x0001) && allentries && con->fixfirmwarebug != FIX_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; - } - - // print log - for (i=20;i>=0;i--){ - struct ata_smart_selftestlog_struct *log; - - // log is a circular buffer - j=(i+data->mostrecenttest)%21; - log=data->selftest_struct+j; - - if (nonempty((unsigned char*)log,sizeof(*log))){ - char *msgtest,*msgstat,percent[64],firstlba[64]; - int errorfound=0; - - // count entry based on non-empty structures -- needed for - // Seagate only -- other vendors don't have blank entries 'in - // the middle' - testno++; - - // test name - switch(log->selftestnumber){ - case 0: msgtest="Offline "; break; - case 1: msgtest="Short offline "; break; - case 2: msgtest="Extended offline "; break; - case 3: msgtest="Conveyance offline "; break; - case 4: msgtest="Selective offline "; break; - case 127: msgtest="Abort offline test "; break; - case 129: msgtest="Short captive "; break; - case 130: msgtest="Extended captive "; break; - case 131: msgtest="Conveyance captive "; break; - case 132: msgtest="Selective captive "; break; - default: - if ( log->selftestnumber>=192 || - (log->selftestnumber>= 64 && log->selftestnumber<=126)) - msgtest="Vendor offline "; - else - msgtest="Reserved offline "; - } - - // test status - switch((log->selfteststatus)>>4){ - case 0:msgstat="Completed without error "; break; - case 1:msgstat="Aborted by host "; break; - case 2:msgstat="Interrupted (host reset) "; break; - case 3:msgstat="Fatal or unknown error "; errorfound=1; break; - case 4:msgstat="Completed: unknown failure "; errorfound=1; break; - case 5:msgstat="Completed: electrical failure"; errorfound=1; break; - case 6:msgstat="Completed: servo/seek failure"; errorfound=1; break; - case 7:msgstat="Completed: read failure "; errorfound=1; break; - case 8:msgstat="Completed: handling damage?? "; errorfound=1; break; - case 15:msgstat="Self-test routine in progress"; break; - default:msgstat="Unknown/reserved test status "; - } - - retval+=errorfound; - sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf); - - // 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 - - if (!errorfound || log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000) - sprintf(firstlba,"%s","-"); - else - sprintf(firstlba,"%u",log->lbafirstfailure); - - // print out a header if needed - if (noheaderprinted && (allentries || errorfound)){ - pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); - noheaderprinted=0; - } - - // print out an entry, either if we are printing all entries OR - // if an error was found - if (allentries || errorfound) - pout("#%2d %s %s %s %8d %s\n", testno, msgtest, msgstat, percent, (int)log->timestamp, firstlba); - - // keep track of time of most recent error - if (errorfound && !hours) - hours=log->timestamp; - } - } - if (!allentries && retval) - pout("\n"); - - hours = hours << 8; - return (retval | hours); -} - -void ataPseudoCheckSmart ( struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds) { - int i; - int failed = 0; - for (i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) { - if (data->vendor_attributes[i].id && - thresholds->thres_entries[i].id && - ATTRIBUTE_FLAGS_PREFAILURE(data->vendor_attributes[i].flags) && - (data->vendor_attributes[i].current <= thresholds->thres_entries[i].threshold) && - (thresholds->thres_entries[i].threshold != 0xFE)){ - pout("Attribute ID %d Failed\n",(int)data->vendor_attributes[i].id); - failed = 1; - } - } - pout("%s\n", ( failed )? - "SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA": - "SMART overall-health self-assessment test result: PASSED"); -} - - -// Compares failure type to policy in effect, and either exits or -// simply returns to the calling routine. -void failuretest(int type, int returnvalue){ - - // If this is an error in an "optional" SMART command - if (type==OPTIONAL_CMD){ - if (con->conservative){ - pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n"); - EXIT(returnvalue); - } - return; - } - - // If this is an error in a "mandatory" SMART command - if (type==MANDATORY_CMD){ - if (con->permissive--) - return; - pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n"); - EXIT(returnvalue); - } - - pout("Smartctl internal error in failuretest(type=%d). Please contact developers at " PACKAGE_HOMEPAGE "\n",type); - EXIT(returnvalue|FAILCMD); -} - -// Used to warn users about invalid checksums. Action to be taken may be -// altered by the user. -void checksumwarning(const char *string){ - // user has asked us to ignore checksum errors - if (con->checksumignore) - return; - - pout("Warning! %s error: invalid SMART checksum.\n",string); - - // user has asked us to fail on checksum errors - if (con->checksumfail) - EXIT(FAILSMART); - - return; -} - -// Initialize to zero just in case some SMART routines don't work -struct ata_identify_device drive; -struct ata_smart_values smartval; -struct ata_smart_thresholds_pvt smartthres; -struct ata_smart_errorlog smarterror; -struct ata_smart_selftestlog smartselftest; - -int ataPrintMain (int fd){ - int timewait,code; - int returnval=0, retid=0, supported=0, needupdate=0; - - // Start by getting Drive ID information. We need this, to know if SMART is supported. - if ((retid=ataReadHDIdentity(fd,&drive))<0){ - pout("Smartctl: Device Read Identity Failed (not an ATA/ATAPI device)\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILID); - } - - // If requested, show which presets would be used for this drive and exit. - if (con->showpresets) { - showpresets(&drive); - EXIT(0); - } - - // Use preset vendor attribute options unless user has requested otherwise. - if (!con->ignorepresets){ - unsigned char *charptr; - if ((charptr=con->attributedefs)) - applypresets(&drive, &charptr, con); - else { - pout("Fatal internal error in ataPrintMain()\n"); - EXIT(returnval|=FAILCMD); - } - } - - // Print most drive identity information if requested - if (con->driveinfo){ - pout("=== START OF INFORMATION SECTION ===\n"); - ataPrintDriveInfo(&drive); - } - - // Was this a 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)); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - - // if drive does not supports SMART it's time to exit - supported=ataSmartSupport(&drive); - if (supported != 1){ - if (supported==0) { - pout("SMART support is: Unavailable - device lacks SMART capability.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - pout(" Checking to be sure by trying SMART ENABLE command.\n"); - } - else { - pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 82-83 don't show if SMART supported.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - pout(" Checking for SMART support by trying SMART ENABLE command.\n"); - } - - if (ataEnableSmart(fd)){ - pout(" SMART ENABLE failed - this establishes that this device lacks SMART functionality.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - supported=0; - } - else { - pout(" SMART ENABLE appeared to work! Continuing.\n"); - supported=1; - } - if (!con->driveinfo) pout("\n"); - } - - // Now print remaining drive info: is SMART enabled? - if (con->driveinfo){ - int ison=ataIsSmartEnabled(&drive),isenabled=ison; - - if (ison==-1) { - pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 85-87 don't show if SMART is enabled.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - // check SMART support by trying a command - pout(" Checking to be sure by trying SMART RETURN STATUS command.\n"); - isenabled=ataDoesSmartWork(fd); - } - else - pout("SMART support is: Available - device has SMART capability.\n"); - - if (isenabled) - pout("SMART support is: Enabled\n"); - else { - if (ison==-1) - pout("SMART support is: Unavailable\n"); - else - pout("SMART support is: Disabled\n"); - } - pout("\n"); - } - - // START OF THE ENABLE/DISABLE SECTION OF THE CODE - if (con->smartenable || con->smartdisable || - con->smartautosaveenable || con->smartautosavedisable || - con->smartautoofflineenable || con->smartautoofflinedisable) - pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); - - // Enable/Disable SMART commands - if (con->smartenable){ - if (ataEnableSmart(fd)) { - pout("Smartctl: SMART Enable Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Enabled.\n"); - } - - // From here on, every command requires that SMART be enabled... - if (!ataDoesSmartWork(fd)) { - pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n"); - return returnval; - } - - // Turn off SMART on device - if (con->smartdisable){ - if (ataDisableSmart(fd)) { - pout( "Smartctl: SMART Disable Failed.\n\n"); - failuretest(MANDATORY_CMD,returnval|=FAILSMART); - } - pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n"); - return returnval; - } - - // Let's ALWAYS issue this command to get the SMART status - code=ataSmartStatus2(fd); - if (code==-1) - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - - // Enable/Disable Auto-save attributes - if (con->smartautosaveenable){ - if (ataEnableAutoSave(fd)){ - pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Attribute Autosave Enabled.\n"); - } - if (con->smartautosavedisable){ - if (ataDisableAutoSave(fd)){ - pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Attribute Autosave Disabled.\n"); - } - - // for everything else read values and thresholds are needed - if (ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (ataReadSmartThresholds(fd, &smartthres)){ - pout("Smartctl: SMART Read Thresholds failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - - // Enable/Disable Off-line testing - if (con->smartautoofflineenable){ - if (!isSupportAutomaticTimer(&smartval)){ - pout("Warning: device does not support SMART Automatic Timers.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - needupdate=1; - if (ataEnableAutoOffline(fd)){ - pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - pout("SMART Automatic Offline Testing Enabled every four hours.\n"); - } - if (con->smartautoofflinedisable){ - if (!isSupportAutomaticTimer(&smartval)){ - pout("Warning: device does not support SMART Automatic Timers.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - needupdate=1; - if (ataDisableAutoOffline(fd)){ - pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - pout("SMART Automatic Offline Testing Disabled.\n"); - } - - if (needupdate && ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - - // all this for a newline! - if (con->smartenable || con->smartdisable || - con->smartautosaveenable || con->smartautosavedisable || - con->smartautoofflineenable || con->smartautoofflinedisable) - pout("\n"); - - // START OF READ-ONLY OPTIONS APART FROM -V and -i - if (con->checksmart || con->generalsmartvalues || con->smartvendorattrib || con->smarterrorlog || con->smartselftestlog) - pout("=== START OF READ SMART DATA SECTION ===\n"); - - // Check SMART status (use previously returned value) - if (con->checksmart){ - switch (code) { - - case 0: - // The case where the disk health is OK - pout("SMART overall-health self-assessment test result: PASSED\n"); - if (ataCheckSmart(&smartval, &smartthres,0)){ - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,2); - } - returnval|=FAILAGE; - } - else - pout("\n"); - break; - - case 1: - // The case where the disk health is NOT OK - PRINT_ON(con); - pout("SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); - PRINT_OFF(con); - if (ataCheckSmart(&smartval, &smartthres,1)){ - returnval|=FAILATTR; - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for failed Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,1); - } - } - else - pout("No failed Attributes found.\n\n"); - returnval|=FAILSTATUS; - PRINT_OFF(con); - break; - - case -1: - default: - // The case where something went wrong with HDIO_DRIVE_TASK ioctl() - if (ataCheckSmart(&smartval, &smartthres,1)){ - PRINT_ON(con); - pout("SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); - PRINT_OFF(con); - returnval|=FAILATTR; - returnval|=FAILSTATUS; - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for failed Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,1); - } - } - else { - pout("SMART overall-health self-assessment test result: PASSED\n"); - if (ataCheckSmart(&smartval, &smartthres,0)){ - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,2); - } - returnval|=FAILAGE; - } - else - pout("\n"); - } - PRINT_OFF(con); - break; - } // end of switch statement - - PRINT_OFF(con); - } // end of checking SMART Status - - // Print general SMART values - if (con->generalsmartvalues) - ataPrintGeneralSmartValues(&smartval, &drive); - - // Print vendor-specific attributes - if (con->smartvendorattrib){ - PRINT_ON(con); - PrintSmartAttribWithThres(&smartval, &smartthres,con->printing_switchable?2:0); - PRINT_OFF(con); - } - - // Print SMART log Directory - if (con->smartlogdirectory){ - struct ata_smart_log_directory smartlogdirectory; - if (!isGeneralPurposeLoggingCapable(&drive)){ - pout("Warning: device does not support General Purpose Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - pout("Log Directory Supported\n"); - if (ataReadLogDirectory(fd, &smartlogdirectory)){ - PRINT_OFF(con); - pout("Read Log Directory failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - ataPrintLogDirectory( &smartlogdirectory); - } - PRINT_OFF(con); - } - - // Print SMART error log - if (con->smarterrorlog){ - if (!isSmartErrorLogCapable(&smartval, &drive)){ - pout("Warning: device does not support Error Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (ataReadErrorLog(fd, &smarterror)){ - pout("Smartctl: SMART Error Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - // quiet mode is turned on inside ataPrintSmartErrorLog() - if (ataPrintSmartErrorlog(&smarterror)) - returnval|=FAILERR; - PRINT_OFF(con); - } - } - - // Print SMART self-test log - if (con->smartselftestlog){ - if (!isSmartTestLogCapable(&smartval, &drive)){ - pout("Warning: device does not support Self Test Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if(ataReadSelfTestLog(fd, &smartselftest)){ - pout("Smartctl: SMART Self Test Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - if (ataPrintSmartSelfTestlog(&smartselftest,!con->printing_switchable)) - returnval|=FAILLOG; - PRINT_OFF(con); - pout("\n"); - } - } - - // Print SMART selective self-test log - if (con->selectivetestlog){ - struct ata_selective_self_test_log log; - - if (!isSupportSelectiveSelfTest(&smartval)) - pout("Device does not support Selective Self Tests/Logging\n"); - else if(ataReadSelectiveSelfTestLog(fd, &log)) { - pout("Smartctl: SMART Selective Self Test Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - ataPrintSelectiveSelfTestLog(&log, &smartval); - PRINT_OFF(con); - pout("\n"); - } - } - - // START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN - if (con->testcase==-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 (con->testcase){ - case OFFLINE_FULL_SCAN: - if (!isSupportExecuteOfflineImmediate(&smartval)){ - pout("Warning: device does not support Execute Offline Immediate function.\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("Warning: device does not support Self-Test functions.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - break; - case CONVEYANCE_SELF_TEST: - case CONVEYANCE_CAPTIVE_SELF_TEST: - if (!isSupportConveyanceSelfTest(&smartval)){ - pout("Warning: device does not support Conveyance Self-Test functions.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - break; - case SELECTIVE_SELF_TEST: - case SELECTIVE_CAPTIVE_SELF_TEST: - if (!isSupportSelectiveSelfTest(&smartval)){ - pout("Warning: device does not support Selective Self-Test functions.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - break; - default: - pout("Internal error in smartctl: con->testcase==%d not recognized\n", (int)con->testcase); - pout("Please contact smartmontools developers at %s.\n", PACKAGE_BUGREPORT); - EXIT(returnval|=FAILCMD); - } - - // Now do the test. Note ataSmartTest prints its own error/success - // messages - if (ataSmartTest(fd, con->testcase, &smartval)) - 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 (con->testcase==OFFLINE_FULL_SCAN){ - if (isSupportOfflineAbort(&smartval)) - pout("Note: giving further SMART commands will abort Offline testing\n"); - else if (ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - } - - // Now say how long the test will take to complete - if ((timewait=TestTime(&smartval,con->testcase))){ - time_t t=time(NULL); - if (con->testcase==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 (con->testcase!=SHORT_CAPTIVE_SELF_TEST && - con->testcase!=EXTEND_CAPTIVE_SELF_TEST && - con->testcase!=CONVEYANCE_CAPTIVE_SELF_TEST && - con->testcase!=SELECTIVE_CAPTIVE_SELF_TEST) - pout("Use smartctl -X to abort test.\n"); - } - } - - return returnval; -} diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp deleted file mode 100644 index 13167d966dabc4fdf98da9c65c2cc1a9988211ae..0000000000000000000000000000000000000000 --- a/sm5/ataprint.cpp +++ /dev/null @@ -1,1833 +0,0 @@ -/* - * ataprint.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 <ctype.h> -#include <stdio.h> -#include <string.h> -#include "atacmdnames.h" -#include "atacmds.h" -#include "ataprint.h" -#include "smartctl.h" -#include "int64.h" -#include "extern.h" -#include "utility.h" -#include "knowndrives.h" -#include "config.h" - -const char *ataprint_c_cvsid="$Id: ataprint.cpp,v 1.155 2004/07/13 14:48:06 ballen4705 Exp $" -ATACMDNAMES_H_CVSID ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// for passing global control variables -extern smartmonctrl *con; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents -// bytes. -void swapbytes(char *out, const char *in, size_t n) -{ - size_t i; - - for (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. -void trim(char *out, const char *in) -{ - int i, first, last; - - // Find the first non-space character (maybe none). - first = -1; - 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--) - ; - last = i; - - strncpy(out, in+first, last-first+1); - out[last-first+1] = '\0'; -} - -// Convenience function for formatting strings from ata_identify_device -void formatdriveidstring(char *out, const char *in, int n) -{ - char tmp[65]; - - n = n > 64 ? 64 : n; - swapbytes(tmp, in, n); - tmp[n] = '\0'; - trim(out, tmp); -} - -// Function for printing ASCII byte-swapped strings, skipping white -// space. Please note that this is needed on both big- and -// little-endian hardware. -void printswap(char *output, char *in, unsigned int n){ - formatdriveidstring(output, in, n); - if (*output) - pout("%s\n", output); - else - pout("[No Information Found]\n"); -} - -/* 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). The string is dynamically allocated - * memory and the return value is a pointer to this string. It is up to the - * caller to free this memory. If there is insufficient memory or if the - * meanings of the flags of the error register are not known for the given - * command then it returns NULL. - * - * 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. - */ -char *construct_st_er_desc(struct ata_smart_errorlog_struct *data) { - unsigned char CR=data->commands[4].commandreg; - unsigned char FR=data->commands[4].featuresreg; - unsigned char ST=data->error_struct.status; - unsigned char ER=data->error_struct.error_register; - char *s; - 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 COMPLETTION 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; - - 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=(int)data->error_struct.sector_count; - 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=(int)data->error_struct.sector_count; - break; - case 0x25: /* READ DMA EXT */ - case 0x26: // READ DMA QUEUED EXT - case 0xC7: // READ DMA QUEUED - case 0xC8: /* READ DMA */ - case 0xC9: - 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=(int)data->error_struct.sector_count; - 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 NULL; - break; - } - break; - case 0xB1: /* DEVICE CONFIGURATION */ - switch (FR) { - case 0xC0: /* DEVICE CONFIGURATION RESTORE */ - error_flag[2] = abrt; - break; - default: - return NULL; - break; - } - break; - case 0xCA: /* WRITE DMA */ - case 0xCB: - 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 - 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=(int)data->error_struct.sector_count; - break; - case 0xE4: // READ BUFFER - case 0xE8: // WRITE BUFFER - error_flag[2] = abrt; - break; - default: - return NULL; - } - - /* 256 bytes -- that'll be plenty (OK, this is lazy!) */ - if (!(s = (char *)malloc(256))) - return s; - - s[0] = '\0'; - - /* We ignore any status flags other than Device Fault and Error */ - - if (uses_device_fault && (ST & (1 << 5))) { - strcat(s, "Device Fault"); - if (ST & 1) // Error flag - strcat(s, "; "); - } - if (ST & 1) { // Error flag - int count = 0; - - strcat(s, "Error: "); - for (i = 7; i >= 0; i--) - if ((ER & (1 << i)) && (error_flag[i])) { - if (count++ > 0) - strcat(s, ", "); - strcat(s, 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) { - char tmp[128]; - int lba; - - // bits 24-27: bits 0-3 of DH - lba = 0xf & data->error_struct.drive_head; - lba <<= 8; - // bits 16-23: CH - lba |= data->error_struct.cylinder_high; - lba <<= 8; - // bits 8-15: CL - lba |= data->error_struct.cylinder_low; - lba <<= 8; - // bits 0-7: SN - lba |= data->error_struct.sector_number; - - // print number of sectors, if known, and append to print string - if (print_sector) { - snprintf(tmp, 128, " %d sectors", print_sector); - strcat(s, tmp); - } - - // print LBA, and append to print string - snprintf(tmp, 128, " at LBA = 0x%08x = %d", lba, lba); - strcat(s, tmp); - } - - return s; -} - -// This returns the capacity of a disk drive and also prints this into -// a string, using comma separators to make it easier to read. If the -// drive doesn't support LBA addressing or has no user writable -// sectors (eg, CDROM or DVD) then routine returns zero. -uint64_t determine_capacity(struct ata_identify_device *drive, char *pstring){ - - unsigned short command_set_2 = drive->command_set_2; - unsigned short capabilities_0 = drive->words047_079[49-47]; - unsigned short sects_16 = drive->words047_079[60-47]; - unsigned short sects_32 = drive->words047_079[61-47]; - unsigned short lba_16 = drive->words088_255[100-88]; - unsigned short lba_32 = drive->words088_255[101-88]; - unsigned short lba_48 = drive->words088_255[102-88]; - unsigned short lba_64 = drive->words088_255[103-88]; - uint64_t capacity_short=0, capacity=0, threedigits, power_of_ten; - int started=0,k=1000000000; - - // if drive supports LBA addressing, determine 32-bit LBA capacity - if (capabilities_0 & 0x0200) { - capacity_short = (unsigned int)sects_32 << 16 | - (unsigned int)sects_16 << 0 ; - - // if drive supports 48-bit addressing, determine THAT capacity - if ((command_set_2 & 0xc000) == 0x4000 && (command_set_2 & 0x0400)) - capacity = (uint64_t)lba_64 << 48 | - (uint64_t)lba_48 << 32 | - (uint64_t)lba_32 << 16 | - (uint64_t)lba_16 << 0 ; - - // choose the larger of the two possible capacities - if (capacity_short>capacity) - capacity=capacity_short; - } - - // turn sectors into bytes - capacity_short = (capacity *= 512); - - // print with comma separators. I know this is anglo-centric: - // tell me what to change to use LOCALE if you want. - power_of_ten = k; - power_of_ten *= k; - - for (k=0; k<7; k++) { - threedigits = capacity/power_of_ten; - capacity -= threedigits*power_of_ten; - if (started) - // we have already printed some digits - pstring += sprintf(pstring, ",%03"PRIu64, threedigits); - else if (threedigits || k==6) { - // these are the first digits that we are printing - pstring += sprintf(pstring, "%"PRIu64, threedigits); - started = 1; - } - if (k!=6) - power_of_ten /= 1000; - } - - return capacity_short; -} - -void ataPrintDriveInfo (struct ata_identify_device *drive){ - int version, drivetype; - const char *description; - char unknown[64], timedatetz[DATEANDEPOCHLEN]; - unsigned short minorrev; - char model[64], serial[64], firm[64], capacity[64]; - - - // print out model, serial # and firmware versions (byte-swap ASCI strings) - pout("Device Model: "); - printswap(model, (char *)drive->model,40); - - pout("Serial Number: "); - printswap(serial, (char *)drive->serial_no,20); - - pout("Firmware Version: "); - printswap(firm, (char *)drive->fw_rev,8); - - if (determine_capacity(drive, capacity)) - pout("User Capacity: %s bytes\n", capacity); - - // See if drive is recognized - drivetype=lookupdrive(model, firm); - pout("Device is: %s\n", drivetype<0? - "Not in smartctl database [for details use: -P showall]": - "In smartctl database [for details use: -P show]"); - - // now get ATA version info - version=ataVersionInfo(&description,drive, &minorrev); - - // unrecognized minor revision code - if (!description){ - if (!minorrev) - sprintf(unknown, "Exact ATA specification draft version not indicated"); - else - sprintf(unknown,"Not recognized. Minor revision code: 0x%02hx", minorrev); - description=unknown; - } - - - // SMART Support was first added into the ATA/ATAPI-3 Standard with - // Revision 3 of the document, July 25, 1995. Look at the "Document - // Status" revision commands at the beginning of - // http://www.t13.org/project/d2008r6.pdf to see this. So it's not - // enough to check if we are ATA-3. Version=-3 indicates ATA-3 - // BEFORE Revision 3. - pout("ATA Version is: %d\n",(int)abs(version)); - pout("ATA Standard is: %s\n",description); - - // print current time and date and timezone - dateandtimezone(timedatetz); - pout("Local Time is: %s\n", timedatetz); - - // Print warning message, if there is one - if (drivetype>=0 && knowndrives[drivetype].warningmsg) - pout("\n==> WARNING: %s\n\n", knowndrives[drivetype].warningmsg); - - if (version>=3) - return; - - pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); - pout("We will try to proceed in spite of this.\n"); - return; -} - - -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\n"; - else - return "is in a Reserved state\n"; - } -} - - - /* prints verbose value Off-line data collection status byte */ - void PrintSmartOfflineStatus(struct 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; -} - -void PrintSmartSelfExecStatus(struct ata_smart_values *data) -{ - 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 15: - 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; - } - -} - - - -void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values *data){ - pout("Total time to complete Offline \n"); - pout("data collection: \t\t (%4d) seconds.\n", - (int)data->total_time_to_complete_off_line); -} - - - -void PrintSmartOfflineCollectCap(struct 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."); - } -} - - - -void PrintSmartCapability ( struct 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"); - } - } -} - -void PrintSmartErrorLogCapability (struct ata_smart_values *data, struct 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); - } -} - -void PrintSmartShortSelfTestPollingTime(struct 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"); -} - -void PrintSmartExtendedSelfTestPollingTime(struct ata_smart_values *data){ - pout("Extended self-test routine\n"); - if (isSupportSelfTest(data)) - pout("recommended polling time: \t (%4d) minutes.\n", - (int)data->extend_test_completion_time); - else - pout("recommended polling time: \t Not Supported.\n"); -} - -void PrintSmartConveyanceSelfTestPollingTime(struct 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"); -} - -// 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 -void PrintSmartAttribWithThres (struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds, - int onlyfailed){ - int i; - int needheader=1; - char rawstring[64]; - - // step through all vendor attributes - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ - char *status; - struct ata_smart_attribute *disk=data->vendor_attributes+i; - struct ata_smart_threshold_entry *thre=thresholds->thres_entries+i; - - // consider only valid attributes - if (disk->id && thre->id){ - char *type, *update; - int failednow,failedever; - char attributename[64]; - - failednow = (disk->current <= thre->threshold); - failedever= (disk->worst <= thre->threshold); - - // These break out of the loop if we are only printing certain entries... - if (onlyfailed==1 && (!ATTRIBUTE_FLAGS_PREFAILURE(disk->flags) || !failednow)) - continue; - - if (onlyfailed==2 && !failedever) - 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"); - } - pout("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE\n"); - needheader=0; - } - - // is this Attribute currently failed, or has it ever failed? - if (failednow) - status="FAILING_NOW"; - else if (failedever) - status="In_the_past"; - else - status=" -"; - - // Print name of attribute - ataPrintSmartAttribName(attributename,disk->id, con->attributedefs); - pout("%-28s",attributename); - - // printing line for each valid attribute - type=ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)?"Pre-fail":"Old_age"; - update=ATTRIBUTE_FLAGS_ONLINE(disk->flags)?"Always":"Offline"; - - pout("0x%04x %.3d %.3d %.3d %-10s%-9s%-12s", - (int)disk->flags, (int)disk->current, (int)disk->worst, - (int)thre->threshold, type, update, status); - - // print raw value of attribute - ataPrintSmartAttribRawValue(rawstring, disk, con->attributedefs); - pout("%s\n", rawstring); - - // print a warning if there is inconsistency here! - if (disk->id != thre->id){ - char atdat[64],atthr[64]; - ataPrintSmartAttribName(atdat, disk->id, con->attributedefs); - ataPrintSmartAttribName(atthr, thre->id, con->attributedefs); - pout("%-28s<== Data Page | WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat); - pout("%-28s<== Threshold Page | INCONSISTENT IDENTITIES IN THE DATA\n",atthr); - } - } - } - if (!needheader) pout("\n"); -} - -void ataPrintGeneralSmartValues(struct ata_smart_values *data, struct ata_identify_device *drive){ - pout("General SMART Values:\n"); - - PrintSmartOfflineStatus(data); - - if (isSupportSelfTest(data)){ - PrintSmartSelfExecStatus (data); - } - - 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); - - pout("\n"); -} - -int ataPrintLogDirectory(struct ata_smart_log_directory *data){ - int i; - char *name; - - pout("SMART Log Directory Logging Version %d%s\n", - data->logversion, data->logversion==1?" [multi-sector log support]":""); - for (i=0; i<=255; i++){ - int numsect; - - // Directory log length - numsect = i? data->entry[i-1].numsectors : 1; - - // If the log is not empty, what is it's name - if (numsect){ - switch (i) { - case 0: - name="Log Directory"; break; - case 1: - name="Summary SMART error log"; break; - case 2: - name="Comprehensive SMART error log"; break; - case 3: - name="Extended Comprehensive SMART error log"; break; - case 6: - name="SMART self-test log"; break; - case 7: - name="Extended self-test log"; break; - case 9: - name="Selective self-test log"; break; - case 0x20: - name="Streaming performance log"; break; - case 0x21: - name="Write stream error log"; break; - case 0x22: - name="Read stream error log"; break; - case 0x23: - name="Delayed sector log"; break; - default: - if (0xa0<=i && i<=0xbf) - name="Device vendor specific log"; - else if (0x80<=i && i<=0x9f) - name="Host vendor specific log"; - else - name="Reserved log"; - break; - } - - // print name and length of log - pout("Log at address 0x%02x has %03d sectors [%s]\n", - i, numsect, name); - } - } - return 0; -} - -// returns number of errors -int ataPrintSmartErrorlog(struct ata_smart_errorlog *data){ - int k; - - 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(con); - // 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 && con->fixfirmwarebug != FIX_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(con); - 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 (k = 4; k >= 0; k-- ) { - char *st_er_desc; - - // The error log data structure entries are a circular buffer - int j, i=(data->error_log_pointer+k)%5; - struct ata_smart_errorlog_struct *elog=data->errorlog_struct+i; - struct ata_smart_errorlog_error_struct *summary=&(elog->error_struct); - - // Spec says: unused error log structures shall be zero filled - if (nonempty((unsigned char*)elog,sizeof(*elog))){ - // Table 57 of T13/1532D Volume 1 Revision 3 - char *msgstate; - int bits=summary->state & 0x0f; - int days = (int)summary->timestamp/24; - - switch (bits){ - case 0x00: msgstate="in an unknown state";break; - case 0x01: msgstate="sleeping"; break; - case 0x02: msgstate="in standby mode"; break; - case 0x03: msgstate="active or idle"; break; - case 0x04: msgstate="doing SMART Offline or Self-test"; break; - default: - if (bits<0x0b) - msgstate="in a reserved state"; - else - msgstate="in a vendor specific state"; - } - - // See table 42 of ATA5 spec - PRINT_ON(con); - 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(con); - 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 - st_er_desc = construct_st_er_desc(elog); - if (st_er_desc) { - pout(" %s", st_er_desc); - free(st_er_desc); - } - 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--){ - struct ata_smart_errorlog_command_struct *thiscommand=elog->commands+j; - - // Spec says: unused data command structures shall be zero filled - if (nonempty((unsigned char*)thiscommand,sizeof(*thiscommand))) { - char timestring[32]; - - // Convert integer milliseconds to a text-format string - MsecToText(thiscommand->timestamp, timestring); - - 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, - timestring, - look_up_ata_command(thiscommand->commandreg, thiscommand->featuresreg)); - } - } - pout("\n"); - } - } - PRINT_ON(con); - if (con->printing_switchable) - pout("\n"); - PRINT_OFF(con); - return data->ata_error_count; -} - -void ataPrintSelectiveSelfTestLog(struct ata_selective_self_test_log *log, struct ata_smart_values *sv) { - int i,field1,field2; - 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("Warning: ATA Specification requires selective self-test log data structure revision number = 1\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 & 0x7), 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; -} - -// 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(struct ata_smart_selftestlog *data,int allentries){ - int i,j,noheaderprinted=1; - int retval=0, hours=0, testno=0; - - if (allentries) - pout("SMART Self-test log structure revision number %d\n",(int)data->revnumber); - if ((data->revnumber!=0x0001) && allentries && con->fixfirmwarebug != FIX_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; - } - - // print log - for (i=20;i>=0;i--){ - struct ata_smart_selftestlog_struct *log; - - // log is a circular buffer - j=(i+data->mostrecenttest)%21; - log=data->selftest_struct+j; - - if (nonempty((unsigned char*)log,sizeof(*log))){ - char *msgtest,*msgstat,percent[64],firstlba[64]; - int errorfound=0; - - // count entry based on non-empty structures -- needed for - // Seagate only -- other vendors don't have blank entries 'in - // the middle' - testno++; - - // test name - switch(log->selftestnumber){ - case 0: msgtest="Offline "; break; - case 1: msgtest="Short offline "; break; - case 2: msgtest="Extended offline "; break; - case 3: msgtest="Conveyance offline "; break; - case 4: msgtest="Selective offline "; break; - case 127: msgtest="Abort offline test "; break; - case 129: msgtest="Short captive "; break; - case 130: msgtest="Extended captive "; break; - case 131: msgtest="Conveyance captive "; break; - case 132: msgtest="Selective captive "; break; - default: - if ( log->selftestnumber>=192 || - (log->selftestnumber>= 64 && log->selftestnumber<=126)) - msgtest="Vendor offline "; - else - msgtest="Reserved offline "; - } - - // test status - switch((log->selfteststatus)>>4){ - case 0:msgstat="Completed without error "; break; - case 1:msgstat="Aborted by host "; break; - case 2:msgstat="Interrupted (host reset) "; break; - case 3:msgstat="Fatal or unknown error "; errorfound=1; break; - case 4:msgstat="Completed: unknown failure "; errorfound=1; break; - case 5:msgstat="Completed: electrical failure"; errorfound=1; break; - case 6:msgstat="Completed: servo/seek failure"; errorfound=1; break; - case 7:msgstat="Completed: read failure "; errorfound=1; break; - case 8:msgstat="Completed: handling damage?? "; errorfound=1; break; - case 15:msgstat="Self-test routine in progress"; break; - default:msgstat="Unknown/reserved test status "; - } - - retval+=errorfound; - sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf); - - // 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 - - if (!errorfound || log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000) - sprintf(firstlba,"%s","-"); - else - sprintf(firstlba,"%u",log->lbafirstfailure); - - // print out a header if needed - if (noheaderprinted && (allentries || errorfound)){ - pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); - noheaderprinted=0; - } - - // print out an entry, either if we are printing all entries OR - // if an error was found - if (allentries || errorfound) - pout("#%2d %s %s %s %8d %s\n", testno, msgtest, msgstat, percent, (int)log->timestamp, firstlba); - - // keep track of time of most recent error - if (errorfound && !hours) - hours=log->timestamp; - } - } - if (!allentries && retval) - pout("\n"); - - hours = hours << 8; - return (retval | hours); -} - -void ataPseudoCheckSmart ( struct ata_smart_values *data, - struct ata_smart_thresholds_pvt *thresholds) { - int i; - int failed = 0; - for (i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) { - if (data->vendor_attributes[i].id && - thresholds->thres_entries[i].id && - ATTRIBUTE_FLAGS_PREFAILURE(data->vendor_attributes[i].flags) && - (data->vendor_attributes[i].current <= thresholds->thres_entries[i].threshold) && - (thresholds->thres_entries[i].threshold != 0xFE)){ - pout("Attribute ID %d Failed\n",(int)data->vendor_attributes[i].id); - failed = 1; - } - } - pout("%s\n", ( failed )? - "SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA": - "SMART overall-health self-assessment test result: PASSED"); -} - - -// Compares failure type to policy in effect, and either exits or -// simply returns to the calling routine. -void failuretest(int type, int returnvalue){ - - // If this is an error in an "optional" SMART command - if (type==OPTIONAL_CMD){ - if (con->conservative){ - pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n"); - EXIT(returnvalue); - } - return; - } - - // If this is an error in a "mandatory" SMART command - if (type==MANDATORY_CMD){ - if (con->permissive--) - return; - pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n"); - EXIT(returnvalue); - } - - pout("Smartctl internal error in failuretest(type=%d). Please contact developers at " PACKAGE_HOMEPAGE "\n",type); - EXIT(returnvalue|FAILCMD); -} - -// Used to warn users about invalid checksums. Action to be taken may be -// altered by the user. -void checksumwarning(const char *string){ - // user has asked us to ignore checksum errors - if (con->checksumignore) - return; - - pout("Warning! %s error: invalid SMART checksum.\n",string); - - // user has asked us to fail on checksum errors - if (con->checksumfail) - EXIT(FAILSMART); - - return; -} - -// Initialize to zero just in case some SMART routines don't work -struct ata_identify_device drive; -struct ata_smart_values smartval; -struct ata_smart_thresholds_pvt smartthres; -struct ata_smart_errorlog smarterror; -struct ata_smart_selftestlog smartselftest; - -int ataPrintMain (int fd){ - int timewait,code; - int returnval=0, retid=0, supported=0, needupdate=0; - - // Start by getting Drive ID information. We need this, to know if SMART is supported. - if ((retid=ataReadHDIdentity(fd,&drive))<0){ - pout("Smartctl: Device Read Identity Failed (not an ATA/ATAPI device)\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILID); - } - - // If requested, show which presets would be used for this drive and exit. - if (con->showpresets) { - showpresets(&drive); - EXIT(0); - } - - // Use preset vendor attribute options unless user has requested otherwise. - if (!con->ignorepresets){ - unsigned char *charptr; - if ((charptr=con->attributedefs)) - applypresets(&drive, &charptr, con); - else { - pout("Fatal internal error in ataPrintMain()\n"); - EXIT(returnval|=FAILCMD); - } - } - - // Print most drive identity information if requested - if (con->driveinfo){ - pout("=== START OF INFORMATION SECTION ===\n"); - ataPrintDriveInfo(&drive); - } - - // Was this a 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)); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - - // if drive does not supports SMART it's time to exit - supported=ataSmartSupport(&drive); - if (supported != 1){ - if (supported==0) { - pout("SMART support is: Unavailable - device lacks SMART capability.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - pout(" Checking to be sure by trying SMART ENABLE command.\n"); - } - else { - pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 82-83 don't show if SMART supported.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - pout(" Checking for SMART support by trying SMART ENABLE command.\n"); - } - - if (ataEnableSmart(fd)){ - pout(" SMART ENABLE failed - this establishes that this device lacks SMART functionality.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - supported=0; - } - else { - pout(" SMART ENABLE appeared to work! Continuing.\n"); - supported=1; - } - if (!con->driveinfo) pout("\n"); - } - - // Now print remaining drive info: is SMART enabled? - if (con->driveinfo){ - int ison=ataIsSmartEnabled(&drive),isenabled=ison; - - if (ison==-1) { - pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 85-87 don't show if SMART is enabled.\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - // check SMART support by trying a command - pout(" Checking to be sure by trying SMART RETURN STATUS command.\n"); - isenabled=ataDoesSmartWork(fd); - } - else - pout("SMART support is: Available - device has SMART capability.\n"); - - if (isenabled) - pout("SMART support is: Enabled\n"); - else { - if (ison==-1) - pout("SMART support is: Unavailable\n"); - else - pout("SMART support is: Disabled\n"); - } - pout("\n"); - } - - // START OF THE ENABLE/DISABLE SECTION OF THE CODE - if (con->smartenable || con->smartdisable || - con->smartautosaveenable || con->smartautosavedisable || - con->smartautoofflineenable || con->smartautoofflinedisable) - pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); - - // Enable/Disable SMART commands - if (con->smartenable){ - if (ataEnableSmart(fd)) { - pout("Smartctl: SMART Enable Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Enabled.\n"); - } - - // From here on, every command requires that SMART be enabled... - if (!ataDoesSmartWork(fd)) { - pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n"); - return returnval; - } - - // Turn off SMART on device - if (con->smartdisable){ - if (ataDisableSmart(fd)) { - pout( "Smartctl: SMART Disable Failed.\n\n"); - failuretest(MANDATORY_CMD,returnval|=FAILSMART); - } - pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n"); - return returnval; - } - - // Let's ALWAYS issue this command to get the SMART status - code=ataSmartStatus2(fd); - if (code==-1) - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - - // Enable/Disable Auto-save attributes - if (con->smartautosaveenable){ - if (ataEnableAutoSave(fd)){ - pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Attribute Autosave Enabled.\n"); - } - if (con->smartautosavedisable){ - if (ataDisableAutoSave(fd)){ - pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - else - pout("SMART Attribute Autosave Disabled.\n"); - } - - // for everything else read values and thresholds are needed - if (ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (ataReadSmartThresholds(fd, &smartthres)){ - pout("Smartctl: SMART Read Thresholds failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - - // Enable/Disable Off-line testing - if (con->smartautoofflineenable){ - if (!isSupportAutomaticTimer(&smartval)){ - pout("Warning: device does not support SMART Automatic Timers.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - needupdate=1; - if (ataEnableAutoOffline(fd)){ - pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - pout("SMART Automatic Offline Testing Enabled every four hours.\n"); - } - if (con->smartautoofflinedisable){ - if (!isSupportAutomaticTimer(&smartval)){ - pout("Warning: device does not support SMART Automatic Timers.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - needupdate=1; - if (ataDisableAutoOffline(fd)){ - pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - pout("SMART Automatic Offline Testing Disabled.\n"); - } - - if (needupdate && ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - - // all this for a newline! - if (con->smartenable || con->smartdisable || - con->smartautosaveenable || con->smartautosavedisable || - con->smartautoofflineenable || con->smartautoofflinedisable) - pout("\n"); - - // START OF READ-ONLY OPTIONS APART FROM -V and -i - if (con->checksmart || con->generalsmartvalues || con->smartvendorattrib || con->smarterrorlog || con->smartselftestlog) - pout("=== START OF READ SMART DATA SECTION ===\n"); - - // Check SMART status (use previously returned value) - if (con->checksmart){ - switch (code) { - - case 0: - // The case where the disk health is OK - pout("SMART overall-health self-assessment test result: PASSED\n"); - if (ataCheckSmart(&smartval, &smartthres,0)){ - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,2); - } - returnval|=FAILAGE; - } - else - pout("\n"); - break; - - case 1: - // The case where the disk health is NOT OK - PRINT_ON(con); - pout("SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); - PRINT_OFF(con); - if (ataCheckSmart(&smartval, &smartthres,1)){ - returnval|=FAILATTR; - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for failed Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,1); - } - } - else - pout("No failed Attributes found.\n\n"); - returnval|=FAILSTATUS; - PRINT_OFF(con); - break; - - case -1: - default: - // The case where something went wrong with HDIO_DRIVE_TASK ioctl() - if (ataCheckSmart(&smartval, &smartthres,1)){ - PRINT_ON(con); - pout("SMART overall-health self-assessment test result: FAILED!\n" - "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); - PRINT_OFF(con); - returnval|=FAILATTR; - returnval|=FAILSTATUS; - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for failed Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Failed Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,1); - } - } - else { - pout("SMART overall-health self-assessment test result: PASSED\n"); - if (ataCheckSmart(&smartval, &smartthres,0)){ - if (con->smartvendorattrib) - pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); - else { - PRINT_ON(con); - pout("Please note the following marginal Attributes:\n"); - PrintSmartAttribWithThres(&smartval, &smartthres,2); - } - returnval|=FAILAGE; - } - else - pout("\n"); - } - PRINT_OFF(con); - break; - } // end of switch statement - - PRINT_OFF(con); - } // end of checking SMART Status - - // Print general SMART values - if (con->generalsmartvalues) - ataPrintGeneralSmartValues(&smartval, &drive); - - // Print vendor-specific attributes - if (con->smartvendorattrib){ - PRINT_ON(con); - PrintSmartAttribWithThres(&smartval, &smartthres,con->printing_switchable?2:0); - PRINT_OFF(con); - } - - // Print SMART log Directory - if (con->smartlogdirectory){ - struct ata_smart_log_directory smartlogdirectory; - if (!isGeneralPurposeLoggingCapable(&drive)){ - pout("Warning: device does not support General Purpose Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - pout("Log Directory Supported\n"); - if (ataReadLogDirectory(fd, &smartlogdirectory)){ - PRINT_OFF(con); - pout("Read Log Directory failed.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else - ataPrintLogDirectory( &smartlogdirectory); - } - PRINT_OFF(con); - } - - // Print SMART error log - if (con->smarterrorlog){ - if (!isSmartErrorLogCapable(&smartval, &drive)){ - pout("Warning: device does not support Error Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (ataReadErrorLog(fd, &smarterror)){ - pout("Smartctl: SMART Error Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - // quiet mode is turned on inside ataPrintSmartErrorLog() - if (ataPrintSmartErrorlog(&smarterror)) - returnval|=FAILERR; - PRINT_OFF(con); - } - } - - // Print SMART self-test log - if (con->smartselftestlog){ - if (!isSmartTestLogCapable(&smartval, &drive)){ - pout("Warning: device does not support Self Test Logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if(ataReadSelfTestLog(fd, &smartselftest)){ - pout("Smartctl: SMART Self Test Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - if (ataPrintSmartSelfTestlog(&smartselftest,!con->printing_switchable)) - returnval|=FAILLOG; - PRINT_OFF(con); - pout("\n"); - } - } - - // Print SMART selective self-test log - if (con->selectivetestlog){ - struct ata_selective_self_test_log log; - - if (!isSupportSelectiveSelfTest(&smartval)) - pout("Device does not support Selective Self Tests/Logging\n"); - else if(ataReadSelectiveSelfTestLog(fd, &log)) { - pout("Smartctl: SMART Selective Self Test Log Read Failed\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - else { - PRINT_ON(con); - ataPrintSelectiveSelfTestLog(&log, &smartval); - PRINT_OFF(con); - pout("\n"); - } - } - - // START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN - if (con->testcase==-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 (con->testcase){ - case OFFLINE_FULL_SCAN: - if (!isSupportExecuteOfflineImmediate(&smartval)){ - pout("Warning: device does not support Execute Offline Immediate function.\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("Warning: device does not support Self-Test functions.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - break; - case CONVEYANCE_SELF_TEST: - case CONVEYANCE_CAPTIVE_SELF_TEST: - if (!isSupportConveyanceSelfTest(&smartval)){ - pout("Warning: device does not support Conveyance Self-Test functions.\n\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - break; - case SELECTIVE_SELF_TEST: - case SELECTIVE_CAPTIVE_SELF_TEST: - if (!isSupportSelectiveSelfTest(&smartval)){ - pout("Warning: device does not support Selective Self-Test functions.\n\n"); - failuretest(MANDATORY_CMD, returnval|=FAILSMART); - } - break; - default: - pout("Internal error in smartctl: con->testcase==%d not recognized\n", (int)con->testcase); - pout("Please contact smartmontools developers at %s.\n", PACKAGE_BUGREPORT); - EXIT(returnval|=FAILCMD); - } - - // Now do the test. Note ataSmartTest prints its own error/success - // messages - if (ataSmartTest(fd, con->testcase, &smartval)) - 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 (con->testcase==OFFLINE_FULL_SCAN){ - if (isSupportOfflineAbort(&smartval)) - pout("Note: giving further SMART commands will abort Offline testing\n"); - else if (ataReadSmartValues(fd, &smartval)){ - pout("Smartctl: SMART Read Values failed.\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - } - - // Now say how long the test will take to complete - if ((timewait=TestTime(&smartval,con->testcase))){ - time_t t=time(NULL); - if (con->testcase==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 (con->testcase!=SHORT_CAPTIVE_SELF_TEST && - con->testcase!=EXTEND_CAPTIVE_SELF_TEST && - con->testcase!=CONVEYANCE_CAPTIVE_SELF_TEST && - con->testcase!=SELECTIVE_CAPTIVE_SELF_TEST) - pout("Use smartctl -X to abort test.\n"); - } - } - - return returnval; -} diff --git a/sm5/ataprint.h b/sm5/ataprint.h deleted file mode 100644 index 348b4a61c1e8459f61122e3003f3e1005036d634..0000000000000000000000000000000000000000 --- a/sm5/ataprint.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ataprint.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 ATAPRINT_H_ -#define ATAPRINT_H_ - -#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.26 2004/01/27 15:29:16 ballen4705 Exp $\n" - -#include <stdio.h> -#include <stdlib.h> - -/* Prints ATA Drive Information and S.M.A.R.T. Capability */ -void ataPrintDriveInfo(struct ata_identify_device *); - -void ataPrintGeneralSmartValues(struct ata_smart_values *, struct ata_identify_device *); - -void ataPrintSmartThresholds(struct ata_smart_thresholds_pvt *); - -// returns number of errors in Errorlog -int ataPrintSmartErrorlog(struct ata_smart_errorlog *); - -int ataPrintLogDirectory(struct ata_smart_log_directory *); - -void PrintSmartAttributes(struct ata_smart_values *); - -void PrintSmartAttribWithThres(struct ata_smart_values *, - struct ata_smart_thresholds_pvt *, - int onlyfailed); - -// returns number of entries that had logged errors -int ataPrintSmartSelfTestlog(struct ata_smart_selftestlog *, int allentries); - -void ataPseudoCheckSmart(struct ata_smart_values *, struct ata_smart_thresholds_pvt *); - -// Convenience function for formatting strings from ata_identify_device. -void formatdriveidstring(char *out, const char *in, int n); - -int ataPrintMain(int fd); - -#endif diff --git a/sm5/autogen.sh b/sm5/autogen.sh deleted file mode 100755 index c8ba690fc7cbafe52b834c194394dc94e5f36234..0000000000000000000000000000000000000000 --- a/sm5/autogen.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh -# $Id: autogen.sh,v 1.8 2004/05/27 15:23:16 card_captor Exp $ -# -# Generate ./configure from config.in and Makefile.in from Makefile.am. -# This also adds files like missing,depcomp,install-sh to the source -# direcory. 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 && -{ - # Enable strict case checking - # (to avoid e.g "DIST_COMMON = ... ChangeLog ..." in Makefile.in) - export CYGWIN="${CYGWIN}${CYGWIN:+ }check_case:strict" - - # 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.8` || AUTOMAKE=`typep automake-1.7` || AUTOMAKE=`typep automake17` || -{ -echo -echo "You must have at least GNU Automake 1.7 (up to 1.8.x) installed" -echo "in order to bootstrap smartmontools from CVS. 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.8.x) 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.7, or automake-1.8 in" -echo "your PATH, but not the respective aclocal-1.7, or" -echo "aclocal-1.8. Your installation of GNU Automake is broken or" -echo "incomplete." -exit 2; -} - -set -e # stops on error status - -${ACLOCAL} -autoheader -${AUTOMAKE} --add-missing --copy --foreign -autoconf diff --git a/sm5/configure.in b/sm5/configure.in deleted file mode 100644 index 0afadafaf8035930351717502d2253b177fc09cd..0000000000000000000000000000000000000000 --- a/sm5/configure.in +++ /dev/null @@ -1,177 +0,0 @@ -# -# $Id: configure.in,v 1.91 2004/08/13 14:09:21 arvoreen Exp $ -# -dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.50) -AC_INIT(smartmontools, 5.33, smartmontools-support@lists.sourceforge.net) -AC_CONFIG_SRCDIR(smartctl.c) - -smartmontools_configure_date=`date -u +"%Y/%m/%d %T %Z"` -smartmontools_cvs_tag=`echo '$Id: configure.in,v 1.91 2004/08/13 14:09:21 arvoreen Exp $'` -smartmontools_release_date=2004/07/05 -smartmontools_release_time="08:10:26 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 - -AM_MAINTAINER_MODE - -AC_LANG_C -dnl Checks for programs. -AC_PROG_CC -AM_PROG_AS -AC_PROG_INSTALL - -AC_CANONICAL_HOST -dnl Set flags which may affect AC_CHECK_*. -case "${host}" in - *-*-mingw*) - CPPFLAGS="$CPPFLAGS -mno-cygwin" - LDFLAGS="$LDFLAGS -mno-cygwin" - CPPFLAGS="$CPPFLAGS -idirafter ${srcdir}/posix -idirafter ${srcdir}/os_win32" -esac - -dnl Checks for libraries.needed for gethostbyname (Solaris needs -dnl libnsl, might in the future also need libsocket) -# AC_SEARCH_LIBS (FUNCTION, SEARCH-LIBS, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], [OTHER-LIBRARIES]) -AC_SEARCH_LIBS(gethostbyname, nsl, , AC_SEARCH_LIBS(gethostbyname, nsl, , , -lsocket), , ) - -dnl Checks for header files. -AC_CHECK_HEADER([getopt.h]) -AC_CHECK_HEADERS([dev/ata/atavar.h]) -AC_CHECK_HEADERS([sys/int_types.h]) -AC_CHECK_HEADERS([sys/inttypes.h]) -AC_CHECK_HEADERS([netdb.h]) -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 Checks for typedefs, structures, and compiler characteristics. - -dnl Checks for library functions. -AC_CHECK_FUNCS([getopt]) -AC_CHECK_FUNCS([getopt_long]) -AC_CHECK_FUNCS([getdomainname]) -AC_CHECK_FUNCS([gethostname]) -AC_CHECK_FUNCS([gethostbyname]) -AC_CHECK_FUNCS([sigset]) -AC_CHECK_FUNCS([strtoull]) -AC_CHECK_FUNCS([uname]) - -AC_SUBST(CPPFLAGS) -AC_SUBST(LDFLAGS) -AC_SUBST(ASFLAGS) - -AC_SUBST([exampledir], ['${docdir}/examplescripts']) - -AC_ARG_WITH(initscriptdir,[AC_HELP_STRING([--with-initscriptdir=dir],[Location of init scripts (default is ${sysconfdir}/rc.d/init.d)])],[initddir="$withval"],[initddir='${sysconfdir}/rc.d/init.d']) -AC_SUBST(initddir) - -AC_ARG_WITH(docdir,[AC_HELP_STRING([--with-docdir=dir],[Location of documentation (default is ${prefix}/share/doc/smartmontools-5.X)])],[docdir="$withval"],[docdir='${prefix}/share/doc/${PACKAGE}-${VERSION}']) -AC_SUBST(docdir) - -AC_ARG_ENABLE(sample,[AC_HELP_STRING([--enable-sample],[Enables appending .sample to the installed smartd rc script and configuration file])],[smartd_suffix='.sample'],[smartd_suffix='']) -AC_SUBST(smartd_suffix) -AM_CONDITIONAL(SMARTD_SUFFIX, test $smartd_suffix) - -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) - -dnl if OS not recognized, then use the os_generic modules -case "${host}" in - *-*-linux-gnu*) - AC_SUBST([os_deps], ['os_linux.o']) - AC_SUBST([os_libs], ['']) ;; - *-*-linux*) - AC_SUBST([os_deps], ['os_linux.o']) - AC_SUBST([os_libs], ['']) ;; - *-*-freebsd*) - AC_SUBST([os_deps], ['os_freebsd.o']) - AC_SUBST([os_libs], ['-lcam']);; - sparc-*-solaris*) - AC_DEFINE_UNQUOTED(DEFAULT_MAILER, "mailx", [use mailx as default mailer]) - AC_DEFINE_UNQUOTED(NEED_SOLARIS_ATA_CODE, "os_solaris_ata.s", [need assembly code os_solaris_ata.s]) - AC_SUBST([os_deps], ['os_solaris.o os_solaris_ata.o']) - AC_SUBST([os_libs], ['']) ;; - *-pc-solaris*) - AC_DEFINE_UNQUOTED(DEFAULT_MAILER, "mailx", [use mailx as default mailer]) - AC_SUBST([os_deps], ['os_solaris.o']) - AC_SUBST([os_libs], ['']) ;; - *-*-netbsd*) - AC_SUBST([os_deps], ['os_netbsd.o']) - AC_SUBST([os_libs], ['-lutil']) ;; - *-*-cygwin*) - AC_SUBST([os_deps], ['os_win32.o']) - AC_SUBST([os_libs], ['']) ;; - *-*-mingw*) - AC_SUBST([os_deps], ['os_win32.o regex.o daemon_win32.o hostname_win32.o syslog_win32.o']) - AC_SUBST([os_libs], ['']) ;; - *-*-darwin*) - AC_SUBST([os_deps], ['os_darwin.o']) - AC_SUBST([os_libs], ['-framework CoreFoundation -framework IOKit']) ;; - *) - AC_SUBST([os_deps], ['os_generic.o']) - AC_SUBST([os_libs], ['']) ;; -esac - -dnl Define platform-specific symbol. -AM_CONDITIONAL(OS_DARWIN, [echo $host_os | grep '^darwin' > /dev/null]) -AM_CONDITIONAL(OS_SOLARIS, [echo $host_os | grep '^solaris' > /dev/null]) -AM_CONDITIONAL(OS_WIN32_MINGW, [echo $host_os | grep '^mingw' > /dev/null]) - -dnl Add -Wall and -W if using gcc and its not already specified. -if test "x$GCC" = "xyes"; then - if test -z "`echo "$CFLAGS" | grep "\-Wall" 2> /dev/null`" ; then - CFLAGS="$CFLAGS -Wall" - fi -# In the next line, do NOT delete the 2 spaces inside double quotes. - if test -z "`echo "$CFLAGS " | grep "\-W " 2> /dev/null`" ; then - CFLAGS="$CFLAGS -W" - fi - case "${host}" in - *-*-mingw*) - # MinGW uses MSVCRT.DLL which uses printf format "%I64d" and not "%lld" for int64_t - CFLAGS="$CFLAGS -Wno-format";; - esac -else - dnl We are NOT using gcc, so enable host-specific compiler flags - case "${host}" in - *-*-solaris*) - dnl set CFLAGS for Solaris C compiler - if test -z "`echo "$CFLAGS" | grep "\-xmemalign" 2> /dev/null`" ; then - dnl we have to tell the compilers about packed ATA structures - CFLAGS="-xmemalign=1i $CFLAGS" - fi - if test -z "`echo "$CFLAGS" | grep "\-xCC" 2> /dev/null`" ; then - dnl we have to tell the compiler to ignore C++ style comments - CFLAGS="-xCC $CFLAGS" - fi - if test -z "`echo "$CFLAGS" | grep "\-xO" 2> /dev/null`" ; then - dnl turn on optimization if user has not explicitly set its value - CFLAGS="-xO2 $CFLAGS" - fi - esac -fi - -AC_DEFINE_UNQUOTED(SMARTMONTOOLS_BUILD_HOST, "${host}", [smartmontools Build Host]) - -AC_SUBST(CFLAGS) - -AC_OUTPUT(Makefile examplescripts/Makefile smartd.initd) -AC_PROG_MAKE_SET diff --git a/sm5/do_release b/sm5/do_release deleted file mode 100755 index 0031f5c239c64aafe6f0aefda5146da4a1f900a6..0000000000000000000000000000000000000000 --- a/sm5/do_release +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash -ev -# -# do a smartmontools release -# (C) 2003-4 Bruce Allen <ballen4705@users.sourceforge.net>, -# Guido Guenther <agx@sigxcpu.org> -# $Id: do_release,v 1.31 2004/07/05 07:41:52 ballen4705 Exp $ - -# Notes on generating releases: -# (1) update NEWS -# (2) update CHANGELOG -- put in release number -# (3) update release number in configure.in and smartmontools.spec -# (4) update internal changelog in smartmontools.spec - -USECVS=1 - -KEYID=0x9BB19A22 - -if [ -f /etc/redhat-release ]; then - RPM_BASE=/usr/src/redhat/ -else - RPM_BASE=/usr/src/rpm/ -fi -SOURCES=$RPM_BASE/SOURCES/ - -setup_cvs() -{ - CVS_SERVER=fakevalue - unset CVS_SERVER || echo "can't unset CVS_SERVER=$CVS_SERVER" - CVS_RSH=ssh - CVSROOT=:ext:ballen4705@cvs.sourceforge.net:/cvsroot/smartmontools -} - -get_release() -{ - VERSION=`grep 'AC_INIT' configure.in | awk '{ print $2 }' | sed s/,//g` - RELEASE="RELEASE_${VERSION//\./_}" - echo "Version: $VERSION" - echo "Release: $RELEASE" -} - -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" -} - -# run automake/autoconf -if [ -f Makefile ] ; then - make distcheck || exit 1 - make clean - make distclean - rm -f Makefile configure -fi - -if [ $USECVS -ne 0 ] ; then - smartmontools_release_date=`date -u +"%Y/%m/%d"` - smartmontools_release_time=`date -u +"%T %Z"` - cat configure.in | 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.in - rm -f configure.tmp -fi - -./autogen.sh - -get_release - -# tag CVS version -if [ $USECVS -ne 0 ] ; then - setup_cvs - cvs commit -m "Release $VERSION $RELEASE" - cvs tag -d $RELEASE - cvs tag $RELEASE -fi - -# build .tar.gz -rm -rf build -mkdir build -cd build -../configure -make distcheck || exit 1 -cd .. -cp build/smartmontools-$VERSION.tar.gz $SOURCES - -# build rpm -rpmbuild -ba --sign smartmontools.spec - -# remove source tarball -rm -f $SOURCES/smartmontools-$VERSION.tar.gz - -# increase release number: -inc_release -if [ $USECVS -ne 0 ] ; then - perl -p -i.bak -e "s/$PERL_OLD/$PERL_NEW/" configure.in - perl -p -i.bak -e "s/Version:\t$PERL_OLD/Version:\t$PERL_NEW/" smartmontools.spec -fi - -mv -f $RPM_BASE/RPMS/i386/smartmontools-$VERSION-*.i386.rpm . -mv -f $RPM_BASE/SRPMS/smartmontools-$VERSION-*.src.rpm . -cp -f build/smartmontools-$VERSION.tar.gz . -if [ "$KEYID" ]; then - gpg --default-key $KEYID --armor --detach-sign ./smartmontools-$VERSION.tar.gz -fi - -# cleanup -rm -rf autom4te.cache build/ config.h.in Makefile.in examplescripts/Makefile.in \ - depcomp mkinstalldirs install-sh configure aclocal.m4 missing *.bak diff --git a/sm5/examplescripts/.cvsignore b/sm5/examplescripts/.cvsignore deleted file mode 100644 index 282522db0342d8750454b3dc162493b5fc709cc8..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/sm5/examplescripts/Example1 b/sm5/examplescripts/Example1 deleted file mode 100755 index 1b32a77a1d5546fc4c459e84a03e7a0fd4814a93..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/Example1 +++ /dev/null @@ -1,43 +0,0 @@ -#!/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.5 2004/01/07 16:49:56 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_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 diff --git a/sm5/examplescripts/Example2 b/sm5/examplescripts/Example2 deleted file mode 100755 index f6534332b3fce622decbd9f8ecedf04e5f0f7222..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/Example2 +++ /dev/null @@ -1,22 +0,0 @@ -#! /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 - diff --git a/sm5/examplescripts/Example3 b/sm5/examplescripts/Example3 deleted file mode 100755 index 6a1b11cdfef8cf821ad5f732adcbab67623cd516..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/Example3 +++ /dev/null @@ -1,25 +0,0 @@ -#! /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,v 1.4 2003/08/17 09:15:56 ballen4705 Exp $ - -# 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 (uncomment the shutdown command if you really -# want to do this!) - -# /sbin/shutdown -hf now - diff --git a/sm5/examplescripts/Makefile.am b/sm5/examplescripts/Makefile.am deleted file mode 100644 index d37c17dd3864f35c2dd2b95890c6f481cc51d5a9..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -## Process this file with automake to produce Makefile.in -examplesdir=$(exampledir) - -examples_DATA = README - -examples_SCRIPTS = Example1 \ - Example2 \ - Example3 - -EXTRA_DIST = $(examples_SCRIPTS) diff --git a/sm5/examplescripts/README b/sm5/examplescripts/README deleted file mode 100644 index b424afb2cf47e49d4529f7859420c80061809cf3..0000000000000000000000000000000000000000 --- a/sm5/examplescripts/README +++ /dev/null @@ -1,50 +0,0 @@ -# Home page: http://smartmontools.sourceforge.net -# -# $Id: README,v 1.2 2004/01/02 16:05:25 ballen4705 Exp $ -# -# Copyright (C) 2003-4 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., 675 -# Mass Ave, Cambridge, MA 02139, 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 one-line 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. - - diff --git a/sm5/extern.h b/sm5/extern.h deleted file mode 100644 index a21e689985c2d400633fbbe3121a843fe87e24e2..0000000000000000000000000000000000000000 --- a/sm5/extern.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * extern.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 EXTERN_H_ -#define EXTERN_H_ - -#define EXTERN_H_CVSID "$Id: extern.h,v 1.39 2004/08/13 13:57:12 arvoreen Exp $\n" - -// Possible values for fixfirmwarebug. If use has NOT specified -F at -// all, then value is 0. -#define FIX_NOTSPECIFIED 0 -#define FIX_NONE 1 -#define FIX_SAMSUNG 2 -#define FIX_SAMSUNG2 3 - -// Block used for global control/communications. If you need more -// global variables, this should be the only place that you need to -// add them. -typedef struct smartmonctrl_s { - // spans for selective self-test - uint64_t smartselectivespan[5][2]; - // number of spans - int smartselectivenumspans; - int testcase; - // one plus time in minutes to wait after powerup before restarting - // interrupted offline scan after selective self-test. - int pendingtime; - // 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. - unsigned char scanafterselect; - unsigned char driveinfo; - unsigned char checksmart; - unsigned char smartvendorattrib; - unsigned char generalsmartvalues; - unsigned char smartlogdirectory; - unsigned char smartselftestlog; - unsigned char selectivetestlog; - unsigned char smarterrorlog; - unsigned char smartdisable; - unsigned char smartenable; - unsigned char smartstatus; - unsigned char smartexeoffimmediate; - unsigned char smartshortselftest; - unsigned char smartextendselftest; - unsigned char smartconveyanceselftest; - unsigned char smartselectiveselftest; - unsigned char smartshortcapselftest; - unsigned char smartextendcapselftest; - unsigned char smartconveyancecapselftest; - unsigned char smartselectivecapselftest; - unsigned char smartselftestabort; - unsigned char smartautoofflineenable; - unsigned char smartautoofflinedisable; - unsigned char smartautosaveenable; - unsigned char smartautosavedisable; - unsigned char printing_switchable; - unsigned char dont_print; - unsigned char permissive; - unsigned char conservative; - unsigned char checksumfail; - unsigned char checksumignore; - unsigned char reportataioctl; - unsigned char reportscsiioctl; - unsigned char fixfirmwarebug; - // 3Ware controller type, but also extensible to other contoller types - unsigned char controller_type; - // For 3Ware controllers, nonzero value is 1 plus the disk number - unsigned char controller_port; - unsigned char ignorepresets; - unsigned char showpresets; - // The i'th entry in this array will modify the printed meaning of - // the i'th SMART attribute. The default definitions of the - // Attributes are obtained by having the array be all zeros. If - // attributedefs[i] is nonzero, it means that the i'th attribute has - // a non-default meaning. See the ataPrintSmartAttribName and - // and parse_attribute_def functions. - unsigned char attributedefs[256]; -} smartmonctrl; - -#endif diff --git a/sm5/int64.h b/sm5/int64.h deleted file mode 100644 index 4e3bd9782049ee73c82d6e9d0763b8324dc9ee55..0000000000000000000000000000000000000000 --- a/sm5/int64.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * int64.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef INT64_H_ -#define INT64_H_ - -#define INT64_H_CVSID "$Id: int64.h,v 1.5 2004/07/29 21:05:25 chrfranke Exp $\n" - -#ifndef CONFIG_H_CVSID -// need HAVE_STDINT_H, HAVE_INTTYPES_H -#include "config.h" -#endif - -// 64 bit integer typedefs - -#ifdef HAVE_SYS_INT_TYPES_H -#include <sys/int_types.h> -#else -#ifdef HAVE_STDINT_H -#include <stdint.h> -#else -#ifdef HAVE_SYS_INTTYPES_H -#include <sys/inttypes.h> -#else -#if defined(_WIN32) && defined(_MSC_VER) -// for MSVC 6.0 -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -// default is GCC style -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif // _WIN32 && _MSC_VER -#endif // HAVE_SYS_INTTYPES_H -#endif // HAVE_STDINT_H -#endif // HAVE_SYS_INT_TYPES_H - -// 64 bit integer format strings - -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#else -#if defined(_WIN32) && defined(_MSC_VER) -// for MSVC 6.0 -#define PRId64 "I64d" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#endif // _WIN32 && _MSC_VER -#endif // HAVE_INTTYPES_H -#ifndef PRId64 // not defined in inttypes.h....fix here -// default is GCC style -#define PRId64 "lld" -#define PRIu64 "llu" -#define PRIx64 "llx" -#endif // ndef PRId64 - - -#if defined(_WIN32) && defined(_MSC_VER) -// for MSVC 6.0: "unsigned __int64 -> double" conversion not implemented -// replacement function implemented in os_win32/int64_vc6.c -double uint64_to_double(unsigned __int64 ull); -#else -#define uint64_to_double(ull) ((double)(ull)) -#endif // _WIN32 && _MSC_VER - - -#endif // INT64_H diff --git a/sm5/knowndrives.c b/sm5/knowndrives.c deleted file mode 100644 index 02813f3db83a02739581204d6150ff4f6f877eed..0000000000000000000000000000000000000000 --- a/sm5/knowndrives.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * knowndrives.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * Address of support mailing list: smartmontools-support@lists.sourceforge.net - * - * Copyright (C) 2003-4 Philip Williams, 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "utility.h" // includes <regex.h> -#include "config.h" - -const char *knowndrives_c_cvsid="$Id: knowndrives.c,v 1.117 2004/07/31 16:38:00 pjwilliams Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID UTILITY_H_CVSID; - -#define MODEL_STRING_LENGTH 40 -#define FIRMWARE_STRING_LENGTH 8 -#define TABLEPRINTWIDTH 19 - -// See vendorattributeargs[] array in atacmds.c for definitions. -#define PRESET_9_MINUTES { 9, 1 } -#define PRESET_9_TEMP { 9, 2 } -#define PRESET_9_SECONDS { 9, 3 } -#define PRESET_9_HALFMINUTES { 9, 4 } -#define PRESET_192_EMERGENCYRETRACTCYCLECT { 192, 1 } -#define PRESET_193_LOADUNLOAD { 193, 1 } -#define PRESET_194_10XCELSIUS { 194, 1 } -#define PRESET_194_UNKNOWN { 194, 2 } -#define PRESET_198_OFFLINESCANUNCSECTORCT { 198, 1 } -#define PRESET_200_WRITEERRORCOUNT { 200, 1 } -#define PRESET_201_DETECTEDTACOUNT { 201, 1 } -#define PRESET_220_TEMP { 220, 1 } - -/* Arrays of preset vendor-specific attribute options for use in - * knowndrives[]. */ - -extern int64_t bytes; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// These three are common to several models. -const unsigned char vendoropts_9_minutes[][2] = { - PRESET_9_MINUTES, - {0,0} -}; -const unsigned char vendoropts_9_halfminutes[][2] = { - PRESET_9_HALFMINUTES, - {0,0} -}; -const unsigned char vendoropts_9_seconds[][2] = { - PRESET_9_SECONDS, - {0,0} -}; - -const unsigned char vendoropts_Maxtor_4D080H4[][2] = { - PRESET_9_MINUTES, - PRESET_194_UNKNOWN, - {0,0} -}; - -const unsigned char vendoropts_Fujitsu_MHS2020AT[][2] = { - PRESET_9_SECONDS, - PRESET_192_EMERGENCYRETRACTCYCLECT, - PRESET_198_OFFLINESCANUNCSECTORCT, - PRESET_200_WRITEERRORCOUNT, - PRESET_201_DETECTEDTACOUNT, - {0,0} -}; - -const unsigned char vendoropts_Fujitsu_MHR2040AT[][2] = { - PRESET_9_SECONDS, - PRESET_192_EMERGENCYRETRACTCYCLECT, - PRESET_198_OFFLINESCANUNCSECTORCT, - PRESET_200_WRITEERRORCOUNT, - {0,0} -}; - -const unsigned char vendoropts_Samsung_SV4012H[][2] = { - PRESET_9_HALFMINUTES, - {0,0} -}; - -const unsigned char vendoropts_Samsung_SV1204H[][2] = { - PRESET_9_HALFMINUTES, - PRESET_194_10XCELSIUS, - {0,0} -}; - -const unsigned char vendoropts_Hitachi_DK23XX[][2] = { - PRESET_9_MINUTES, - PRESET_193_LOADUNLOAD, - {0,0} -}; - -const char same_as_minus_F[]="Fixes byte order in some SMART data (same as -F samsung)"; -const char same_as_minus_F2[]="Fixes byte order in some SMART data (same as -F samsung2)"; - -const char may_need_minus_F_disabled[] ="May need -F samsung disabled; see manual for details."; -const char may_need_minus_F2_disabled[]="May need -F samsung2 disabled; see manual for details."; -const char may_need_minus_F2_enabled[] ="May need -F samsung2 enabled; see manual for details."; -const char may_need_minus_F_enabled[] ="May need -F samsung or -F samsung2 enabled; see manual for details."; - -/* Special-purpose functions for use in knowndrives[]. */ -void specialpurpose_reverse_samsung(smartmonctrl *con) -{ - if (con->fixfirmwarebug==FIX_NOTSPECIFIED) - con->fixfirmwarebug = FIX_SAMSUNG; -} -void specialpurpose_reverse_samsung2(smartmonctrl *con) -{ - if (con->fixfirmwarebug==FIX_NOTSPECIFIED) - con->fixfirmwarebug = FIX_SAMSUNG2; -} - -/* Table of settings for known drives terminated by an element containing all - * zeros. The drivesettings structure is described in knowndrives.h. Note - * that lookupdrive() will search knowndrives[] from the start to end or - * until it finds the first match, so the order in knowndrives[] is important - * for distinct entries that could match the same drive. */ - -// Note that the table just below uses EXTENDED REGULAR EXPRESSIONS. -// A good on-line reference for these is: -// http://www.zeus.com/extra/docsystem/docroot/apps/web/docs/modules/access/regex.html - -const drivesettings knowndrives[] = { - { // IBM Deskstar 60GXP series - "IC35L0[12346]0AVER07", - ".*", - "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n" - "Please see http://www.geocities.com/dtla_update/index.html#rel and\n" - "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n" - "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215", - NULL, NULL, NULL - }, - { // IBM Deskstar 40GV & 75GXP series (A5AA/A6AA firmware) - "(IBM-)?DTLA-30[57]0[123467][05]", - "^T[WX][123468A]OA[56]AA$", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 40GV & 75GXP series (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://www.geocities.com/dtla_update/ and\n" - "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n" - "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215", - NULL, NULL, NULL - }, - { // ExcelStor J240 - "^ExcelStor Technology J240$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Fujitsu MPB series - "^FUJITSU MPB....ATU?$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPD and MPE series - "^FUJITSU MP[DE]....A[HTE]$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPF series - "^FUJITSU MPF3(102A[HT]|153A[HT]|204A[HT])$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPG series - "^FUJITSU MPG3(102A(H|T E)|204A(H|[HT] E)|307A(H E|T)|409A[HT] E)$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPC series - "^FUJITSU MPC3(032AT|043AT|045AH|064A[HT]|084AT|096AT|102AT)$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHN2300AT - "^FUJITSU MHN2300AT$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHR2040AT - "^FUJITSU MHR2040AT$", - ".*", // Tested on 40BA - NULL, - vendoropts_Fujitsu_MHR2040AT, - NULL, NULL - }, - { // Fujitsu MHSxxxxAT family - "^FUJITSU MHS20[6432]0AT( .)?$", - ".*", - NULL, - vendoropts_Fujitsu_MHS2020AT, - NULL, NULL - }, - { // Fujitsu MHL2300AT, MHM2200AT, MHM2100AT, MHM2150AT - "^FUJITSU MH(L230|M2(20|10|15))0AT$", - ".*", - "This drive's firmware has a harmless Drive Identity Structure\n" - "checksum error bug.", - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHTxxxxAT family - "^FUJITSU MHT20[23468]0AT$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHTxxxxAH family - "^FUJITSU MHT20[468]0AH$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Samsung SV4012H (known firmware) - "^SAMSUNG SV4012H$", - "^RM100-08$", - NULL, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV4012H (all other firmware) - "^SAMSUNG SV4012H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV0412H (known firmware) - "^SAMSUNG SV0412H$", - "^SK100-01$", - NULL, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV0412H (all other firmware) - "^SAMSUNG SV0412H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV1204H (known firmware) - "^SAMSUNG SV1204H$", - "^RK100-1[3-5]$", - NULL, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { //Samsung SV1204H (all other firmware) - "^SAMSUNG SV1204H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { //SAMSUNG SV0322A tested with FW JK200-35 - "^SAMSUNG SV0322A$", - ".*", - NULL, - NULL, - NULL, - NULL - }, - { // SAMSUNG SP40A2H with RR100-07 firmware - "^SAMSUNG SP40A2H$", - "^RR100-07$", - NULL, - vendoropts_9_halfminutes, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { - // Any other Samsung disk with *-23 *-24 firmware - // SAMSUNG SP1213N (TL100-23 firmware) - // SAMSUNG SP0802N (TK100-23 firmware) - // Samsung SP1604N, tested with FW TM100-23 and TM100-24 - "^SAMSUNG .*$", - ".*-2[34]$", - NULL, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung2, - same_as_minus_F2 - }, - { // All Samsung drives with '.*-25' firmware - "^SAMSUNG.*", - ".*-25$", - may_need_minus_F2_disabled, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung2, - same_as_minus_F2 - }, - { // All Samsung drives with '.*-26 or later (currently to -39)' firmware - "^SAMSUNG.*", - ".*-(2[6789]|3[0-9])$", - NULL, - vendoropts_Samsung_SV4012H, - NULL, - NULL - }, - { // Samsung ALL OTHER DRIVES - "^SAMSUNG.*", - ".*", - may_need_minus_F_enabled, - NULL, NULL, NULL - }, - { // Maxtor Fireball 541DX family - "^Maxtor 2B0(0[468]|1[05]|20)H1$", - ".*", - NULL, - vendoropts_Maxtor_4D080H4, - NULL, NULL - }, - { // Maxtor DiamondMax 3400 Ultra ATA family - "^Maxtor 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|1(350|202)E8|1010E6|0840E5|0640E4)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax D540X-4G family - "^Maxtor 4G(120J6|160J[68])$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax D540X-4K family - "^MAXTOR 4K(020H1|040H2|060H3|080H4)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax Plus D740X family - "^MAXTOR 6L0(20[JL]1|40[JL]2|60[JL]3|80[JL]4)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax Plus 5120 Ultra ATA 33 family - "^Maxtor 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 6800 Ultra ATA 66 family - "^Maxtor 9(2732U8|2390U7|2049U6|1707U5|1366U4|1024U3|0845U3|0683U2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax D540X-4D and Maxtor 4G120J6 - "^Maxtor (4D0(20H1|40H2|60H3|80H4)|4G120J6)$", - ".*", - NULL, - vendoropts_Maxtor_4D080H4, - NULL, NULL - }, - { // Maxtor DiamondMax 16 family - "^Maxtor 4(R0[68]0[JL]|R1[26]0L|A160J)0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 4320 family - "^Maxtor (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D4|90432D2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 20 VL family - "^Maxtor (94091U8|93071U6|92561U5|92041U4|91731U4|91531U3|91361U3|91021U2|90841U2|90651U2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax VL 30 family - "^Maxtor (33073U4|32049U3|31536U2|30768U1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 36 family - "^Maxtor (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 40 ATA 66 series - "^Maxtor 9(0684U2|1024U2|1362U3|1536U3|2049U4|2562U5|3073U6|4098U8)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 40 series (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)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 40 VL Ultra ATA 100 series - "^Maxtor 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 45 Ulta ATA 100 family - "^Maxtor 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 60 family - "^Maxtor 5T0(60H6|40H4|30H3|20H2|10H1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 80 family - "^Maxtor (98196H8|96147H6)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 536DX family - "^Maxtor 4W(100H6|080H6|060H4|040H3|030H2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 8 family - "^Maxtor 6E0[234]0L0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 9 family - "^Maxtor 6Y((060|080|120|160)L0|(060|080|120|160|200|250)P0|(060|080|120|160|200|250)M0)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor MaXLine Plus II - "^Maxtor 7Y250[PM]0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor MaXLine II family - "^Maxtor [45]A(25|32)0[JN]0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // HITACHI_DK14FA-20B - "^HITACHI_DK14FA-20B$", - ".*", - NULL, - vendoropts_Hitachi_DK23XX, - NULL, NULL - }, - { // HITACHI Travelstar DK23XX/DK23XXB series - "^HITACHI_DK23..-..B?$", - ".*", - NULL, - vendoropts_Hitachi_DK23XX, - NULL, NULL - }, - { // IBM Deskstar 14GXP and 16GP series - "^IBM-DTTA-3(7101|7129|7144|5032|5043|5064|5084|5101|5129|5168)0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 25GP and 22GXP family - "^IBM-DJNA-3(5(101|152|203|250)|7(091|135|180|220))0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 25GS, 18GT, and 12GN family - "^IBM-DARA-2(25|18|15|12|09|06)000$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 48GH, 30GN, and 15GN family - "^IC25(T048ATDA05|N0(30|20|15|12|10|07|06|05)ATDA04)-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 32GH, 30GT, and 20GN family - "^IBM-DJSA-2(32|30|20|10|05)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 37GP and 34GXP family - "^IBM-DPTA-3(5(375|300|225|150)|7(342|273|205|136))0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Travelstar 60GH and 40GN family - "^IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Travelstar 40GNX family - "^IC25N0[42]0ATC[SX]05-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Travelstar 80GN family - "^(Hitachi )?IC25N0[23468]0ATMR04-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Travelstar 5K80 family - "^HTS5480[8642]0M9AT00$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Deskstar 120GXP family - "^IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Deskstar GXP-180 family - "^IC35L(030|060|090|120|180)AVV207-[01]$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 14GS - "^IBM-DCYA-214000$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 4LP - "^IBM-DTNA-2(180|216)0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Deskstar 7K250 series - "^HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4025GAS - "^TOSHIBA MK4025GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK6021GAS [Bruce -- use for testing on laptop] - "^TOSHIBA MK6021GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4019GAX/MK4019GAXB - "^TOSHIBA MK4019GAXB?$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK6409MAV - "^TOSHIBA MK6409MAV$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOS MK3019GAXB SUN30G - "^TOS MK3019GAXB SUN30G$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK2016GAP, MK2017GAP, MK2018GAP, MK2018GAS, MK2023GAS - "^TOSHIBA MK20(1[678]GAP|(18|23)GAS)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4018GAS - "^TOSHIBA MK4018GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK3017GAP - "^TOSHIBA MK3017GAP$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Medalist 8641 family - "^ST3(2110|3221|4312|6531|8641)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series X family - "^ST3(10014A(CE)?|20014A)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series 6 family - "^ST3(8002|6002|4081|3061|2041)0A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series 5 family - "^ST3(40823|30621|20413|15311|10211)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U8 family - "^ST3(8410|4313|17221|13021)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA II family - "^ST3(3063|2042|1532|1021)0A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA III family - "^ST3(40824|30620|20414|15310|10215)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA IV family - "^ST3(20011|40016|60021|80021)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA V family - "^ST3(12002(3A|4A|9A|3AS)|800(23A|15A|23AS)|60(015A|210A)|40017A)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda 7200.7 and 7200.7 Plus family - "^ST3(200822AS?|16002[13]AS?|12002[26]AS?|8001[13]AS?|60014A|40014AS?)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Medalist 17242, 13032, 10232, 8422, and 4312 - "^ST3(1724|1303|1023|842|431)2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // 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-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar family - /* 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-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxAB series - /* 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)00AB-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxAA series - /* 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(64|84|102|136|205|272|307)AA(-.*)?$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxBA series - /* 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(102|136|153|205)BA$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC12500, AC24300, AC25100, AC36400, AC38400 - "^WDC AC(125|243|251|364|384)00", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar SE family - /* 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((4|6|8|10|12|16|18|20|25)00JB|(12|20|25)00PB)-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar SE (Serial ATA) family - "^WDC WD(4|8|12|16|20|25)00JD-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC38400 - "^WDC AC38400L$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC23200L - "^WDC AC23200L$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLlct15 20 and QUANTUM FIREBALLlct15 30 - "^QUANTUM FIREBALLlct15 [23]0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLlct20 series - "^QUANTUM FIREBALLlct20 [234]0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL CX10.2A - "^QUANTUM FIREBALL CX10.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLP LM15 and LM30 - "^QUANTUM FIREBALLP LM(15|30)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL CR4.3A - "^QUANTUM FIREBALL CR4.3A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLP AS10.2 and AS40.0 - "^QUANTUM FIREBALLP AS(10.2|40.0)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL EX6.4A - "^QUANTUM FIREBALL EX6.4A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL ST3.2A - "^QUANTUM FIREBALL ST3.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL EX3.2A - "^QUANTUM FIREBALL EX3.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - /*------------------------------------------------------------ - * End of table. Do not add entries below this marker. - *------------------------------------------------------------ */ - {NULL, NULL, NULL, NULL, NULL, NULL} -}; - -// 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 index of the -// first match in knowndrives[] or -1 if no match if found. -int lookupdrive(const char *model, const char *firmware) -{ - regex_t regex; - int i, index; - const char *empty = ""; - - model = model ? model : empty; - firmware = firmware ? firmware : empty; - - for (i = 0, index = -1; index == -1 && knowndrives[i].modelregexp; i++) { - // Attempt to compile regular expression. - if (compileregex(®ex, knowndrives[i].modelregexp, REG_EXTENDED)) - goto CONTINUE; - - // Check whether model matches the regular expression in knowndrives[i]. - if (!regexec(®ex, model, 0, NULL, 0)) { - // model matches, now check firmware. - if (!knowndrives[i].firmwareregexp) - // The firmware regular expression in knowndrives[i] is NULL, which is - // considered a match. - index = i; - else { - // Compare firmware against the regular expression in knowndrives[i]. - regfree(®ex); // Recycle regex. - if (compileregex(®ex, knowndrives[i].firmwareregexp, REG_EXTENDED)) - goto CONTINUE; - if (!regexec(®ex, firmware, 0, NULL, 0)) - index = i; - } - } - CONTINUE: - regfree(®ex); - } - - return index; -} - - -// Shows all presets for drives in knowndrives[]. -void showonepreset(const drivesettings *drivetable){ - - const unsigned char (* presets)[2] = drivetable->vendoropts; - int first_preset = 1; - - // Basic error check - if (!drivetable || !drivetable->modelregexp){ - pout("Null known drive table pointer. Please report\n" - "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n"); - return; - } - - // print model and firmware regular expressions - pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL REGEXP:", drivetable->modelregexp); - pout("%-*s %s\n", TABLEPRINTWIDTH, "FIRMWARE REGEXP:", drivetable->firmwareregexp ? - drivetable->firmwareregexp : ""); - - // if there are any presets, then show them - if (presets && (*presets)[0]) while (1) { - char out[256]; - const int attr = (*presets)[0], val = (*presets)[1]; - unsigned char fakearray[MAX_ATTRIBUTE_NUM]; - - // if we are at the end of the attribute list, break out - if (!attr) - break; - - // This is a hack. ataPrintSmartAttribName() needs a pointer to an - // "array" to dereference, so we provide such a pointer. - fakearray[attr]=val; - ataPrintSmartAttribName(out, attr, fakearray); - - // Use leading zeros instead of spaces so that everything lines up. - out[0] = (out[0] == ' ') ? '0' : out[0]; - out[1] = (out[1] == ' ') ? '0' : out[1]; - pout("%-*s %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", out); - first_preset = 0; - presets++; - } - else - pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required."); - - - // Is a special purpose function defined? If so, describe it - if (drivetable->specialpurpose){ - pout("%-*s ", TABLEPRINTWIDTH, "OTHER PRESETS:"); - pout("%s\n", drivetable->functiondesc ? - drivetable->functiondesc : "A special purpose function " - "is defined for this drive"); - } - - // Print any special warnings - if (drivetable->warningmsg){ - pout("%-*s ", TABLEPRINTWIDTH, "WARNINGS:"); - pout("%s\n", drivetable->warningmsg); - } - - return; -} - -void showallpresets(void){ - int i; - - // loop over all entries in the knowndrives[] table, printing them - // out in a nice format - for (i=0; knowndrives[i].modelregexp; i++){ - showonepreset(&knowndrives[i]); - pout("\n"); - } - pout("For information about adding a drive to the database see the FAQ on the\n"); - pout("smartmontools home page: " PACKAGE_HOMEPAGE "\n"); - return; -} - -// Shows the presets (if any) that are available for the given drive. -void showpresets(const struct ata_identify_device *drive){ - int i; - char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; - - // get the drive's model/firmware strings - formatdriveidstring(model, (char *)drive->model, MODEL_STRING_LENGTH); - formatdriveidstring(firmware, (char *)drive->fw_rev, FIRMWARE_STRING_LENGTH); - - // and search to see if they match values in the table - if ((i = lookupdrive(model, firmware)) < 0) { - // 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(&knowndrives[i]); - return; -} - -// Sets preset vendor attribute options in opts by finding the entry -// (if any) for the given drive in knowndrives[]. Values that have -// already been set in opts will not be changed. Returns <0 if drive -// not recognized else index >=0 into drive database. -int applypresets(const struct ata_identify_device *drive, unsigned char **optsptr, - smartmonctrl *con) { - int i; - unsigned char *opts; - char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; - - if (*optsptr==NULL) - bytes+=MAX_ATTRIBUTE_NUM; - - if (*optsptr==NULL && !(*optsptr=(unsigned char *)calloc(MAX_ATTRIBUTE_NUM,1))){ - pout("Unable to allocate memory in applypresets()"); - bytes-=MAX_ATTRIBUTE_NUM; - EXIT(1); - } - - opts=*optsptr; - - // get the drive's model/firmware strings - formatdriveidstring(model, (char *)drive->model, MODEL_STRING_LENGTH); - formatdriveidstring(firmware, (char *)drive->fw_rev, FIRMWARE_STRING_LENGTH); - - // Look up the drive in knowndrives[]. - if ((i = lookupdrive(model, firmware)) >= 0) { - - // if vendoropts is non-NULL then Attribute interpretation presets - if (knowndrives[i].vendoropts) { - const unsigned char (* presets)[2]; - - // For each attribute in list of attribute/val pairs... - presets = knowndrives[i].vendoropts; - while (1) { - const int attr = (*presets)[0]; - const int val = (*presets)[1]; - - if (!attr) - break; - - // ... set attribute if user hasn't already done so. - if (!opts[attr]) - opts[attr] = val; - presets++; - } - } - - // If a special-purpose function is defined for this drive then - // call it. Note that if command line arguments or Directives - // over-ride this choice, then the specialpurpose function that is - // called must deal with this. - if (knowndrives[i].specialpurpose) - (*knowndrives[i].specialpurpose)(con); - } - - // return <0 if drive wasn't recognized, or index>=0 into database - // if it was - return i; -} diff --git a/sm5/knowndrives.cpp b/sm5/knowndrives.cpp deleted file mode 100644 index 9026bc8bbc6781532076f8b498496f4f9a7be29e..0000000000000000000000000000000000000000 --- a/sm5/knowndrives.cpp +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * knowndrives.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * Address of support mailing list: smartmontools-support@lists.sourceforge.net - * - * Copyright (C) 2003-4 Philip Williams, 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "utility.h" // includes <regex.h> -#include "config.h" - -const char *knowndrives_c_cvsid="$Id: knowndrives.cpp,v 1.117 2004/07/31 16:38:00 pjwilliams Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID UTILITY_H_CVSID; - -#define MODEL_STRING_LENGTH 40 -#define FIRMWARE_STRING_LENGTH 8 -#define TABLEPRINTWIDTH 19 - -// See vendorattributeargs[] array in atacmds.c for definitions. -#define PRESET_9_MINUTES { 9, 1 } -#define PRESET_9_TEMP { 9, 2 } -#define PRESET_9_SECONDS { 9, 3 } -#define PRESET_9_HALFMINUTES { 9, 4 } -#define PRESET_192_EMERGENCYRETRACTCYCLECT { 192, 1 } -#define PRESET_193_LOADUNLOAD { 193, 1 } -#define PRESET_194_10XCELSIUS { 194, 1 } -#define PRESET_194_UNKNOWN { 194, 2 } -#define PRESET_198_OFFLINESCANUNCSECTORCT { 198, 1 } -#define PRESET_200_WRITEERRORCOUNT { 200, 1 } -#define PRESET_201_DETECTEDTACOUNT { 201, 1 } -#define PRESET_220_TEMP { 220, 1 } - -/* Arrays of preset vendor-specific attribute options for use in - * knowndrives[]. */ - -extern int64_t bytes; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// These three are common to several models. -const unsigned char vendoropts_9_minutes[][2] = { - PRESET_9_MINUTES, - {0,0} -}; -const unsigned char vendoropts_9_halfminutes[][2] = { - PRESET_9_HALFMINUTES, - {0,0} -}; -const unsigned char vendoropts_9_seconds[][2] = { - PRESET_9_SECONDS, - {0,0} -}; - -const unsigned char vendoropts_Maxtor_4D080H4[][2] = { - PRESET_9_MINUTES, - PRESET_194_UNKNOWN, - {0,0} -}; - -const unsigned char vendoropts_Fujitsu_MHS2020AT[][2] = { - PRESET_9_SECONDS, - PRESET_192_EMERGENCYRETRACTCYCLECT, - PRESET_198_OFFLINESCANUNCSECTORCT, - PRESET_200_WRITEERRORCOUNT, - PRESET_201_DETECTEDTACOUNT, - {0,0} -}; - -const unsigned char vendoropts_Fujitsu_MHR2040AT[][2] = { - PRESET_9_SECONDS, - PRESET_192_EMERGENCYRETRACTCYCLECT, - PRESET_198_OFFLINESCANUNCSECTORCT, - PRESET_200_WRITEERRORCOUNT, - {0,0} -}; - -const unsigned char vendoropts_Samsung_SV4012H[][2] = { - PRESET_9_HALFMINUTES, - {0,0} -}; - -const unsigned char vendoropts_Samsung_SV1204H[][2] = { - PRESET_9_HALFMINUTES, - PRESET_194_10XCELSIUS, - {0,0} -}; - -const unsigned char vendoropts_Hitachi_DK23XX[][2] = { - PRESET_9_MINUTES, - PRESET_193_LOADUNLOAD, - {0,0} -}; - -const char same_as_minus_F[]="Fixes byte order in some SMART data (same as -F samsung)"; -const char same_as_minus_F2[]="Fixes byte order in some SMART data (same as -F samsung2)"; - -const char may_need_minus_F_disabled[] ="May need -F samsung disabled; see manual for details."; -const char may_need_minus_F2_disabled[]="May need -F samsung2 disabled; see manual for details."; -const char may_need_minus_F2_enabled[] ="May need -F samsung2 enabled; see manual for details."; -const char may_need_minus_F_enabled[] ="May need -F samsung or -F samsung2 enabled; see manual for details."; - -/* Special-purpose functions for use in knowndrives[]. */ -void specialpurpose_reverse_samsung(smartmonctrl *con) -{ - if (con->fixfirmwarebug==FIX_NOTSPECIFIED) - con->fixfirmwarebug = FIX_SAMSUNG; -} -void specialpurpose_reverse_samsung2(smartmonctrl *con) -{ - if (con->fixfirmwarebug==FIX_NOTSPECIFIED) - con->fixfirmwarebug = FIX_SAMSUNG2; -} - -/* Table of settings for known drives terminated by an element containing all - * zeros. The drivesettings structure is described in knowndrives.h. Note - * that lookupdrive() will search knowndrives[] from the start to end or - * until it finds the first match, so the order in knowndrives[] is important - * for distinct entries that could match the same drive. */ - -// Note that the table just below uses EXTENDED REGULAR EXPRESSIONS. -// A good on-line reference for these is: -// http://www.zeus.com/extra/docsystem/docroot/apps/web/docs/modules/access/regex.html - -const drivesettings knowndrives[] = { - { // IBM Deskstar 60GXP series - "IC35L0[12346]0AVER07", - ".*", - "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n" - "Please see http://www.geocities.com/dtla_update/index.html#rel and\n" - "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n" - "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215", - NULL, NULL, NULL - }, - { // IBM Deskstar 40GV & 75GXP series (A5AA/A6AA firmware) - "(IBM-)?DTLA-30[57]0[123467][05]", - "^T[WX][123468A]OA[56]AA$", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 40GV & 75GXP series (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://www.geocities.com/dtla_update/ and\n" - "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n" - "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215", - NULL, NULL, NULL - }, - { // ExcelStor J240 - "^ExcelStor Technology J240$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Fujitsu MPB series - "^FUJITSU MPB....ATU?$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPD and MPE series - "^FUJITSU MP[DE]....A[HTE]$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPF series - "^FUJITSU MPF3(102A[HT]|153A[HT]|204A[HT])$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPG series - "^FUJITSU MPG3(102A(H|T E)|204A(H|[HT] E)|307A(H E|T)|409A[HT] E)$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MPC series - "^FUJITSU MPC3(032AT|043AT|045AH|064A[HT]|084AT|096AT|102AT)$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHN2300AT - "^FUJITSU MHN2300AT$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHR2040AT - "^FUJITSU MHR2040AT$", - ".*", // Tested on 40BA - NULL, - vendoropts_Fujitsu_MHR2040AT, - NULL, NULL - }, - { // Fujitsu MHSxxxxAT family - "^FUJITSU MHS20[6432]0AT( .)?$", - ".*", - NULL, - vendoropts_Fujitsu_MHS2020AT, - NULL, NULL - }, - { // Fujitsu MHL2300AT, MHM2200AT, MHM2100AT, MHM2150AT - "^FUJITSU MH(L230|M2(20|10|15))0AT$", - ".*", - "This drive's firmware has a harmless Drive Identity Structure\n" - "checksum error bug.", - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHTxxxxAT family - "^FUJITSU MHT20[23468]0AT$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Fujitsu MHTxxxxAH family - "^FUJITSU MHT20[468]0AH$", - ".*", - NULL, - vendoropts_9_seconds, - NULL, NULL - }, - { // Samsung SV4012H (known firmware) - "^SAMSUNG SV4012H$", - "^RM100-08$", - NULL, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV4012H (all other firmware) - "^SAMSUNG SV4012H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV0412H (known firmware) - "^SAMSUNG SV0412H$", - "^SK100-01$", - NULL, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV0412H (all other firmware) - "^SAMSUNG SV0412H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { // Samsung SV1204H (known firmware) - "^SAMSUNG SV1204H$", - "^RK100-1[3-5]$", - NULL, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { //Samsung SV1204H (all other firmware) - "^SAMSUNG SV1204H$", - ".*", - may_need_minus_F_disabled, - vendoropts_Samsung_SV1204H, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { //SAMSUNG SV0322A tested with FW JK200-35 - "^SAMSUNG SV0322A$", - ".*", - NULL, - NULL, - NULL, - NULL - }, - { // SAMSUNG SP40A2H with RR100-07 firmware - "^SAMSUNG SP40A2H$", - "^RR100-07$", - NULL, - vendoropts_9_halfminutes, - specialpurpose_reverse_samsung, - same_as_minus_F - }, - { - // Any other Samsung disk with *-23 *-24 firmware - // SAMSUNG SP1213N (TL100-23 firmware) - // SAMSUNG SP0802N (TK100-23 firmware) - // Samsung SP1604N, tested with FW TM100-23 and TM100-24 - "^SAMSUNG .*$", - ".*-2[34]$", - NULL, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung2, - same_as_minus_F2 - }, - { // All Samsung drives with '.*-25' firmware - "^SAMSUNG.*", - ".*-25$", - may_need_minus_F2_disabled, - vendoropts_Samsung_SV4012H, - specialpurpose_reverse_samsung2, - same_as_minus_F2 - }, - { // All Samsung drives with '.*-26 or later (currently to -39)' firmware - "^SAMSUNG.*", - ".*-(2[6789]|3[0-9])$", - NULL, - vendoropts_Samsung_SV4012H, - NULL, - NULL - }, - { // Samsung ALL OTHER DRIVES - "^SAMSUNG.*", - ".*", - may_need_minus_F_enabled, - NULL, NULL, NULL - }, - { // Maxtor Fireball 541DX family - "^Maxtor 2B0(0[468]|1[05]|20)H1$", - ".*", - NULL, - vendoropts_Maxtor_4D080H4, - NULL, NULL - }, - { // Maxtor DiamondMax 3400 Ultra ATA family - "^Maxtor 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|1(350|202)E8|1010E6|0840E5|0640E4)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax D540X-4G family - "^Maxtor 4G(120J6|160J[68])$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax D540X-4K family - "^MAXTOR 4K(020H1|040H2|060H3|080H4)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax Plus D740X family - "^MAXTOR 6L0(20[JL]1|40[JL]2|60[JL]3|80[JL]4)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Maxtor DiamondMax Plus 5120 Ultra ATA 33 family - "^Maxtor 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 6800 Ultra ATA 66 family - "^Maxtor 9(2732U8|2390U7|2049U6|1707U5|1366U4|1024U3|0845U3|0683U2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax D540X-4D and Maxtor 4G120J6 - "^Maxtor (4D0(20H1|40H2|60H3|80H4)|4G120J6)$", - ".*", - NULL, - vendoropts_Maxtor_4D080H4, - NULL, NULL - }, - { // Maxtor DiamondMax 16 family - "^Maxtor 4(R0[68]0[JL]|R1[26]0L|A160J)0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 4320 family - "^Maxtor (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D4|90432D2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 20 VL family - "^Maxtor (94091U8|93071U6|92561U5|92041U4|91731U4|91531U3|91361U3|91021U2|90841U2|90651U2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax VL 30 family - "^Maxtor (33073U4|32049U3|31536U2|30768U1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 36 family - "^Maxtor (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 40 ATA 66 series - "^Maxtor 9(0684U2|1024U2|1362U3|1536U3|2049U4|2562U5|3073U6|4098U8)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 40 series (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)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 40 VL Ultra ATA 100 series - "^Maxtor 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 45 Ulta ATA 100 family - "^Maxtor 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 60 family - "^Maxtor 5T0(60H6|40H4|30H3|20H2|10H1)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 80 family - "^Maxtor (98196H8|96147H6)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax 536DX family - "^Maxtor 4W(100H6|080H6|060H4|040H3|030H2)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 8 family - "^Maxtor 6E0[234]0L0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor DiamondMax Plus 9 family - "^Maxtor 6Y((060|080|120|160)L0|(060|080|120|160|200|250)P0|(060|080|120|160|200|250)M0)$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor MaXLine Plus II - "^Maxtor 7Y250[PM]0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // Maxtor MaXLine II family - "^Maxtor [45]A(25|32)0[JN]0$", - ".*", - NULL, - vendoropts_9_minutes, - NULL, NULL - }, - { // HITACHI_DK14FA-20B - "^HITACHI_DK14FA-20B$", - ".*", - NULL, - vendoropts_Hitachi_DK23XX, - NULL, NULL - }, - { // HITACHI Travelstar DK23XX/DK23XXB series - "^HITACHI_DK23..-..B?$", - ".*", - NULL, - vendoropts_Hitachi_DK23XX, - NULL, NULL - }, - { // IBM Deskstar 14GXP and 16GP series - "^IBM-DTTA-3(7101|7129|7144|5032|5043|5064|5084|5101|5129|5168)0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 25GP and 22GXP family - "^IBM-DJNA-3(5(101|152|203|250)|7(091|135|180|220))0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 25GS, 18GT, and 12GN family - "^IBM-DARA-2(25|18|15|12|09|06)000$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 48GH, 30GN, and 15GN family - "^IC25(T048ATDA05|N0(30|20|15|12|10|07|06|05)ATDA04)-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 32GH, 30GT, and 20GN family - "^IBM-DJSA-2(32|30|20|10|05)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Deskstar 37GP and 34GXP family - "^IBM-DPTA-3(5(375|300|225|150)|7(342|273|205|136))0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Travelstar 60GH and 40GN family - "^IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Travelstar 40GNX family - "^IC25N0[42]0ATC[SX]05-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Travelstar 80GN family - "^(Hitachi )?IC25N0[23468]0ATMR04-.$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Travelstar 5K80 family - "^HTS5480[8642]0M9AT00$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Deskstar 120GXP family - "^IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM/Hitachi Deskstar GXP-180 family - "^IC35L(030|060|090|120|180)AVV207-[01]$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 14GS - "^IBM-DCYA-214000$", - ".*", - NULL, NULL, NULL, NULL - }, - { // IBM Travelstar 4LP - "^IBM-DTNA-2(180|216)0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Hitachi Deskstar 7K250 series - "^HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4025GAS - "^TOSHIBA MK4025GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK6021GAS [Bruce -- use for testing on laptop] - "^TOSHIBA MK6021GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4019GAX/MK4019GAXB - "^TOSHIBA MK4019GAXB?$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK6409MAV - "^TOSHIBA MK6409MAV$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOS MK3019GAXB SUN30G - "^TOS MK3019GAXB SUN30G$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK2016GAP, MK2017GAP, MK2018GAP, MK2018GAS, MK2023GAS - "^TOSHIBA MK20(1[678]GAP|(18|23)GAS)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK4018GAS - "^TOSHIBA MK4018GAS$", - ".*", - NULL, NULL, NULL, NULL - }, - { // TOSHIBA MK3017GAP - "^TOSHIBA MK3017GAP$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Medalist 8641 family - "^ST3(2110|3221|4312|6531|8641)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series X family - "^ST3(10014A(CE)?|20014A)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series 6 family - "^ST3(8002|6002|4081|3061|2041)0A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U Series 5 family - "^ST3(40823|30621|20413|15311|10211)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate U8 family - "^ST3(8410|4313|17221|13021)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA II family - "^ST3(3063|2042|1532|1021)0A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA III family - "^ST3(40824|30620|20414|15310|10215)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA IV family - "^ST3(20011|40016|60021|80021)A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda ATA V family - "^ST3(12002(3A|4A|9A|3AS)|800(23A|15A|23AS)|60(015A|210A)|40017A)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Barracuda 7200.7 and 7200.7 Plus family - "^ST3(200822AS?|16002[13]AS?|12002[26]AS?|8001[13]AS?|60014A|40014AS?)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Seagate Medalist 17242, 13032, 10232, 8422, and 4312 - "^ST3(1724|1303|1023|842|431)2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // 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-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar family - /* 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-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxAB series - /* 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)00AB-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxAA series - /* 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(64|84|102|136|205|272|307)AA(-.*)?$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar WDxxxBA series - /* 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(102|136|153|205)BA$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC12500, AC24300, AC25100, AC36400, AC38400 - "^WDC AC(125|243|251|364|384)00", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar SE family - /* 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((4|6|8|10|12|16|18|20|25)00JB|(12|20|25)00PB)-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar SE (Serial ATA) family - "^WDC WD(4|8|12|16|20|25)00JD-.*$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC38400 - "^WDC AC38400L$", - ".*", - NULL, NULL, NULL, NULL - }, - { // Western Digital Caviar AC23200L - "^WDC AC23200L$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLlct15 20 and QUANTUM FIREBALLlct15 30 - "^QUANTUM FIREBALLlct15 [23]0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLlct20 series - "^QUANTUM FIREBALLlct20 [234]0$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL CX10.2A - "^QUANTUM FIREBALL CX10.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLP LM15 and LM30 - "^QUANTUM FIREBALLP LM(15|30)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL CR4.3A - "^QUANTUM FIREBALL CR4.3A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALLP AS10.2 and AS40.0 - "^QUANTUM FIREBALLP AS(10.2|40.0)$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL EX6.4A - "^QUANTUM FIREBALL EX6.4A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL ST3.2A - "^QUANTUM FIREBALL ST3.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - { // QUANTUM FIREBALL EX3.2A - "^QUANTUM FIREBALL EX3.2A$", - ".*", - NULL, NULL, NULL, NULL - }, - /*------------------------------------------------------------ - * End of table. Do not add entries below this marker. - *------------------------------------------------------------ */ - {NULL, NULL, NULL, NULL, NULL, NULL} -}; - -// 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 index of the -// first match in knowndrives[] or -1 if no match if found. -int lookupdrive(const char *model, const char *firmware) -{ - regex_t regex; - int i, index; - const char *empty = ""; - - model = model ? model : empty; - firmware = firmware ? firmware : empty; - - for (i = 0, index = -1; index == -1 && knowndrives[i].modelregexp; i++) { - // Attempt to compile regular expression. - if (compileregex(®ex, knowndrives[i].modelregexp, REG_EXTENDED)) - goto CONTINUE; - - // Check whether model matches the regular expression in knowndrives[i]. - if (!regexec(®ex, model, 0, NULL, 0)) { - // model matches, now check firmware. - if (!knowndrives[i].firmwareregexp) - // The firmware regular expression in knowndrives[i] is NULL, which is - // considered a match. - index = i; - else { - // Compare firmware against the regular expression in knowndrives[i]. - regfree(®ex); // Recycle regex. - if (compileregex(®ex, knowndrives[i].firmwareregexp, REG_EXTENDED)) - goto CONTINUE; - if (!regexec(®ex, firmware, 0, NULL, 0)) - index = i; - } - } - CONTINUE: - regfree(®ex); - } - - return index; -} - - -// Shows all presets for drives in knowndrives[]. -void showonepreset(const drivesettings *drivetable){ - - const unsigned char (* presets)[2] = drivetable->vendoropts; - int first_preset = 1; - - // Basic error check - if (!drivetable || !drivetable->modelregexp){ - pout("Null known drive table pointer. Please report\n" - "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n"); - return; - } - - // print model and firmware regular expressions - pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL REGEXP:", drivetable->modelregexp); - pout("%-*s %s\n", TABLEPRINTWIDTH, "FIRMWARE REGEXP:", drivetable->firmwareregexp ? - drivetable->firmwareregexp : ""); - - // if there are any presets, then show them - if (presets && (*presets)[0]) while (1) { - char out[256]; - const int attr = (*presets)[0], val = (*presets)[1]; - unsigned char fakearray[MAX_ATTRIBUTE_NUM]; - - // if we are at the end of the attribute list, break out - if (!attr) - break; - - // This is a hack. ataPrintSmartAttribName() needs a pointer to an - // "array" to dereference, so we provide such a pointer. - fakearray[attr]=val; - ataPrintSmartAttribName(out, attr, fakearray); - - // Use leading zeros instead of spaces so that everything lines up. - out[0] = (out[0] == ' ') ? '0' : out[0]; - out[1] = (out[1] == ' ') ? '0' : out[1]; - pout("%-*s %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", out); - first_preset = 0; - presets++; - } - else - pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required."); - - - // Is a special purpose function defined? If so, describe it - if (drivetable->specialpurpose){ - pout("%-*s ", TABLEPRINTWIDTH, "OTHER PRESETS:"); - pout("%s\n", drivetable->functiondesc ? - drivetable->functiondesc : "A special purpose function " - "is defined for this drive"); - } - - // Print any special warnings - if (drivetable->warningmsg){ - pout("%-*s ", TABLEPRINTWIDTH, "WARNINGS:"); - pout("%s\n", drivetable->warningmsg); - } - - return; -} - -void showallpresets(void){ - int i; - - // loop over all entries in the knowndrives[] table, printing them - // out in a nice format - for (i=0; knowndrives[i].modelregexp; i++){ - showonepreset(&knowndrives[i]); - pout("\n"); - } - pout("For information about adding a drive to the database see the FAQ on the\n"); - pout("smartmontools home page: " PACKAGE_HOMEPAGE "\n"); - return; -} - -// Shows the presets (if any) that are available for the given drive. -void showpresets(const struct ata_identify_device *drive){ - int i; - char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; - - // get the drive's model/firmware strings - formatdriveidstring(model, (char *)drive->model, MODEL_STRING_LENGTH); - formatdriveidstring(firmware, (char *)drive->fw_rev, FIRMWARE_STRING_LENGTH); - - // and search to see if they match values in the table - if ((i = lookupdrive(model, firmware)) < 0) { - // 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(&knowndrives[i]); - return; -} - -// Sets preset vendor attribute options in opts by finding the entry -// (if any) for the given drive in knowndrives[]. Values that have -// already been set in opts will not be changed. Returns <0 if drive -// not recognized else index >=0 into drive database. -int applypresets(const struct ata_identify_device *drive, unsigned char **optsptr, - smartmonctrl *con) { - int i; - unsigned char *opts; - char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; - - if (*optsptr==NULL) - bytes+=MAX_ATTRIBUTE_NUM; - - if (*optsptr==NULL && !(*optsptr=(unsigned char *)calloc(MAX_ATTRIBUTE_NUM,1))){ - pout("Unable to allocate memory in applypresets()"); - bytes-=MAX_ATTRIBUTE_NUM; - EXIT(1); - } - - opts=*optsptr; - - // get the drive's model/firmware strings - formatdriveidstring(model, (char *)drive->model, MODEL_STRING_LENGTH); - formatdriveidstring(firmware, (char *)drive->fw_rev, FIRMWARE_STRING_LENGTH); - - // Look up the drive in knowndrives[]. - if ((i = lookupdrive(model, firmware)) >= 0) { - - // if vendoropts is non-NULL then Attribute interpretation presets - if (knowndrives[i].vendoropts) { - const unsigned char (* presets)[2]; - - // For each attribute in list of attribute/val pairs... - presets = knowndrives[i].vendoropts; - while (1) { - const int attr = (*presets)[0]; - const int val = (*presets)[1]; - - if (!attr) - break; - - // ... set attribute if user hasn't already done so. - if (!opts[attr]) - opts[attr] = val; - presets++; - } - } - - // If a special-purpose function is defined for this drive then - // call it. Note that if command line arguments or Directives - // over-ride this choice, then the specialpurpose function that is - // called must deal with this. - if (knowndrives[i].specialpurpose) - (*knowndrives[i].specialpurpose)(con); - } - - // return <0 if drive wasn't recognized, or index>=0 into database - // if it was - return i; -} diff --git a/sm5/knowndrives.h b/sm5/knowndrives.h deleted file mode 100644 index fd5851e869fd76d23a4b3189e190fa389e8cb980..0000000000000000000000000000000000000000 --- a/sm5/knowndrives.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * knowndrives.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * Address of support mailing list: smartmontools-support@lists.sourceforge.net - * - * Copyright (C) 2003-4 Philip Williams, 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef KNOWNDRIVES_H_ -#define KNOWNDRIVES_H_ - -#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h,v 1.10 2004/01/02 16:05:25 ballen4705 Exp $\n" - -/* Structure used to store settings for specific drives in knowndrives[]. The - * elements are used in the following ways: - * - * modelregexp POSIX regular expression to match the model of a device. - * This should never be NULL (except to terminate the - * knowndrives array). - * firmwareregexp POSIX regular expression to match a devices's firmware - * version. This is optional and should be NULL if it is not - * to be used. If it is non-NULL 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. - * vendoropts Pointer to first element of an array of vendor-specific - * option attribute/value pairs that should be set for a - * matching device unless the user has requested otherwise. - * The user's own settings override these. The array should - * be terminated with the entry {0,0}. - * specialpurpose Pointer to a function that defines some additional action - * that may be taken for matching devices. - * functiondesc A description of the effect of the specialpurpose - * function. Used by showpresets() and showallpresets() to - * make the output more informative. - */ -typedef struct drivesettings_s { - const char * const modelregexp; - const char * const firmwareregexp; - const char * const warningmsg; - const unsigned char (* const vendoropts)[2]; - void (* const specialpurpose)(smartmonctrl *); - const char * const functiondesc; -} drivesettings; - -/* Table of settings for known drives. Defined in knowndrives.c. */ -extern const drivesettings knowndrives[]; - -// Searches knowndrives[] for a drive with the given model number and firmware -// string. -int lookupdrive(const char *model, const char *firmware); - -// Shows the presets (if any) that are available for the given drive. -void showpresets(const struct ata_identify_device *drive); - -// Shows all presets for drives in knowndrives[]. -void showallpresets(void); - -// Sets preset vendor attribute options in opts by finding the entry -// (if any) for the given drive in knowndrives[]. Values that have -// already been set in opts will not be changed. Also sets options in -// con. Returns <0 if drive not recognized else index of drive in -// database. -int applypresets(const struct ata_identify_device *drive, unsigned char **opts, - smartmonctrl *con); - -#endif diff --git a/sm5/os_darwin.c b/sm5/os_darwin.c deleted file mode 100644 index 4922a19515b3a67602da4e52c64236d5a4fd0234..0000000000000000000000000000000000000000 --- a/sm5/os_darwin.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * os_darwin.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdbool.h> -#include <errno.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/ata/IOATAStorageDefines.h> -#include <IOKit/storage/ata/ATASMARTLib.h> -#include <IOKit/storage/IOStorageDeviceCharacteristics.h> -#include <IOKit/storage/IOMedia.h> -#include <CoreFoundation/CoreFoundation.h> - - // No, I don't know why there isn't a header for this. -#define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice" - -#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.c,v 1.7 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_XXXX_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. - dev_name = dev_name; // suppress unused warning. - return CONTROLLER_ATA; -} - -// 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; - int result; - int index; - const char * cls; - - if (strcmp (name, "ATA") == 0) - cls = kIOATABlockStorageDeviceClass; - else // only ATA supported right now. - return 0; - - err = IOServiceGetMatchingServices (kIOMasterPortDefault, - IOServiceMatching (cls), - &i); - if (err != kIOReturnSuccess) - return -1; - - // Count the devices. - for (result = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; result++) - IOObjectRelease (device); - - // Create an array of service names. - IOIteratorReset (i); - *devlist = Calloc (result, sizeof (char *)); - if (! *devlist) - goto error; - for (index = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; index++) - { - io_string_t devName; - IORegistryEntryGetPath(device, kIOServicePlane, devName); - IOObjectRelease (device); - - (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__); - if (! (*devlist)[index]) - goto error; - } - IOObjectRelease (i); - - return result; - - error: - 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; - bool hassmart; - 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 the ATA block storage driver that is the parent of this device - while (! IOObjectConformsTo (disk, kIOATABlockStorageDeviceClass)) - { - IOReturn err; - io_object_t notdisk = disk; - - err = IORegistryEntryGetParentEntry (notdisk, kIOServicePlane, &disk); - if (err != kIOReturnSuccess || ! disk) - { - errno = ENODEV; - IOObjectRelease (notdisk); - return -1; - } - } - - devices[devnum].ioob = disk; - - { - CFDictionaryRef diskChars = NULL; - CFNumberRef diskFeatures = NULL; - UInt32 ataFeatures; - - // Determine whether the drive actually supports SMART. - if ((diskChars = IORegistryEntryCreateCFProperty (disk, - CFSTR (kIOPropertyDeviceCharacteristicsKey), - kCFAllocatorDefault, - kNilOptions)) != NULL - && CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"), - (const void **)&diskFeatures) - && CFNumberGetValue (diskFeatures, kCFNumberLongType, &ataFeatures) - && (ataFeatures & kIOATAFeatureSMART)) - devices[devnum].hassmart = true; - else - devices[devnum].hassmart = false; - if (diskChars) - CFRelease (diskChars); - } - - { - SInt32 dummy; - - devices[devnum].plugin = NULL; - devices[devnum].smartIf = NULL; - - // Create an interface to the ATA SMART library. - if (devices[devnum].hassmart - && IOCreatePlugInInterfaceForService (disk, - kIOATASMARTUserClientTypeID, - kIOCFPlugInInterfaceID, - &devices[devnum].plugin, - &dummy) == kIOReturnSuccess) - (*devices[devnum].plugin)->QueryInterface - (devices[devnum].plugin, - CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID), - (LPVOID) &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.c 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; - - if (! ifp) - return -1; - smartIf = *ifp; - - 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 && 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; - } - if (err == kIOReturnExclusiveAccess) - errno = EBUSY; - return err == kIOReturnSuccess ? 0 : -1; -} - -// There's no special handling needed for hidden devices, the kernel -// must deal with them. -int escalade_command_interface(int fd, int escalade_port, int escalade_type, - smart_command_set command, int select, - char *data) -{ - fd = fd; - escalade_port = escalade_port; - escalade_type = escalade_type; - command = command; - select = select; - data = data; - return -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; -} diff --git a/sm5/os_darwin.cpp b/sm5/os_darwin.cpp deleted file mode 100644 index 27d67a079e760069a33fca1ba844e0f83663e048..0000000000000000000000000000000000000000 --- a/sm5/os_darwin.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/* - * os_darwin.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdbool.h> -#include <errno.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/ata/IOATAStorageDefines.h> -#include <IOKit/storage/ata/ATASMARTLib.h> -#include <IOKit/storage/IOStorageDeviceCharacteristics.h> -#include <IOKit/storage/IOMedia.h> -#include <CoreFoundation/CoreFoundation.h> - - // No, I don't know why there isn't a header for this. -#define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice" - -#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,v 1.7 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_XXXX_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. - dev_name = dev_name; // suppress unused warning. - return CONTROLLER_ATA; -} - -// 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; - int result; - int index; - const char * cls; - - if (strcmp (name, "ATA") == 0) - cls = kIOATABlockStorageDeviceClass; - else // only ATA supported right now. - return 0; - - err = IOServiceGetMatchingServices (kIOMasterPortDefault, - IOServiceMatching (cls), - &i); - if (err != kIOReturnSuccess) - return -1; - - // Count the devices. - for (result = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; result++) - IOObjectRelease (device); - - // Create an array of service names. - IOIteratorReset (i); - *devlist = Calloc (result, sizeof (char *)); - if (! *devlist) - goto error; - for (index = 0; (device = IOIteratorNext (i)) != MACH_PORT_NULL; index++) - { - io_string_t devName; - IORegistryEntryGetPath(device, kIOServicePlane, devName); - IOObjectRelease (device); - - (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__); - if (! (*devlist)[index]) - goto error; - } - IOObjectRelease (i); - - return result; - - error: - 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; - bool hassmart; - 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 the ATA block storage driver that is the parent of this device - while (! IOObjectConformsTo (disk, kIOATABlockStorageDeviceClass)) - { - IOReturn err; - io_object_t notdisk = disk; - - err = IORegistryEntryGetParentEntry (notdisk, kIOServicePlane, &disk); - if (err != kIOReturnSuccess || ! disk) - { - errno = ENODEV; - IOObjectRelease (notdisk); - return -1; - } - } - - devices[devnum].ioob = disk; - - { - CFDictionaryRef diskChars = NULL; - CFNumberRef diskFeatures = NULL; - UInt32 ataFeatures; - - // Determine whether the drive actually supports SMART. - if ((diskChars = IORegistryEntryCreateCFProperty (disk, - CFSTR (kIOPropertyDeviceCharacteristicsKey), - kCFAllocatorDefault, - kNilOptions)) != NULL - && CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"), - (const void **)&diskFeatures) - && CFNumberGetValue (diskFeatures, kCFNumberLongType, &ataFeatures) - && (ataFeatures & kIOATAFeatureSMART)) - devices[devnum].hassmart = true; - else - devices[devnum].hassmart = false; - if (diskChars) - CFRelease (diskChars); - } - - { - SInt32 dummy; - - devices[devnum].plugin = NULL; - devices[devnum].smartIf = NULL; - - // Create an interface to the ATA SMART library. - if (devices[devnum].hassmart - && IOCreatePlugInInterfaceForService (disk, - kIOATASMARTUserClientTypeID, - kIOCFPlugInInterfaceID, - &devices[devnum].plugin, - &dummy) == kIOReturnSuccess) - (*devices[devnum].plugin)->QueryInterface - (devices[devnum].plugin, - CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID), - (LPVOID) &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.c 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; - - if (! ifp) - return -1; - smartIf = *ifp; - - 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 && 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; - } - if (err == kIOReturnExclusiveAccess) - errno = EBUSY; - return err == kIOReturnSuccess ? 0 : -1; -} - -// There's no special handling needed for hidden devices, the kernel -// must deal with them. -int escalade_command_interface(int fd, int escalade_port, int escalade_type, - smart_command_set command, int select, - char *data) -{ - fd = fd; - escalade_port = escalade_port; - escalade_type = escalade_type; - command = command; - select = select; - data = data; - return -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; -} diff --git a/sm5/os_darwin.h b/sm5/os_darwin.h deleted file mode 100644 index ae1f1c0c135be4369c60676dd0baeeef451c7260..0000000000000000000000000000000000000000 --- a/sm5/os_darwin.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * os_generic.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 Geoff Keating <geoffk@geoffk.org> - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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_XXXX_H_CVSID "$Id: os_darwin.h,v 1.1 2004/07/16 01:41:20 geoffk1 Exp $\n" - -// There isn't actually any content here yet. - -#endif /* OS_DARWIN_H_ */ diff --git a/sm5/os_darwin/English_Localizable.strings b/sm5/os_darwin/English_Localizable.strings deleted file mode 100644 index 4f5d3d6c48963d13aacfbcb2ffb15c06940718ca..0000000000000000000000000000000000000000 --- a/sm5/os_darwin/English_Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -<?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> diff --git a/sm5/os_darwin/SMART.in b/sm5/os_darwin/SMART.in deleted file mode 100644 index 4425ca9b68f8d627097d515ad67a3be599f85b25..0000000000000000000000000000000000000000 --- a/sm5/os_darwin/SMART.in +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -# Darwin init file for smartd -# -# Home page of code is: http://smartmontools.sourceforge.net -# -# Copyright (C) 2004 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., 675 -# Mass Ave, Cambridge, MA 02139, USA. - -# $Id: SMART.in,v 1.2 2004/08/09 05:31:43 geoffk1 Exp $ - -## -# 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" diff --git a/sm5/os_darwin/StartupParameters.plist b/sm5/os_darwin/StartupParameters.plist deleted file mode 100644 index 174d831d031cc766ea12a9ba56ce83c47bf9c45f..0000000000000000000000000000000000000000 --- a/sm5/os_darwin/StartupParameters.plist +++ /dev/null @@ -1,5 +0,0 @@ -{ - Description = "SMART disk monitoring"; - Provides = ("SMART"); - Requires = ("System Log"); -} diff --git a/sm5/os_freebsd.c b/sm5/os_freebsd.c deleted file mode 100644 index 1cde13c0b01f49242b5b2ad68fce8465a57d57db..0000000000000000000000000000000000000000 --- a/sm5/os_freebsd.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * os_freebsd.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdio.h> -#include <sys/types.h> -#include <dirent.h> -#include <err.h> -#include <camlib.h> -#include <cam/scsi/scsi_message.h> -#include <sys/ata.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <glob.h> -#include <fcntl.h> - - -#include "config.h" -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" -#include "os_freebsd.h" - -static const char *filenameandversion="$Id: os_freebsd.c,v 1.40 2004/08/16 22:44:26 ballen4705 Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_freebsd.c,v 1.40 2004/08/16 22:44:26 ballen4705 Exp $" \ -ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Private table of open devices: guaranteed zero on startup since -// part of static data. -struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV]; - -// forward declaration -static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *ch); - -// print examples for smartctl -void print_smartctl_examples(){ - printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( - " 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" -// " 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/ad0 (Prints all SMART information)\n" - " smartctl -s on -o on -S on /dev/ad0 (Enables SMART on first disk)\n" - " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n" - " smartctl -A -l selftest -q errorsonly /dev/ad0\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; -} - -// Like open(). Return positive integer handle, used by functions below only. mode=="ATA" or "SCSI". -int deviceopen (const char* dev, char* mode) { - struct freebsd_dev_channel *fdchan; - int parse_ok, i; - - // Search table for a free entry - for (i=0; i<FREEBSD_MAXDEV; i++) - if (!devicetable[i]) - break; - - // If no free entry found, return error. We have max allowed number - // of "file descriptors" already allocated. - if (i==FREEBSD_MAXDEV) { - errno=EMFILE; - return -1; - } - - fdchan = calloc(1,sizeof(struct freebsd_dev_channel)); - if (fdchan == NULL) { - // errno already set by call to malloc() - return -1; - } - - parse_ok = parse_ata_chan_dev (dev,fdchan); - if (parse_ok == CONTROLLER_UNKNOWN) { - free(fdchan); - errno = ENOTTY; - return -1; // can't handle what we don't know - } - - if (parse_ok == CONTROLLER_ATA) { - if ((fdchan->atacommand = open("/dev/ata",O_RDWR))<0) { - int myerror = errno; //preserve across free call - free (fdchan); - errno = myerror; - return -1; - } - } - - if (parse_ok == CONTROLLER_3WARE_678K_CHAR) { - char buf[512]; - sprintf(buf,"/dev/twe%d",fdchan->device); - printf("Using %s, as control device\n", buf); - if ((fdchan->atacommand = open(buf,O_RDWR))<0) { - int myerror = errno; // preserver across free call - free(fdchan); - errno=myerror; - return -1; - } - } - - if (parse_ok == CONTROLLER_SCSI) { - // this is really a NO-OP, as the parse takes care - // of filling in correct details - } - - // return pointer to "file descriptor" table entry, properly offset. - devicetable[i]=fdchan; - return i+FREEBSD_FDOFFSET; -} - -// Returns 1 if device not available/open/found else 0. Also shifts fd into valid range. -static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) { - // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1 - *fd -= FREEBSD_FDOFFSET; - - // check for validity of "file descriptor". - if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) { - errno = ENODEV; - return 1; - } - - return 0; -} - -// Like close(). Acts on handles returned by above function. -int deviceclose (int fd) { - struct freebsd_dev_channel *fdchan; - int failed = 0; - - // check for valid file descriptor - if (isnotopen(&fd, &fdchan)) - return -1; - - - // did we allocate a SCSI device name? - if (fdchan->devname) - free(fdchan->devname); - - // close device, if open - if (fdchan->atacommand) - failed=close(fdchan->atacommand); - - if (fdchan->scsicontrol) - failed=close(fdchan->scsicontrol); - - // if close succeeded, then remove from device list - // Eduard, should we also remove it from list if close() fails? I'm - // not sure. Here I only remove it from list if close() worked. - if (!failed) { - free(fdchan); - devicetable[fd]=NULL; - } - - return failed; -} - -#define NO_RETURN 0 -#define BAD_SMART 1 -#define NO_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", - - PACKAGE_STRING " does not currentlly support TWE devices (3ware Escalade)\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. See os_linux.c -int ata_command_interface(int fd, smart_command_set command, int select, char *data) { -#ifndef ATAREQUEST - // sorry, but without ATAng, we can't do anything here - printwarning(BAD_KERNEL,NULL); - errno = ENOSYS; - return -1; -#else - struct freebsd_dev_channel* con; - int retval, copydata=0; - struct ata_cmd iocmd; - unsigned char buff[512]; - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -1; - - bzero(buff,512); - - bzero(&iocmd,sizeof(struct ata_cmd)); - bzero(buff,512); - iocmd.cmd=ATAREQUEST; - iocmd.channel=con->channel; - iocmd.device=con->device; - - iocmd.u.request.u.ata.command=ATA_SMART_CMD; - iocmd.u.request.timeout=600; - switch (command){ - case READ_VALUES: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_VALUES; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case READ_THRESHOLDS: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_THRESHOLDS; - iocmd.u.request.u.ata.count=1; - iocmd.u.request.u.ata.lba=1|(0xc24f<<8); - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case READ_LOG: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR; - iocmd.u.request.u.ata.lba=select|(0xc24f<<8); - iocmd.u.request.u.ata.count=1; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case IDENTIFY: - iocmd.u.request.u.ata.command=ATA_IDENTIFY_DEVICE; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case PIDENTIFY: - iocmd.u.request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case ENABLE: - iocmd.u.request.u.ata.feature=ATA_SMART_ENABLE; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case DISABLE: - iocmd.u.request.u.ata.feature=ATA_SMART_DISABLE; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case AUTO_OFFLINE: - // NOTE: According to ATAPI 4 and UP, this command is obsolete - iocmd.u.request.u.ata.feature=ATA_SMART_AUTO_OFFLINE; - iocmd.u.request.u.ata.lba=select|(0xc24f<<8); - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case AUTOSAVE: - iocmd.u.request.u.ata.feature=ATA_SMART_AUTOSAVE; - iocmd.u.request.u.ata.count=0xf1; // to enable autosave - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case IMMEDIATE_OFFLINE: - iocmd.u.request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE; - iocmd.u.request.u.ata.lba = select|(0xc24f<<8); // put test in sector - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case STATUS_CHECK: // same command, no HDIO in FreeBSD - case STATUS: - // this command only says if SMART is working. It could be - // replaced with STATUS_CHECK below. - iocmd.u.request.u.ata.feature=ATA_SMART_STATUS; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - default: - pout("Unrecognized command %d in ata_command_interface()\n" - "Please contact " PACKAGE_BUGREPORT "\n", command); - errno=ENOSYS; - 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; - - if ((retval=ioctl(con->atacommand, IOCATA, &iocmd))) - return -1; - -#if __FreeBSD_version < 502000 - printwarning(NO_RETURN,NULL); -#endif - - high = (iocmd.u.request.u.ata.lba >> 16) & 0xff; - low = (iocmd.u.request.u.ata.lba >> 8) & 0xff; - - // 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]; - sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", - (int)iocmd.u.request.u.ata.command, - (int)iocmd.u.request.u.ata.feature, - (int)iocmd.u.request.u.ata.count, - (int)((iocmd.u.request.u.ata.lba) & 0xff), - (int)((iocmd.u.request.u.ata.lba>>8) & 0xff), - (int)((iocmd.u.request.u.ata.lba>>16) & 0xff), - (int)iocmd.u.request.error); - printwarning(BAD_SMART,buf); - return 0; - } - - if ((retval=ioctl(con->atacommand, IOCATA, &iocmd))) { - perror("Failed command: "); - return -1; - } - // - if (copydata) - memcpy(data, buff, 512); - - return 0; -#endif -} - - -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) -{ - struct freebsd_dev_channel* con = NULL; - struct cam_device* cam_dev = NULL; - 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("]"); - } - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -ENOTTY; - - - if (!(cam_dev = cam_open_spec_device(con->devname,con->unitnum,O_RDWR,NULL))) { - warnx("%s",cam_errbuf); - return -1; - } - - if (!(ccb = cam_getccb(cam_dev))) { - warnx("error allocating ccb"); - return -ENOMEM; - } - - // 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(cam_dev,ccb) < 0) { - warn("error sending SCSI ccb"); - #if __FreeBSD_version > 500000 - cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); - #endif - cam_freeccb(ccb); - return -1; - } - - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - #if __FreeBSD_version > 500000 - cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); - #endif - cam_freeccb(ccb); - return -1; - } - - if (iop->sensep) { - memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data)); - iop->resp_sense_len = sizeof(struct scsi_sense_data); - } - - iop->scsi_status = ccb->csio.scsi_status; - - cam_freeccb(ccb); - - if (cam_dev) - cam_close_device(cam_dev); - - 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; -} - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c - -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) { - - // to hold true file descriptor - struct freebsd_dev_channel* con; - - // return value and buffer for ioctl() - int ioctlreturn, readdata=0; - - // Used by both the SCSI and char interfaces - char ioctl_buffer[sizeof(struct twe_usercommand)]; - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -1; - - memset(ioctl_buffer, 0, sizeof(struct twe_usercommand)); - - struct twe_usercommand* cmd = (struct twe_usercommand*)ioctl_buffer; - cmd->tu_command.ata.opcode = TWE_OP_ATA_PASSTHROUGH; - - // Same for (almost) all commands - but some reset below - cmd->tu_command.ata.request_id = 0xFF; - cmd->tu_command.ata.unit = disknum; - cmd->tu_command.ata.host_id = 0; - cmd->tu_command.ata.status = 0; - cmd->tu_command.ata.flags = 0x1; - cmd->tu_command.ata.drive_head = 0x0; - cmd->tu_command.ata.sector_num = 0; - - // All SMART commands use this CL/CH signature. These are magic - // values from the ATA specifications. - cmd->tu_command.ata.cylinder_lo = 0x4F; - cmd->tu_command.ata.cylinder_hi = 0xC2; - - // SMART ATA COMMAND REGISTER value - cmd->tu_command.ata.command = ATA_SMART_CMD; - - // 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 - if (command == READ_VALUES || - command == READ_THRESHOLDS || - command == READ_LOG || - command == IDENTIFY || - command == WRITE_LOG ) { - readdata=1; - cmd->tu_size = 512; - cmd->tu_data = data; - cmd->tu_command.ata.sgl_offset = 0x5; - cmd->tu_command.ata.size = 0x5; - cmd->tu_command.ata.param = 0xD; - cmd->tu_command.ata.sector_count = 0x1; - // 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) - // cmd->tu_command.ata.size++; - } - else { - // Non data command -- but doesn't use large sector - // count register values. - cmd->tu_command.ata.sgl_offset = 0x0; - cmd->tu_command.ata.size = 0x5; - cmd->tu_command.ata.param = 0x8; - cmd->tu_command.ata.sector_count = 0x0; - } - - // Now set ATA registers depending upon command - switch (command){ - case CHECK_POWER_MODE: - cmd->tu_command.ata.command = ATA_CHECK_POWER_MODE; - cmd->tu_command.ata.features = 0; - cmd->tu_command.ata.cylinder_lo = 0; - cmd->tu_command.ata.cylinder_hi = 0; - break; - case READ_VALUES: - cmd->tu_command.ata.features = ATA_SMART_READ_VALUES; - break; - case READ_THRESHOLDS: - cmd->tu_command.ata.features = ATA_SMART_READ_THRESHOLDS; - break; - case READ_LOG: - cmd->tu_command.ata.features = ATA_SMART_READ_LOG_SECTOR; - // log number to return - cmd->tu_command.ata.sector_num = select; - break; - case WRITE_LOG: - cmd->tu_data = data; - readdata=0; - cmd->tu_command.ata.features = ATA_SMART_WRITE_LOG_SECTOR; - cmd->tu_command.ata.sector_count = 1; - cmd->tu_command.ata.sector_num = select; - cmd->tu_command.ata.param = 0xF; // PIO data write - break; - case IDENTIFY: - // ATA IDENTIFY DEVICE - cmd->tu_command.ata.command = ATA_IDENTIFY_DEVICE; - cmd->tu_command.ata.features = 0; - cmd->tu_command.ata.cylinder_lo = 0; - cmd->tu_command.ata.cylinder_hi = 0; - break; - case PIDENTIFY: - // 3WARE controller can NOT have packet device internally - pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); - errno=ENODEV; - return -1; - case ENABLE: - cmd->tu_command.ata.features = ATA_SMART_ENABLE; - break; - case DISABLE: - cmd->tu_command.ata.features = ATA_SMART_DISABLE; - break; - case AUTO_OFFLINE: - cmd->tu_command.ata.features = ATA_SMART_AUTO_OFFLINE; - // Enable or disable? - cmd->tu_command.ata.sector_count = select; - break; - case AUTOSAVE: - cmd->tu_command.ata.features = ATA_SMART_AUTOSAVE; - // Enable or disable? - cmd->tu_command.ata.sector_count = select; - break; - case IMMEDIATE_OFFLINE: - cmd->tu_command.ata.features = ATA_SMART_IMMEDIATE_OFFLINE; - // What test type to run? - cmd->tu_command.ata.sector_num = select; - break; - case STATUS_CHECK: - cmd->tu_command.ata.features = ATA_SMART_STATUS; - break; - case STATUS: - // This is JUST to see if SMART is enabled, by giving SMART status - // command. But it doesn't say if status was good, or failing. - // See below for the difference. - cmd->tu_command.ata.features = ATA_SMART_STATUS; - break; - default: - pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); - errno=ENOSYS; - return -1; - } - - // Now send the command down through an ioctl() - ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd); - - // Deal with the different error cases - if (ioctlreturn) { - if (!errno) - errno=EIO; - return -1; - } - - // See if the ATA command failed. Now that we have returned from - // the ioctl() call, if passthru is valid, then: - // - cmd->tu_command.ata.status contains the 3ware controller STATUS - // - cmd->tu_command.ata.command contains the ATA STATUS register - // - cmd->tu_command.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 (cmd->tu_command.ata.status || (cmd->tu_command.ata.command & 0x21)) { - pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",cmd->tu_command.ata.status,cmd->tu_command.ata.command,cmd->tu_command.ata.flags); - errno=EIO; - return -1; - } - - // For STATUS_CHECK, we need to check register values - if (command==STATUS_CHECK) { - - // To find out if the SMART RETURN STATUS is good or failing, we - // need to examine the values of the Cylinder Low and Cylinder - // High Registers. - - unsigned short cyl_lo=cmd->tu_command.ata.cylinder_lo; - unsigned short cyl_hi=cmd->tu_command.ata.cylinder_hi; - - // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. - if (cyl_lo==0x4F && cyl_hi==0xC2) - return 0; - - // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL - if (cyl_lo==0xF4 && cyl_hi==0x2C) - return 1; - - errno=EIO; - return -1; - } - - // copy sector count register (one byte!) to return data - if (command==CHECK_POWER_MODE) - *data=*(char *)&(cmd->tu_command.ata.sector_count); - - // look for nonexistent devices/ports - if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { - errno=ENODEV; - return -1; - } - - return 0; -} - -static int get_twe_channel_unit (const char* name, int* unit, int* dev) { - // at some point, we need to figure out which TWE controller any - // given disk belongs to..... - // at this point, I have no clue how to do this...so for now, it is - // always going to be controller 0 - *dev=0; - *unit=0; // not really needed for TWE drives, as we handle that seperately - return 0; -} - -static int get_ata_channel_unit ( const char* name, int* unit, int* dev) { -#ifndef ATAREQUEST - *dev=0; - *unit=0; -return 0; -#else - // there is no direct correlation between name 'ad0, ad1, ...' and - // channel/unit number. So we need to iterate through the possible - // channels and check each unit to see if we match names - struct ata_cmd iocmd; - int fd,maxunit; - - bzero(&iocmd, sizeof(struct ata_cmd)); - - if ((fd = open("/dev/ata", O_RDWR)) < 0) - return -errno; - - iocmd.cmd = ATAGMAXCHANNEL; - if (ioctl(fd, IOCATA, &iocmd) < 0) { - return -errno; - close(fd); - } - maxunit = iocmd.u.maxchan; - for (*unit = 0; *unit < maxunit; (*unit)++) { - iocmd.channel = *unit; - iocmd.device = -1; - iocmd.cmd = ATAGPARM; - if (ioctl(fd, IOCATA, &iocmd) < 0) { - close(fd); - return -errno; - } - if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) { - *dev = 0; - break; - } - if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) { - *dev = 1; - break; - } - } - close(fd); - if (*unit == maxunit) - return -1; - else - return 0; -#endif -} - - -// Guess device type (ata or scsi) based on device name (FreeBSD -// specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst, -// osst, nosst and sg. -static const char * fbsd_dev_prefix = "/dev/"; -static const char * fbsd_dev_ata_disk_prefix = "ad"; -static const char * fbsd_dev_scsi_disk_plus = "da"; -static const char * fbsd_dev_scsi_tape1 = "sa"; -static const char * fbsd_dev_scsi_tape2 = "nsa"; -static const char * fbsd_dev_scsi_tape3 = "esa"; -static const char * fbsd_dev_twe_disk = "twed"; - -static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) { - int len; - int dev_prefix_len = strlen(fbsd_dev_prefix); - - // if dev_name null, or string length zero - if (!dev_name || !(len = strlen(dev_name))) - return CONTROLLER_UNKNOWN;; - - // Remove the leading /dev/... if it's there - if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) { - if (len <= dev_prefix_len) - // if nothing else in the string, unrecognized - return CONTROLLER_UNKNOWN; - // else advance pointer to following characters - dev_name += dev_prefix_len; - } - // form /dev/ad* or ad* - if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name, - strlen(fbsd_dev_ata_disk_prefix))) { - if (chan != NULL) { - if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { - return CONTROLLER_UNKNOWN; - } - } - return CONTROLLER_ATA; - } - - // form /dev/da* or da* - if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name, - strlen(fbsd_dev_scsi_disk_plus))) - goto handlescsi; - - // form /dev/sa* or sa* - if (!strncmp(fbsd_dev_scsi_tape1, dev_name, - strlen(fbsd_dev_scsi_tape1))) - goto handlescsi; - - // form /dev/nsa* or nsa* - if (!strncmp(fbsd_dev_scsi_tape2, dev_name, - strlen(fbsd_dev_scsi_tape2))) - goto handlescsi; - - // form /dev/esa* or esa* - if (!strncmp(fbsd_dev_scsi_tape3, dev_name, - strlen(fbsd_dev_scsi_tape3))) - goto handlescsi; - - if (!strncmp(fbsd_dev_twe_disk,dev_name, - strlen(fbsd_dev_twe_disk))) { - if (chan != NULL) { - if (get_twe_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { - return CONTROLLER_UNKNOWN; - } - } - return CONTROLLER_3WARE_678K_CHAR; - } - - // we failed to recognize any of the forms - return CONTROLLER_UNKNOWN; - - handlescsi: - if (chan != NULL) { - if (!(chan->devname = calloc(1,DEV_IDLEN+1))) - return CONTROLLER_UNKNOWN; - - if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1) - return CONTROLLER_UNKNOWN; - } - return CONTROLLER_SCSI; - -} - -int guess_device_type (const char* dev_name) { - return parse_ata_chan_dev(dev_name,NULL); -} - -// global variable holding byte count of allocated memory -extern long long bytes; - -// we are going to take advantage of the fact that FreeBSD's devfs will only -// have device entries for devices that exist. So if we get the equivilent of -// ls /dev/ad?, we have all the ATA devices on the system -// -// If any errors occur, leave errno set as it was returned by the -// system call, and return <0. - -// Return values: -// -1 out of memory -// -2 to -5 errors in glob - -int get_dev_names(char*** names, const char* prefix) { - int n = 0; - char** mp; - int retglob,lim; - glob_t globbuf; - int i; - char pattern1[128],pattern2[128]; - - bzero(&globbuf,sizeof(globbuf)); - // in case of non-clean exit - *names=NULL; - - // handle 0-99 possible devices, will still be limited by MAX_NUM_DEV - sprintf(pattern1,"/dev/%s[0-9]",prefix); - sprintf(pattern2,"/dev/%s[0-9][0-9]",prefix); - - // Use glob to look for any directory entries matching the patterns - // first call inits with first pattern match, second call appends - // to first list. Turn on NOCHECK for second call. This results in no - // error if no more matches found, however it does append the actual - // pattern to the list of paths.... - if ((retglob=glob(pattern1, GLOB_ERR, NULL, &globbuf)) || - (retglob=glob(pattern2, GLOB_ERR|GLOB_APPEND|GLOB_NOCHECK,NULL,&globbuf))) { - int retval = -1; - // glob failed - if (retglob==GLOB_NOSPACE) - pout("glob(3) ran out of memory matching patterns (%s),(%s)\n", - pattern1, pattern2); - else if (retglob==GLOB_ABORTED) - pout("glob(3) aborted matching patterns (%s),(%s)\n", - pattern1, pattern2); - else if (retglob==GLOB_NOMATCH) { - pout("glob(3) found no matches for patterns (%s),(%s)\n", - pattern1, pattern2); - retval = 0; - } - else if (retglob) - pout("Unexplained error in glob(3) of patterns (%s),(%s)\n", - pattern1, pattern2); - - // Free memory and return - globfree(&globbuf); - - return retval; - } - - // did we find too many paths? - // did we find too many paths? - lim = globbuf.gl_pathc < MAX_NUM_DEV ? globbuf.gl_pathc : MAX_NUM_DEV; - if (lim < globbuf.gl_pathc) - pout("glob(3) found %d > MAX=%d devices matching patterns (%s),(%s): ignoring %d paths\n", - globbuf.gl_pathc, MAX_NUM_DEV, pattern1,pattern2, - globbuf.gl_pathc-MAX_NUM_DEV); - - // allocate space for up to lim number of ATA devices - if (!(mp = (char **)calloc(lim, sizeof(char*)))){ - pout("Out of memory constructing scan device list\n"); - return -1; - } - - // now step through the list returned by glob. No link checking needed - // in FreeBSD - for (i=0; i<globbuf.gl_pathc; i++){ - // becuase of the NO_CHECK on second call to glob, - // the pattern itself will be added to path list.. - // so ignore any paths that have the ']' from pattern - if (strchr(globbuf.gl_pathv[i],']') == NULL) - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - } - - globfree(&globbuf); - mp = realloc(mp,n*(sizeof(char*))); // shrink to correct size - bytes += (n)*(sizeof(char*)); // and set allocated byte count - *names=mp; - return n; -} - -int make_device_names (char*** devlist, const char* name) { - if (!strcmp(name,"SCSI")) - return get_dev_names(devlist,"da"); - else if (!strcmp(name,"ATA")) - return get_dev_names(devlist,"ad"); - else - return 0; -} diff --git a/sm5/os_freebsd.cpp b/sm5/os_freebsd.cpp deleted file mode 100644 index 1bfc3a1babac2cb63bf91f20f8fc49ec75adda9e..0000000000000000000000000000000000000000 --- a/sm5/os_freebsd.cpp +++ /dev/null @@ -1,938 +0,0 @@ -/* - * os_freebsd.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdio.h> -#include <sys/types.h> -#include <dirent.h> -#include <err.h> -#include <camlib.h> -#include <cam/scsi/scsi_message.h> -#include <sys/ata.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <glob.h> -#include <fcntl.h> - - -#include "config.h" -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" -#include "os_freebsd.h" - -static const char *filenameandversion="$Id: os_freebsd.cpp,v 1.40 2004/08/16 22:44:26 ballen4705 Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.40 2004/08/16 22:44:26 ballen4705 Exp $" \ -ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Private table of open devices: guaranteed zero on startup since -// part of static data. -struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV]; - -// forward declaration -static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *ch); - -// print examples for smartctl -void print_smartctl_examples(){ - printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( - " 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" -// " 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/ad0 (Prints all SMART information)\n" - " smartctl -s on -o on -S on /dev/ad0 (Enables SMART on first disk)\n" - " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n" - " smartctl -A -l selftest -q errorsonly /dev/ad0\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; -} - -// Like open(). Return positive integer handle, used by functions below only. mode=="ATA" or "SCSI". -int deviceopen (const char* dev, char* mode) { - struct freebsd_dev_channel *fdchan; - int parse_ok, i; - - // Search table for a free entry - for (i=0; i<FREEBSD_MAXDEV; i++) - if (!devicetable[i]) - break; - - // If no free entry found, return error. We have max allowed number - // of "file descriptors" already allocated. - if (i==FREEBSD_MAXDEV) { - errno=EMFILE; - return -1; - } - - fdchan = calloc(1,sizeof(struct freebsd_dev_channel)); - if (fdchan == NULL) { - // errno already set by call to malloc() - return -1; - } - - parse_ok = parse_ata_chan_dev (dev,fdchan); - if (parse_ok == CONTROLLER_UNKNOWN) { - free(fdchan); - errno = ENOTTY; - return -1; // can't handle what we don't know - } - - if (parse_ok == CONTROLLER_ATA) { - if ((fdchan->atacommand = open("/dev/ata",O_RDWR))<0) { - int myerror = errno; //preserve across free call - free (fdchan); - errno = myerror; - return -1; - } - } - - if (parse_ok == CONTROLLER_3WARE_678K_CHAR) { - char buf[512]; - sprintf(buf,"/dev/twe%d",fdchan->device); - printf("Using %s, as control device\n", buf); - if ((fdchan->atacommand = open(buf,O_RDWR))<0) { - int myerror = errno; // preserver across free call - free(fdchan); - errno=myerror; - return -1; - } - } - - if (parse_ok == CONTROLLER_SCSI) { - // this is really a NO-OP, as the parse takes care - // of filling in correct details - } - - // return pointer to "file descriptor" table entry, properly offset. - devicetable[i]=fdchan; - return i+FREEBSD_FDOFFSET; -} - -// Returns 1 if device not available/open/found else 0. Also shifts fd into valid range. -static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) { - // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1 - *fd -= FREEBSD_FDOFFSET; - - // check for validity of "file descriptor". - if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) { - errno = ENODEV; - return 1; - } - - return 0; -} - -// Like close(). Acts on handles returned by above function. -int deviceclose (int fd) { - struct freebsd_dev_channel *fdchan; - int failed = 0; - - // check for valid file descriptor - if (isnotopen(&fd, &fdchan)) - return -1; - - - // did we allocate a SCSI device name? - if (fdchan->devname) - free(fdchan->devname); - - // close device, if open - if (fdchan->atacommand) - failed=close(fdchan->atacommand); - - if (fdchan->scsicontrol) - failed=close(fdchan->scsicontrol); - - // if close succeeded, then remove from device list - // Eduard, should we also remove it from list if close() fails? I'm - // not sure. Here I only remove it from list if close() worked. - if (!failed) { - free(fdchan); - devicetable[fd]=NULL; - } - - return failed; -} - -#define NO_RETURN 0 -#define BAD_SMART 1 -#define NO_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", - - PACKAGE_STRING " does not currentlly support TWE devices (3ware Escalade)\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. See os_linux.c -int ata_command_interface(int fd, smart_command_set command, int select, char *data) { -#ifndef ATAREQUEST - // sorry, but without ATAng, we can't do anything here - printwarning(BAD_KERNEL,NULL); - errno = ENOSYS; - return -1; -#else - struct freebsd_dev_channel* con; - int retval, copydata=0; - struct ata_cmd iocmd; - unsigned char buff[512]; - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -1; - - bzero(buff,512); - - bzero(&iocmd,sizeof(struct ata_cmd)); - bzero(buff,512); - iocmd.cmd=ATAREQUEST; - iocmd.channel=con->channel; - iocmd.device=con->device; - - iocmd.u.request.u.ata.command=ATA_SMART_CMD; - iocmd.u.request.timeout=600; - switch (command){ - case READ_VALUES: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_VALUES; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case READ_THRESHOLDS: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_THRESHOLDS; - iocmd.u.request.u.ata.count=1; - iocmd.u.request.u.ata.lba=1|(0xc24f<<8); - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case READ_LOG: - iocmd.u.request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR; - iocmd.u.request.u.ata.lba=select|(0xc24f<<8); - iocmd.u.request.u.ata.count=1; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case IDENTIFY: - iocmd.u.request.u.ata.command=ATA_IDENTIFY_DEVICE; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case PIDENTIFY: - iocmd.u.request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE; - iocmd.u.request.flags=ATA_CMD_READ; - iocmd.u.request.data=buff; - iocmd.u.request.count=512; - copydata=1; - break; - case ENABLE: - iocmd.u.request.u.ata.feature=ATA_SMART_ENABLE; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case DISABLE: - iocmd.u.request.u.ata.feature=ATA_SMART_DISABLE; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case AUTO_OFFLINE: - // NOTE: According to ATAPI 4 and UP, this command is obsolete - iocmd.u.request.u.ata.feature=ATA_SMART_AUTO_OFFLINE; - iocmd.u.request.u.ata.lba=select|(0xc24f<<8); - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case AUTOSAVE: - iocmd.u.request.u.ata.feature=ATA_SMART_AUTOSAVE; - iocmd.u.request.u.ata.count=0xf1; // to enable autosave - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case IMMEDIATE_OFFLINE: - iocmd.u.request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE; - iocmd.u.request.u.ata.lba = select|(0xc24f<<8); // put test in sector - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - case STATUS_CHECK: // same command, no HDIO in FreeBSD - case STATUS: - // this command only says if SMART is working. It could be - // replaced with STATUS_CHECK below. - iocmd.u.request.u.ata.feature=ATA_SMART_STATUS; - iocmd.u.request.u.ata.lba=0xc24f<<8; - iocmd.u.request.flags=ATA_CMD_CONTROL; - break; - default: - pout("Unrecognized command %d in ata_command_interface()\n" - "Please contact " PACKAGE_BUGREPORT "\n", command); - errno=ENOSYS; - 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; - - if ((retval=ioctl(con->atacommand, IOCATA, &iocmd))) - return -1; - -#if __FreeBSD_version < 502000 - printwarning(NO_RETURN,NULL); -#endif - - high = (iocmd.u.request.u.ata.lba >> 16) & 0xff; - low = (iocmd.u.request.u.ata.lba >> 8) & 0xff; - - // 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]; - sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", - (int)iocmd.u.request.u.ata.command, - (int)iocmd.u.request.u.ata.feature, - (int)iocmd.u.request.u.ata.count, - (int)((iocmd.u.request.u.ata.lba) & 0xff), - (int)((iocmd.u.request.u.ata.lba>>8) & 0xff), - (int)((iocmd.u.request.u.ata.lba>>16) & 0xff), - (int)iocmd.u.request.error); - printwarning(BAD_SMART,buf); - return 0; - } - - if ((retval=ioctl(con->atacommand, IOCATA, &iocmd))) { - perror("Failed command: "); - return -1; - } - // - if (copydata) - memcpy(data, buff, 512); - - return 0; -#endif -} - - -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) -{ - struct freebsd_dev_channel* con = NULL; - struct cam_device* cam_dev = NULL; - 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("]"); - } - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -ENOTTY; - - - if (!(cam_dev = cam_open_spec_device(con->devname,con->unitnum,O_RDWR,NULL))) { - warnx("%s",cam_errbuf); - return -1; - } - - if (!(ccb = cam_getccb(cam_dev))) { - warnx("error allocating ccb"); - return -ENOMEM; - } - - // 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(cam_dev,ccb) < 0) { - warn("error sending SCSI ccb"); - #if __FreeBSD_version > 500000 - cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); - #endif - cam_freeccb(ccb); - return -1; - } - - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - #if __FreeBSD_version > 500000 - cam_error_print(cam_dev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); - #endif - cam_freeccb(ccb); - return -1; - } - - if (iop->sensep) { - memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data)); - iop->resp_sense_len = sizeof(struct scsi_sense_data); - } - - iop->scsi_status = ccb->csio.scsi_status; - - cam_freeccb(ccb); - - if (cam_dev) - cam_close_device(cam_dev); - - 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; -} - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c - -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) { - - // to hold true file descriptor - struct freebsd_dev_channel* con; - - // return value and buffer for ioctl() - int ioctlreturn, readdata=0; - - // Used by both the SCSI and char interfaces - char ioctl_buffer[sizeof(struct twe_usercommand)]; - - // check that "file descriptor" is valid - if (isnotopen(&fd,&con)) - return -1; - - memset(ioctl_buffer, 0, sizeof(struct twe_usercommand)); - - struct twe_usercommand* cmd = (struct twe_usercommand*)ioctl_buffer; - cmd->tu_command.ata.opcode = TWE_OP_ATA_PASSTHROUGH; - - // Same for (almost) all commands - but some reset below - cmd->tu_command.ata.request_id = 0xFF; - cmd->tu_command.ata.unit = disknum; - cmd->tu_command.ata.host_id = 0; - cmd->tu_command.ata.status = 0; - cmd->tu_command.ata.flags = 0x1; - cmd->tu_command.ata.drive_head = 0x0; - cmd->tu_command.ata.sector_num = 0; - - // All SMART commands use this CL/CH signature. These are magic - // values from the ATA specifications. - cmd->tu_command.ata.cylinder_lo = 0x4F; - cmd->tu_command.ata.cylinder_hi = 0xC2; - - // SMART ATA COMMAND REGISTER value - cmd->tu_command.ata.command = ATA_SMART_CMD; - - // 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 - if (command == READ_VALUES || - command == READ_THRESHOLDS || - command == READ_LOG || - command == IDENTIFY || - command == WRITE_LOG ) { - readdata=1; - cmd->tu_size = 512; - cmd->tu_data = data; - cmd->tu_command.ata.sgl_offset = 0x5; - cmd->tu_command.ata.size = 0x5; - cmd->tu_command.ata.param = 0xD; - cmd->tu_command.ata.sector_count = 0x1; - // 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) - // cmd->tu_command.ata.size++; - } - else { - // Non data command -- but doesn't use large sector - // count register values. - cmd->tu_command.ata.sgl_offset = 0x0; - cmd->tu_command.ata.size = 0x5; - cmd->tu_command.ata.param = 0x8; - cmd->tu_command.ata.sector_count = 0x0; - } - - // Now set ATA registers depending upon command - switch (command){ - case CHECK_POWER_MODE: - cmd->tu_command.ata.command = ATA_CHECK_POWER_MODE; - cmd->tu_command.ata.features = 0; - cmd->tu_command.ata.cylinder_lo = 0; - cmd->tu_command.ata.cylinder_hi = 0; - break; - case READ_VALUES: - cmd->tu_command.ata.features = ATA_SMART_READ_VALUES; - break; - case READ_THRESHOLDS: - cmd->tu_command.ata.features = ATA_SMART_READ_THRESHOLDS; - break; - case READ_LOG: - cmd->tu_command.ata.features = ATA_SMART_READ_LOG_SECTOR; - // log number to return - cmd->tu_command.ata.sector_num = select; - break; - case WRITE_LOG: - cmd->tu_data = data; - readdata=0; - cmd->tu_command.ata.features = ATA_SMART_WRITE_LOG_SECTOR; - cmd->tu_command.ata.sector_count = 1; - cmd->tu_command.ata.sector_num = select; - cmd->tu_command.ata.param = 0xF; // PIO data write - break; - case IDENTIFY: - // ATA IDENTIFY DEVICE - cmd->tu_command.ata.command = ATA_IDENTIFY_DEVICE; - cmd->tu_command.ata.features = 0; - cmd->tu_command.ata.cylinder_lo = 0; - cmd->tu_command.ata.cylinder_hi = 0; - break; - case PIDENTIFY: - // 3WARE controller can NOT have packet device internally - pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); - errno=ENODEV; - return -1; - case ENABLE: - cmd->tu_command.ata.features = ATA_SMART_ENABLE; - break; - case DISABLE: - cmd->tu_command.ata.features = ATA_SMART_DISABLE; - break; - case AUTO_OFFLINE: - cmd->tu_command.ata.features = ATA_SMART_AUTO_OFFLINE; - // Enable or disable? - cmd->tu_command.ata.sector_count = select; - break; - case AUTOSAVE: - cmd->tu_command.ata.features = ATA_SMART_AUTOSAVE; - // Enable or disable? - cmd->tu_command.ata.sector_count = select; - break; - case IMMEDIATE_OFFLINE: - cmd->tu_command.ata.features = ATA_SMART_IMMEDIATE_OFFLINE; - // What test type to run? - cmd->tu_command.ata.sector_num = select; - break; - case STATUS_CHECK: - cmd->tu_command.ata.features = ATA_SMART_STATUS; - break; - case STATUS: - // This is JUST to see if SMART is enabled, by giving SMART status - // command. But it doesn't say if status was good, or failing. - // See below for the difference. - cmd->tu_command.ata.features = ATA_SMART_STATUS; - break; - default: - pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); - errno=ENOSYS; - return -1; - } - - // Now send the command down through an ioctl() - ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd); - - // Deal with the different error cases - if (ioctlreturn) { - if (!errno) - errno=EIO; - return -1; - } - - // See if the ATA command failed. Now that we have returned from - // the ioctl() call, if passthru is valid, then: - // - cmd->tu_command.ata.status contains the 3ware controller STATUS - // - cmd->tu_command.ata.command contains the ATA STATUS register - // - cmd->tu_command.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 (cmd->tu_command.ata.status || (cmd->tu_command.ata.command & 0x21)) { - pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",cmd->tu_command.ata.status,cmd->tu_command.ata.command,cmd->tu_command.ata.flags); - errno=EIO; - return -1; - } - - // For STATUS_CHECK, we need to check register values - if (command==STATUS_CHECK) { - - // To find out if the SMART RETURN STATUS is good or failing, we - // need to examine the values of the Cylinder Low and Cylinder - // High Registers. - - unsigned short cyl_lo=cmd->tu_command.ata.cylinder_lo; - unsigned short cyl_hi=cmd->tu_command.ata.cylinder_hi; - - // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. - if (cyl_lo==0x4F && cyl_hi==0xC2) - return 0; - - // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL - if (cyl_lo==0xF4 && cyl_hi==0x2C) - return 1; - - errno=EIO; - return -1; - } - - // copy sector count register (one byte!) to return data - if (command==CHECK_POWER_MODE) - *data=*(char *)&(cmd->tu_command.ata.sector_count); - - // look for nonexistent devices/ports - if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { - errno=ENODEV; - return -1; - } - - return 0; -} - -static int get_twe_channel_unit (const char* name, int* unit, int* dev) { - // at some point, we need to figure out which TWE controller any - // given disk belongs to..... - // at this point, I have no clue how to do this...so for now, it is - // always going to be controller 0 - *dev=0; - *unit=0; // not really needed for TWE drives, as we handle that seperately - return 0; -} - -static int get_ata_channel_unit ( const char* name, int* unit, int* dev) { -#ifndef ATAREQUEST - *dev=0; - *unit=0; -return 0; -#else - // there is no direct correlation between name 'ad0, ad1, ...' and - // channel/unit number. So we need to iterate through the possible - // channels and check each unit to see if we match names - struct ata_cmd iocmd; - int fd,maxunit; - - bzero(&iocmd, sizeof(struct ata_cmd)); - - if ((fd = open("/dev/ata", O_RDWR)) < 0) - return -errno; - - iocmd.cmd = ATAGMAXCHANNEL; - if (ioctl(fd, IOCATA, &iocmd) < 0) { - return -errno; - close(fd); - } - maxunit = iocmd.u.maxchan; - for (*unit = 0; *unit < maxunit; (*unit)++) { - iocmd.channel = *unit; - iocmd.device = -1; - iocmd.cmd = ATAGPARM; - if (ioctl(fd, IOCATA, &iocmd) < 0) { - close(fd); - return -errno; - } - if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) { - *dev = 0; - break; - } - if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) { - *dev = 1; - break; - } - } - close(fd); - if (*unit == maxunit) - return -1; - else - return 0; -#endif -} - - -// Guess device type (ata or scsi) based on device name (FreeBSD -// specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst, -// osst, nosst and sg. -static const char * fbsd_dev_prefix = "/dev/"; -static const char * fbsd_dev_ata_disk_prefix = "ad"; -static const char * fbsd_dev_scsi_disk_plus = "da"; -static const char * fbsd_dev_scsi_tape1 = "sa"; -static const char * fbsd_dev_scsi_tape2 = "nsa"; -static const char * fbsd_dev_scsi_tape3 = "esa"; -static const char * fbsd_dev_twe_disk = "twed"; - -static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) { - int len; - int dev_prefix_len = strlen(fbsd_dev_prefix); - - // if dev_name null, or string length zero - if (!dev_name || !(len = strlen(dev_name))) - return CONTROLLER_UNKNOWN;; - - // Remove the leading /dev/... if it's there - if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) { - if (len <= dev_prefix_len) - // if nothing else in the string, unrecognized - return CONTROLLER_UNKNOWN; - // else advance pointer to following characters - dev_name += dev_prefix_len; - } - // form /dev/ad* or ad* - if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name, - strlen(fbsd_dev_ata_disk_prefix))) { - if (chan != NULL) { - if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { - return CONTROLLER_UNKNOWN; - } - } - return CONTROLLER_ATA; - } - - // form /dev/da* or da* - if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name, - strlen(fbsd_dev_scsi_disk_plus))) - goto handlescsi; - - // form /dev/sa* or sa* - if (!strncmp(fbsd_dev_scsi_tape1, dev_name, - strlen(fbsd_dev_scsi_tape1))) - goto handlescsi; - - // form /dev/nsa* or nsa* - if (!strncmp(fbsd_dev_scsi_tape2, dev_name, - strlen(fbsd_dev_scsi_tape2))) - goto handlescsi; - - // form /dev/esa* or esa* - if (!strncmp(fbsd_dev_scsi_tape3, dev_name, - strlen(fbsd_dev_scsi_tape3))) - goto handlescsi; - - if (!strncmp(fbsd_dev_twe_disk,dev_name, - strlen(fbsd_dev_twe_disk))) { - if (chan != NULL) { - if (get_twe_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) { - return CONTROLLER_UNKNOWN; - } - } - return CONTROLLER_3WARE_678K_CHAR; - } - - // we failed to recognize any of the forms - return CONTROLLER_UNKNOWN; - - handlescsi: - if (chan != NULL) { - if (!(chan->devname = calloc(1,DEV_IDLEN+1))) - return CONTROLLER_UNKNOWN; - - if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1) - return CONTROLLER_UNKNOWN; - } - return CONTROLLER_SCSI; - -} - -int guess_device_type (const char* dev_name) { - return parse_ata_chan_dev(dev_name,NULL); -} - -// global variable holding byte count of allocated memory -extern long long bytes; - -// we are going to take advantage of the fact that FreeBSD's devfs will only -// have device entries for devices that exist. So if we get the equivilent of -// ls /dev/ad?, we have all the ATA devices on the system -// -// If any errors occur, leave errno set as it was returned by the -// system call, and return <0. - -// Return values: -// -1 out of memory -// -2 to -5 errors in glob - -int get_dev_names(char*** names, const char* prefix) { - int n = 0; - char** mp; - int retglob,lim; - glob_t globbuf; - int i; - char pattern1[128],pattern2[128]; - - bzero(&globbuf,sizeof(globbuf)); - // in case of non-clean exit - *names=NULL; - - // handle 0-99 possible devices, will still be limited by MAX_NUM_DEV - sprintf(pattern1,"/dev/%s[0-9]",prefix); - sprintf(pattern2,"/dev/%s[0-9][0-9]",prefix); - - // Use glob to look for any directory entries matching the patterns - // first call inits with first pattern match, second call appends - // to first list. Turn on NOCHECK for second call. This results in no - // error if no more matches found, however it does append the actual - // pattern to the list of paths.... - if ((retglob=glob(pattern1, GLOB_ERR, NULL, &globbuf)) || - (retglob=glob(pattern2, GLOB_ERR|GLOB_APPEND|GLOB_NOCHECK,NULL,&globbuf))) { - int retval = -1; - // glob failed - if (retglob==GLOB_NOSPACE) - pout("glob(3) ran out of memory matching patterns (%s),(%s)\n", - pattern1, pattern2); - else if (retglob==GLOB_ABORTED) - pout("glob(3) aborted matching patterns (%s),(%s)\n", - pattern1, pattern2); - else if (retglob==GLOB_NOMATCH) { - pout("glob(3) found no matches for patterns (%s),(%s)\n", - pattern1, pattern2); - retval = 0; - } - else if (retglob) - pout("Unexplained error in glob(3) of patterns (%s),(%s)\n", - pattern1, pattern2); - - // Free memory and return - globfree(&globbuf); - - return retval; - } - - // did we find too many paths? - // did we find too many paths? - lim = globbuf.gl_pathc < MAX_NUM_DEV ? globbuf.gl_pathc : MAX_NUM_DEV; - if (lim < globbuf.gl_pathc) - pout("glob(3) found %d > MAX=%d devices matching patterns (%s),(%s): ignoring %d paths\n", - globbuf.gl_pathc, MAX_NUM_DEV, pattern1,pattern2, - globbuf.gl_pathc-MAX_NUM_DEV); - - // allocate space for up to lim number of ATA devices - if (!(mp = (char **)calloc(lim, sizeof(char*)))){ - pout("Out of memory constructing scan device list\n"); - return -1; - } - - // now step through the list returned by glob. No link checking needed - // in FreeBSD - for (i=0; i<globbuf.gl_pathc; i++){ - // becuase of the NO_CHECK on second call to glob, - // the pattern itself will be added to path list.. - // so ignore any paths that have the ']' from pattern - if (strchr(globbuf.gl_pathv[i],']') == NULL) - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - } - - globfree(&globbuf); - mp = realloc(mp,n*(sizeof(char*))); // shrink to correct size - bytes += (n)*(sizeof(char*)); // and set allocated byte count - *names=mp; - return n; -} - -int make_device_names (char*** devlist, const char* name) { - if (!strcmp(name,"SCSI")) - return get_dev_names(devlist,"da"); - else if (!strcmp(name,"ATA")) - return get_dev_names(devlist,"ad"); - else - return 0; -} diff --git a/sm5/os_freebsd.h b/sm5/os_freebsd.h deleted file mode 100644 index 87d3039302e6c0b2b19be3d2cac4892f12ff811d..0000000000000000000000000000000000000000 --- a/sm5/os_freebsd.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * os_freebsd.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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_FREEBSD_H_ -#define OS_FREEBSD_H_ - -#define OS_XXXX_H_CVSID "$Id: os_freebsd.h,v 1.12 2004/08/16 22:44:26 ballen4705 Exp $\n" - -struct freebsd_dev_channel { - int channel; // the ATA channel to work with - int device; // the device on the channel - int atacommand; // the ATA Command file descriptor (/dev/ata) - char* devname; // the SCSI device name - int unitnum; // the SCSI unit number - int scsicontrol; // the SCSI control interface -}; - -#define FREEBSD_MAXDEV 64 -#define FREEBSD_FDOFFSET 16; -#define MAX_NUM_DEV 26 - -#ifdef HAVE_SYS_TWEREG_H -#include <twereg.h> -#else -#include "twereg.h" -#endif - -#ifdef HAVE_SYS_TWEIO_H -#include <tweio.h> -#else -#include "tweio.h" -#endif - -/* - 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? -*/ - - -#endif /* OS_FREEBSD_H_ */ diff --git a/sm5/os_generic.c b/sm5/os_generic.c deleted file mode 100644 index 0101f3bdfb6e1af445bba9232b2d29a1abef0d2c..0000000000000000000000000000000000000000 --- a/sm5/os_generic.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * os_generic.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* 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.[hc] called os_myOS.[hc]. - - [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] 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. -*/ - -// These are needed to define prototypes for the functions defined below -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" - -// This is to include whatever prototypes you define in os_generic.h -#include "os_generic.h" - -// Needed by '-V' option (CVS versioning) of smartd/smartctl -const char *os_XXXX_c_cvsid="$Id: os_generic.c,v 1.15 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - - -// 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" -#ifdef HAVE_UNAME -#include <sys/utsname.h> -#endif - -static void unsupported(){ - static int warninggiven; - - if (!warninggiven) { - char *osname; - extern unsigned char debugmode; - unsigned char savedebugmode=debugmode; - -#ifdef HAVE_UNAME - struct utsname ostype; - uname(&ostype); - osname=ostype.sysname; -#else - osname="host's"; -#endif - - debugmode=1; - pout("\n" - "############################################################################\n" - "WARNING: smartmontools has not been ported to the %s Operating System.\n" - "Please see the files os_generic.c and os_generic.h for porting instructions.\n" - "############################################################################\n\n", - osname); - debugmode=savedebugmode; - 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/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; -} - -// tries to guess device type given the name (a path). See utility.h -// for return values. -int guess_device_type (const char* dev_name) { - unsupported(); - 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(); - 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.c 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){ - unsupported(); - return -1; -} - -// Like close(). Acts only on integer handles returned by -// deviceopen() above. -int deviceclose(int fd){ - unsupported(); - return 0; -} - -// Interface to ATA devices. See os_linux.c 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){ - unsupported(); - return -1; -} - -// Interface to ATA devices behind 3ware escalade RAID controller -// cards. Same description as ata_command_interface() above except -// that 0 <= disknum <= 15 specifies the ATA disk attached to the -// controller. -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - unsupported(); - return -1; -} - -#include <errno.h> -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { - unsupported(); - return -ENOSYS; -} diff --git a/sm5/os_generic.cpp b/sm5/os_generic.cpp deleted file mode 100644 index 56d5858f7901a24383889cf36d9db438c0b528ad..0000000000000000000000000000000000000000 --- a/sm5/os_generic.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * os_generic.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* 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.[hc] called os_myOS.[hc]. - - [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] 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. -*/ - -// These are needed to define prototypes for the functions defined below -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" - -// This is to include whatever prototypes you define in os_generic.h -#include "os_generic.h" - -// Needed by '-V' option (CVS versioning) of smartd/smartctl -const char *os_XXXX_c_cvsid="$Id: os_generic.cpp,v 1.15 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - - -// 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" -#ifdef HAVE_UNAME -#include <sys/utsname.h> -#endif - -static void unsupported(){ - static int warninggiven; - - if (!warninggiven) { - char *osname; - extern unsigned char debugmode; - unsigned char savedebugmode=debugmode; - -#ifdef HAVE_UNAME - struct utsname ostype; - uname(&ostype); - osname=ostype.sysname; -#else - osname="host's"; -#endif - - debugmode=1; - pout("\n" - "############################################################################\n" - "WARNING: smartmontools has not been ported to the %s Operating System.\n" - "Please see the files os_generic.c and os_generic.h for porting instructions.\n" - "############################################################################\n\n", - osname); - debugmode=savedebugmode; - 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/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; -} - -// tries to guess device type given the name (a path). See utility.h -// for return values. -int guess_device_type (const char* dev_name) { - unsupported(); - 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(); - 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.c 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){ - unsupported(); - return -1; -} - -// Like close(). Acts only on integer handles returned by -// deviceopen() above. -int deviceclose(int fd){ - unsupported(); - return 0; -} - -// Interface to ATA devices. See os_linux.c 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){ - unsupported(); - return -1; -} - -// Interface to ATA devices behind 3ware escalade RAID controller -// cards. Same description as ata_command_interface() above except -// that 0 <= disknum <= 15 specifies the ATA disk attached to the -// controller. -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - unsupported(); - return -1; -} - -#include <errno.h> -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { - unsupported(); - return -ENOSYS; -} diff --git a/sm5/os_generic.h b/sm5/os_generic.h deleted file mode 100644 index ed5415c3c513102a6c57a26f3ee1a90ed7e92b89..0000000000000000000000000000000000000000 --- a/sm5/os_generic.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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-4 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., 675 Mass Ave, Cambridge, MA 02139, 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_GENERIC_H_ -#define OS_GENERIC_H_ - -#define OS_XXXX_H_CVSID "$Id: os_generic.h,v 1.3 2004/01/02 16:05:25 ballen4705 Exp $\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_ */ diff --git a/sm5/os_linux.c b/sm5/os_linux.c deleted file mode 100644 index 28dbfd0ff875cb9cea27d020d77ef41c489dbaab..0000000000000000000000000000000000000000 --- a/sm5/os_linux.c +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * os_linux.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2003-4 Doug Gilbert <dougg@torque.net> - * - * 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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 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 <errno.h> -#include <fcntl.h> -#include <glob.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 <unistd.h> -#ifndef makedev // old versions of types.h do not include sysmacros.h -#include <sys/sysmacros.h> -#endif - -#include "atacmds.h" -#include "os_linux.h" -#include "scsicmds.h" -#include "utility.h" - -#ifndef ENOTSUP -#define ENOTSUP ENOSYS -#endif -typedef unsigned long long u8; - -#define ARGUSED(x) ((void)(x)) - -static const char *filenameandversion="$Id: os_linux.c,v 1.70 2004/08/16 22:44:26 ballen4705 Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_linux.c,v 1.70 2004/08/16 22:44:26 ballen4705 Exp $" \ -ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// global variable holding byte count of allocated memory -extern long long bytes; - - - -/* 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 -int setup_3ware_nodes(char *nodename, 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; - - /* 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; - } - - /* Now check if nodes are correct */ - for (index=0; index<16; index++) { - sprintf(nodestring, "/dev/%s%d", nodename, index); - - /* Try to stat the node */ - if ((stat(nodestring, &stat_buf))) { - /* 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"); - return 3; - } - } - - /* 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))) { - - /* Delete the old node */ - if (unlink(nodestring)) { - pout("problem unlinking stale 3ware device node %s", nodestring); - syserror("unlink"); - return 4; - } - - /* Make a new node */ - if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { - pout("problem creating 3ware device nodes %s", nodestring); - syserror("mknod"); - return 5; - } - } - } - return 0; -} - -// equivalent to open(path, flags) -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_RDONLY | O_NONBLOCK); - else if (!strcmp(type,"ATA_3WARE_9000")) { - // the device nodes for this controller are dynamically assigned, - // so we need to check that they exist with the correct major - // numbers and if not, create them - if (setup_3ware_nodes("twa", "3w-9xxx")) { - if (!errno) - errno=ENXIO; - return -1; - } - return open(pathname, O_RDONLY | O_NONBLOCK); - } - else if (!strcmp(type,"ATA_3WARE_678K")) { - // the device nodes for this controller are dynamically assigned, - // so we need to check that they exist with the correct major - // numbers and if not, create them - if (setup_3ware_nodes("twe", "3w-xxxx")) { - if (!errno) - errno=ENXIO; - return -1; - } - return open(pathname, O_RDONLY | O_NONBLOCK); - } - else - return -1; -} - -// equivalent to close(file descriptor) -int deviceclose(int fd){ - return close(fd); -} - -// print examples for smartctl -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; -} - - -// 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 -// -// If any errors occur, leave errno set as it was returned by the -// system call, and return <0. -int get_dev_names(char*** names, const char* pattern, const char* name, int max) { - int n = 0, retglob, i, lim; - char** mp; - glob_t globbuf; - - memset(&globbuf, 0, sizeof(globbuf)); - - // in case of non-clean exit - *names=NULL; - - // Use glob to look for any directory entries matching the pattern - if ((retglob=glob(pattern, GLOB_ERR, NULL, &globbuf))) { - - // glob failed: free memory and return - globfree(&globbuf); - - if (retglob==GLOB_NOMATCH){ - pout("glob(3) found no matches for pattern %s\n", pattern); - return 0; - } - - if (retglob==GLOB_NOSPACE) - pout("glob(3) ran out of memory matching pattern %s\n", pattern); -#ifdef GLOB_ABORTED // missing in old versions of glob.h - else if (retglob==GLOB_ABORTED) - pout("glob(3) aborted matching pattern %s\n", pattern); -#endif - else - pout("Unexplained error in glob(3) of pattern %s\n", pattern); - - return -1; - } - - // did we find too many paths? - lim = ((int)globbuf.gl_pathc < max) ? (int)globbuf.gl_pathc : max; - if (lim < (int)globbuf.gl_pathc) - pout("glob(3) found %d > MAX=%d devices matching pattern %s: ignoring %d paths\n", - (int)globbuf.gl_pathc, max, pattern, (int)(globbuf.gl_pathc-max)); - - // allocate space for up to lim number of ATA devices - if (!(mp = (char **)calloc(lim, sizeof(char*)))){ - pout("Out of memory constructing scan device list\n"); - return -1; - } - - // 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 (i=0; i<lim; i++){ - int retlink; - - // prepare a buffer for storing the link - char linkbuf[1024]; - - // see if path is a link - retlink=readlink(globbuf.gl_pathv[i], linkbuf, 1023); - - // if not a link (or a strange link), keep it - if (retlink<=0 || retlink>1023) - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - else { - // or if it's a link that points to a disc, follow it - char *p; - linkbuf[retlink]='\0'; - 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. - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - 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. - char tmpname[1024]={0}; - char *type=strcmp(name,"ATA")?"scsi":"ide"; - if (strstr(linkbuf, type)){ - snprintf(tmpname, 1024, "%s/disc", globbuf.gl_pathv[i]); - mp[n++] = CustomStrDup(tmpname, 1, __LINE__, filenameandversion); - } - } - } - } - - // free memory, track memory usage - globfree(&globbuf); - mp = realloc(mp,n*(sizeof(char*))); - bytes += n*(sizeof(char*)); - - // and set up return values - *names=mp; - return n; -} - -// makes a list of device names to scan, for either ATA or SCSI -// devices. Return -1 if no memory remaining, else the number of -// devices on the list, which can be >=0. -int make_device_names (char*** devlist, const char* name) { - int retval, maxdev; - -#if 0 - // for testing case where no device names are found - return 0; -#endif - - if (!strcmp(name,"SCSI")) - retval=get_dev_names(devlist,"/dev/sd[a-z]", name, maxdev=26); - else if (!strcmp(name,"ATA")) - retval=get_dev_names(devlist,"/dev/hd[a-t]", name, maxdev=20); - else - // don't recognize disk type! - return 0; - - // if we found traditional links, we are done - if (retval>0) - return retval; - - // else look for devfs entries without traditional links - return get_dev_names(devlist,"/dev/discs/disc*", name, maxdev); -} - - -// 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" - - -// 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); - - 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: - 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; - } - - // 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(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; - } - - // There are two different types of ioctls(). The HDIO_DRIVE_TASK - // one is this: - if (command==STATUS_CHECK){ - 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(device, 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("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 - // 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(device, 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(device, 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_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); -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) -{ -#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(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) - pout(" SG_IO ioctl failed, errno=%d [%s]\n", errno, - strerror(errno)); - return -errno; - } - if (report > 0) { - pout(" scsi_status=0x%x, host_status=0x%x, driver_status=0x%x\n" - " info=0x%x duration=%d milliseconds\n", io_hdr.status, - io_hdr.host_status, io_hdr.driver_status, io_hdr.info, - io_hdr.duration); - if (report > 1) { - if (DXFER_FROM_DEVICE == iop->dxfer_dir) { - 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); - } - } - } - iop->resid = io_hdr.resid; - iop->scsi_status = io_hdr.status; - - 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 - return -EIO; /* catch all */ - } - if (0 != masked_driver_status) { - if (LSCSI_DRIVER_TIMEOUT == masked_driver_status) - return -ETIMEDOUT; - else - return -EIO; /* catch all */ - } - if (LSCSI_DRIVER_SENSE == (io_hdr.driver_status & 0xf)) - 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) { - 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(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 */ -int do_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, 0))) { - 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); - 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 - - -// prototype -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) ) - -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - - // return value and buffer for ioctl() - int ioctlreturn, readdata=0; - - // 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); - - if (escalade_type==CONTROLLER_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 (escalade_type==CONTROLLER_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 (escalade_type==CONTROLLER_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 { - pout("Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum); - errno=ENOSYS; - return -1; - } - - // Same for (almost) all commands - but some reset below - passthru->byte0.opcode = TW_OP_ATA_PASSTHRU; - passthru->request_id = 0xFF; - passthru->byte3.aport = disknum; - passthru->byte3.host_id = 0; - passthru->status = 0; - passthru->flags = 0x1; - passthru->drive_head = 0x0; - passthru->sector_num = 0; - - // All SMART commands use this CL/CH signature. These are magic - // values from the ATA specifications. - passthru->cylinder_lo = 0x4F; - passthru->cylinder_hi = 0xC2; - - // SMART ATA COMMAND REGISTER value - passthru->command = ATA_SMART_CMD; - - // 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 - if (command == READ_VALUES || - command == READ_THRESHOLDS || - command == READ_LOG || - command == IDENTIFY || - command == WRITE_LOG ) { - readdata=1; - passthru->byte0.sgloff = 0x5; - passthru->size = 0x7; - passthru->param = 0xD; - passthru->sector_count = 0x1; - // 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 (escalade_type==CONTROLLER_3WARE_9000_CHAR && sizeof(long)==8) - passthru->size++; - } - else { - // 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; - } - - // Now set ATA registers depending upon command - switch (command){ - case CHECK_POWER_MODE: - passthru->command = ATA_CHECK_POWER_MODE; - passthru->features = 0; - passthru->cylinder_lo = 0; - passthru->cylinder_hi = 0; - break; - case READ_VALUES: - passthru->features = ATA_SMART_READ_VALUES; - break; - case READ_THRESHOLDS: - passthru->features = ATA_SMART_READ_THRESHOLDS; - break; - case READ_LOG: - passthru->features = ATA_SMART_READ_LOG_SECTOR; - // log number to return - passthru->sector_num = select; - break; - case WRITE_LOG: - if (escalade_type == CONTROLLER_3WARE_9000_CHAR) - memcpy((unsigned char *)tw_ioctl_apache->data_buffer, data, 512); - else if (escalade_type == CONTROLLER_3WARE_678K_CHAR) - memcpy((unsigned char *)tw_ioctl_char->data_buffer, data, 512); - else { - // COMMAND NOT SUPPORTED VIA SCSI IOCTL INTERFACE - // memcpy(tw_output->output_data, data, 512); - printwarning(command); - errno=ENOTSUP; - return -1; - } - readdata=0; - passthru->features = ATA_SMART_WRITE_LOG_SECTOR; - passthru->sector_count = 1; - passthru->sector_num = select; - passthru->param = 0xF; // PIO data write - break; - case IDENTIFY: - // ATA IDENTIFY DEVICE - passthru->command = ATA_IDENTIFY_DEVICE; - passthru->features = 0; - passthru->cylinder_lo = 0; - passthru->cylinder_hi = 0; - break; - case PIDENTIFY: - // 3WARE controller can NOT have packet device internally - pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); - errno=ENODEV; - return -1; - case ENABLE: - passthru->features = ATA_SMART_ENABLE; - break; - case DISABLE: - passthru->features = ATA_SMART_DISABLE; - break; - case AUTO_OFFLINE: - passthru->features = ATA_SMART_AUTO_OFFLINE; - // Enable or disable? - passthru->sector_count = select; - break; - case AUTOSAVE: - passthru->features = ATA_SMART_AUTOSAVE; - // Enable or disable? - passthru->sector_count = select; - break; - case IMMEDIATE_OFFLINE: - passthru->features = ATA_SMART_IMMEDIATE_OFFLINE; - // What test type to run? - passthru->sector_num = select; - break; - case STATUS_CHECK: - passthru->features = ATA_SMART_STATUS; - break; - case STATUS: - // This is JUST to see if SMART is enabled, by giving SMART status - // command. But it doesn't say if status was good, or failing. - // See below for the difference. - passthru->features = ATA_SMART_STATUS; - break; - default: - pout("Unrecognized command %d in linux_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); - errno=ENOSYS; - return -1; - } - - // Now send the command down through an ioctl() - if (escalade_type==CONTROLLER_3WARE_9000_CHAR) - ioctlreturn=ioctl(fd, TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache); - else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) - ioctlreturn=ioctl(fd, TW_CMD_PACKET_WITH_DATA, tw_ioctl_char); - else - ioctlreturn=ioctl(fd, SCSI_IOCTL_SEND_COMMAND, tw_ioctl); - - // Deal with the different error cases - if (ioctlreturn) { - if (CONTROLLER_3WARE_678K==escalade_type && ((command==AUTO_OFFLINE || command==AUTOSAVE) && select)){ - // error here is probably a kernel driver whose version is too old - printwarning(command); - errno=ENOTSUP; - } - if (!errno) - errno=EIO; - return -1; - } - - // 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 (CONTROLLER_3WARE_678K==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))) { - errno=EIO; - return -1; - } - - // If this is a read data command, copy data to output buffer - if (readdata) { - if (escalade_type==CONTROLLER_3WARE_9000_CHAR) - memcpy(data, (unsigned char *)tw_ioctl_apache->data_buffer, 512); - else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) - memcpy(data, (unsigned char *)tw_ioctl_char->data_buffer, 512); - else - memcpy(data, tw_output->output_data, 512); - } - - // For STATUS_CHECK, we need to check register values - if (command==STATUS_CHECK) { - - // To find out if the SMART RETURN STATUS is good or failing, we - // need to examine the values of the Cylinder Low and Cylinder - // High Registers. - - unsigned short cyl_lo=passthru->cylinder_lo; - unsigned short cyl_hi=passthru->cylinder_hi; - - // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. - if (cyl_lo==0x4F && cyl_hi==0xC2) - return 0; - - // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL - if (cyl_lo==0xF4 && cyl_hi==0x2C) - return 1; - - // Any other values mean that something has gone wrong with the command - if (CONTROLLER_3WARE_678K==escalade_type) { - printwarning(command); - errno=ENOSYS; - return 0; - } - else { - errno=EIO; - return -1; - } - } - - // copy sector count register (one byte!) to return data - if (command==CHECK_POWER_MODE) - *data=*(char *)&(passthru->sector_count); - - // look for nonexistent devices/ports - if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { - errno=ENODEV; - return -1; - } - - return 0; -} - -// 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; -} - -// 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. -static const char * lin_dev_prefix = "/dev/"; -static const char * lin_dev_ata_disk_plus = "h"; -static const char * lin_dev_ata_devfs_disk_plus = "ide/"; -static const char * lin_dev_scsi_devfs_disk_plus = "scsi/"; -static const char * lin_dev_scsi_disk_plus = "s"; -static const char * lin_dev_scsi_tape1 = "ns"; -static const char * lin_dev_scsi_tape2 = "os"; -static const char * lin_dev_scsi_tape3 = "nos"; -static const char * lin_dev_3ware_9000_char = "twa"; -static const char * lin_dev_3ware_678k_char = "twe"; - -int guess_device_type(const char * dev_name) { - int len; - int dev_prefix_len = strlen(lin_dev_prefix); - - // if dev_name null, or string length zero - if (!dev_name || !(len = strlen(dev_name))) - return CONTROLLER_UNKNOWN; - - // Remove the leading /dev/... if it's there - if (!strncmp(lin_dev_prefix, dev_name, dev_prefix_len)) { - if (len <= dev_prefix_len) - // if nothing else in the string, unrecognized - return CONTROLLER_UNKNOWN; - // else advance pointer to following characters - dev_name += dev_prefix_len; - } - - // form /dev/h* or h* - if (!strncmp(lin_dev_ata_disk_plus, dev_name, - strlen(lin_dev_ata_disk_plus))) - return CONTROLLER_ATA; - - // form /dev/ide/* or ide/* - if (!strncmp(lin_dev_ata_devfs_disk_plus, dev_name, - strlen(lin_dev_ata_devfs_disk_plus))) - return CONTROLLER_ATA; - - // form /dev/s* or s* - if (!strncmp(lin_dev_scsi_disk_plus, dev_name, - strlen(lin_dev_scsi_disk_plus))) - return CONTROLLER_SCSI; - - // form /dev/scsi/* or scsi/* - if (!strncmp(lin_dev_scsi_devfs_disk_plus, dev_name, - strlen(lin_dev_scsi_devfs_disk_plus))) - return CONTROLLER_SCSI; - - // form /dev/ns* or ns* - if (!strncmp(lin_dev_scsi_tape1, dev_name, - strlen(lin_dev_scsi_tape1))) - return CONTROLLER_SCSI; - - // form /dev/os* or os* - if (!strncmp(lin_dev_scsi_tape2, dev_name, - strlen(lin_dev_scsi_tape2))) - return CONTROLLER_SCSI; - - // form /dev/nos* or nos* - if (!strncmp(lin_dev_scsi_tape3, dev_name, - strlen(lin_dev_scsi_tape3))) - return CONTROLLER_SCSI; - - // form /dev/twa* - if (!strncmp(lin_dev_3ware_9000_char, dev_name, - strlen(lin_dev_3ware_9000_char))) - return CONTROLLER_3WARE_9000_CHAR; - - // form /dev/twe* - if (!strncmp(lin_dev_3ware_678k_char, dev_name, - strlen(lin_dev_3ware_678k_char))) - return CONTROLLER_3WARE_678K_CHAR; - - // we failed to recognize any of the forms - return CONTROLLER_UNKNOWN; -} - - -#if 0 - -[ed@firestorm ed]$ ls -l /dev/discs -total 0 -lr-xr-xr-x 1 root root 30 Dec 31 1969 disc0 -> ../ide/host2/bus0/target0/lun0/ -lr-xr-xr-x 1 root root 30 Dec 31 1969 disc1 -> ../ide/host2/bus1/target0/lun0/ -[ed@firestorm ed]$ ls -l dev/ide/host*/bus*/target*/lun*/disc -ls: dev/ide/host*/bus*/target*/lun*/disc: No such file or directory -[ed@firestorm ed]$ ls -l /dev/ide/host*/bus*/target*/lun*/disc -brw------- 1 root root 33, 0 Dec 31 1969 /dev/ide/host2/bus0/target0/lun0/disc -brw------- 1 root root 34, 0 Dec 31 1969 /dev/ide/host2/bus1/target0/lun0/disc -[ed@firestorm ed]$ ls -l /dev/ide/c*b*t*u* -ls: /dev/ide/c*b*t*u*: No such file or directory -[ed@firestorm ed]$ -Script done on Fri Nov 7 13:46:28 2003 - -#endif diff --git a/sm5/os_linux.cpp b/sm5/os_linux.cpp deleted file mode 100644 index 380b3a60c31d30be797d8a02115acec26b17a86b..0000000000000000000000000000000000000000 --- a/sm5/os_linux.cpp +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * os_linux.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2003-4 Doug Gilbert <dougg@torque.net> - * - * 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, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 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 <errno.h> -#include <fcntl.h> -#include <glob.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 <unistd.h> -#ifndef makedev // old versions of types.h do not include sysmacros.h -#include <sys/sysmacros.h> -#endif - -#include "atacmds.h" -#include "os_linux.h" -#include "scsicmds.h" -#include "utility.h" - -#ifndef ENOTSUP -#define ENOTSUP ENOSYS -#endif -typedef unsigned long long u8; - -#define ARGUSED(x) ((void)(x)) - -static const char *filenameandversion="$Id: os_linux.cpp,v 1.70 2004/08/16 22:44:26 ballen4705 Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.70 2004/08/16 22:44:26 ballen4705 Exp $" \ -ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// global variable holding byte count of allocated memory -extern long long bytes; - - - -/* 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 -int setup_3ware_nodes(char *nodename, 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; - - /* 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; - } - - /* Now check if nodes are correct */ - for (index=0; index<16; index++) { - sprintf(nodestring, "/dev/%s%d", nodename, index); - - /* Try to stat the node */ - if ((stat(nodestring, &stat_buf))) { - /* 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"); - return 3; - } - } - - /* 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))) { - - /* Delete the old node */ - if (unlink(nodestring)) { - pout("problem unlinking stale 3ware device node %s", nodestring); - syserror("unlink"); - return 4; - } - - /* Make a new node */ - if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { - pout("problem creating 3ware device nodes %s", nodestring); - syserror("mknod"); - return 5; - } - } - } - return 0; -} - -// equivalent to open(path, flags) -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_RDONLY | O_NONBLOCK); - else if (!strcmp(type,"ATA_3WARE_9000")) { - // the device nodes for this controller are dynamically assigned, - // so we need to check that they exist with the correct major - // numbers and if not, create them - if (setup_3ware_nodes("twa", "3w-9xxx")) { - if (!errno) - errno=ENXIO; - return -1; - } - return open(pathname, O_RDONLY | O_NONBLOCK); - } - else if (!strcmp(type,"ATA_3WARE_678K")) { - // the device nodes for this controller are dynamically assigned, - // so we need to check that they exist with the correct major - // numbers and if not, create them - if (setup_3ware_nodes("twe", "3w-xxxx")) { - if (!errno) - errno=ENXIO; - return -1; - } - return open(pathname, O_RDONLY | O_NONBLOCK); - } - else - return -1; -} - -// equivalent to close(file descriptor) -int deviceclose(int fd){ - return close(fd); -} - -// print examples for smartctl -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; -} - - -// 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 -// -// If any errors occur, leave errno set as it was returned by the -// system call, and return <0. -int get_dev_names(char*** names, const char* pattern, const char* name, int max) { - int n = 0, retglob, i, lim; - char** mp; - glob_t globbuf; - - memset(&globbuf, 0, sizeof(globbuf)); - - // in case of non-clean exit - *names=NULL; - - // Use glob to look for any directory entries matching the pattern - if ((retglob=glob(pattern, GLOB_ERR, NULL, &globbuf))) { - - // glob failed: free memory and return - globfree(&globbuf); - - if (retglob==GLOB_NOMATCH){ - pout("glob(3) found no matches for pattern %s\n", pattern); - return 0; - } - - if (retglob==GLOB_NOSPACE) - pout("glob(3) ran out of memory matching pattern %s\n", pattern); -#ifdef GLOB_ABORTED // missing in old versions of glob.h - else if (retglob==GLOB_ABORTED) - pout("glob(3) aborted matching pattern %s\n", pattern); -#endif - else - pout("Unexplained error in glob(3) of pattern %s\n", pattern); - - return -1; - } - - // did we find too many paths? - lim = ((int)globbuf.gl_pathc < max) ? (int)globbuf.gl_pathc : max; - if (lim < (int)globbuf.gl_pathc) - pout("glob(3) found %d > MAX=%d devices matching pattern %s: ignoring %d paths\n", - (int)globbuf.gl_pathc, max, pattern, (int)(globbuf.gl_pathc-max)); - - // allocate space for up to lim number of ATA devices - if (!(mp = (char **)calloc(lim, sizeof(char*)))){ - pout("Out of memory constructing scan device list\n"); - return -1; - } - - // 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 (i=0; i<lim; i++){ - int retlink; - - // prepare a buffer for storing the link - char linkbuf[1024]; - - // see if path is a link - retlink=readlink(globbuf.gl_pathv[i], linkbuf, 1023); - - // if not a link (or a strange link), keep it - if (retlink<=0 || retlink>1023) - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - else { - // or if it's a link that points to a disc, follow it - char *p; - linkbuf[retlink]='\0'; - 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. - mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion); - 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. - char tmpname[1024]={0}; - char *type=strcmp(name,"ATA")?"scsi":"ide"; - if (strstr(linkbuf, type)){ - snprintf(tmpname, 1024, "%s/disc", globbuf.gl_pathv[i]); - mp[n++] = CustomStrDup(tmpname, 1, __LINE__, filenameandversion); - } - } - } - } - - // free memory, track memory usage - globfree(&globbuf); - mp = realloc(mp,n*(sizeof(char*))); - bytes += n*(sizeof(char*)); - - // and set up return values - *names=mp; - return n; -} - -// makes a list of device names to scan, for either ATA or SCSI -// devices. Return -1 if no memory remaining, else the number of -// devices on the list, which can be >=0. -int make_device_names (char*** devlist, const char* name) { - int retval, maxdev; - -#if 0 - // for testing case where no device names are found - return 0; -#endif - - if (!strcmp(name,"SCSI")) - retval=get_dev_names(devlist,"/dev/sd[a-z]", name, maxdev=26); - else if (!strcmp(name,"ATA")) - retval=get_dev_names(devlist,"/dev/hd[a-t]", name, maxdev=20); - else - // don't recognize disk type! - return 0; - - // if we found traditional links, we are done - if (retval>0) - return retval; - - // else look for devfs entries without traditional links - return get_dev_names(devlist,"/dev/discs/disc*", name, maxdev); -} - - -// 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" - - -// 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); - - 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: - 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; - } - - // 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(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; - } - - // There are two different types of ioctls(). The HDIO_DRIVE_TASK - // one is this: - if (command==STATUS_CHECK){ - 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(device, 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("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 - // 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(device, 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(device, 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_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); -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) -{ -#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(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) - pout(" SG_IO ioctl failed, errno=%d [%s]\n", errno, - strerror(errno)); - return -errno; - } - if (report > 0) { - pout(" scsi_status=0x%x, host_status=0x%x, driver_status=0x%x\n" - " info=0x%x duration=%d milliseconds\n", io_hdr.status, - io_hdr.host_status, io_hdr.driver_status, io_hdr.info, - io_hdr.duration); - if (report > 1) { - if (DXFER_FROM_DEVICE == iop->dxfer_dir) { - 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); - } - } - } - iop->resid = io_hdr.resid; - iop->scsi_status = io_hdr.status; - - 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 - return -EIO; /* catch all */ - } - if (0 != masked_driver_status) { - if (LSCSI_DRIVER_TIMEOUT == masked_driver_status) - return -ETIMEDOUT; - else - return -EIO; /* catch all */ - } - if (LSCSI_DRIVER_SENSE == (io_hdr.driver_status & 0xf)) - 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) { - 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(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 */ -int do_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, 0))) { - 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); - 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 - - -// prototype -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) ) - -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - - // return value and buffer for ioctl() - int ioctlreturn, readdata=0; - - // 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); - - if (escalade_type==CONTROLLER_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 (escalade_type==CONTROLLER_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 (escalade_type==CONTROLLER_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 { - pout("Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum); - errno=ENOSYS; - return -1; - } - - // Same for (almost) all commands - but some reset below - passthru->byte0.opcode = TW_OP_ATA_PASSTHRU; - passthru->request_id = 0xFF; - passthru->byte3.aport = disknum; - passthru->byte3.host_id = 0; - passthru->status = 0; - passthru->flags = 0x1; - passthru->drive_head = 0x0; - passthru->sector_num = 0; - - // All SMART commands use this CL/CH signature. These are magic - // values from the ATA specifications. - passthru->cylinder_lo = 0x4F; - passthru->cylinder_hi = 0xC2; - - // SMART ATA COMMAND REGISTER value - passthru->command = ATA_SMART_CMD; - - // 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 - if (command == READ_VALUES || - command == READ_THRESHOLDS || - command == READ_LOG || - command == IDENTIFY || - command == WRITE_LOG ) { - readdata=1; - passthru->byte0.sgloff = 0x5; - passthru->size = 0x7; - passthru->param = 0xD; - passthru->sector_count = 0x1; - // 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 (escalade_type==CONTROLLER_3WARE_9000_CHAR && sizeof(long)==8) - passthru->size++; - } - else { - // 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; - } - - // Now set ATA registers depending upon command - switch (command){ - case CHECK_POWER_MODE: - passthru->command = ATA_CHECK_POWER_MODE; - passthru->features = 0; - passthru->cylinder_lo = 0; - passthru->cylinder_hi = 0; - break; - case READ_VALUES: - passthru->features = ATA_SMART_READ_VALUES; - break; - case READ_THRESHOLDS: - passthru->features = ATA_SMART_READ_THRESHOLDS; - break; - case READ_LOG: - passthru->features = ATA_SMART_READ_LOG_SECTOR; - // log number to return - passthru->sector_num = select; - break; - case WRITE_LOG: - if (escalade_type == CONTROLLER_3WARE_9000_CHAR) - memcpy((unsigned char *)tw_ioctl_apache->data_buffer, data, 512); - else if (escalade_type == CONTROLLER_3WARE_678K_CHAR) - memcpy((unsigned char *)tw_ioctl_char->data_buffer, data, 512); - else { - // COMMAND NOT SUPPORTED VIA SCSI IOCTL INTERFACE - // memcpy(tw_output->output_data, data, 512); - printwarning(command); - errno=ENOTSUP; - return -1; - } - readdata=0; - passthru->features = ATA_SMART_WRITE_LOG_SECTOR; - passthru->sector_count = 1; - passthru->sector_num = select; - passthru->param = 0xF; // PIO data write - break; - case IDENTIFY: - // ATA IDENTIFY DEVICE - passthru->command = ATA_IDENTIFY_DEVICE; - passthru->features = 0; - passthru->cylinder_lo = 0; - passthru->cylinder_hi = 0; - break; - case PIDENTIFY: - // 3WARE controller can NOT have packet device internally - pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum); - errno=ENODEV; - return -1; - case ENABLE: - passthru->features = ATA_SMART_ENABLE; - break; - case DISABLE: - passthru->features = ATA_SMART_DISABLE; - break; - case AUTO_OFFLINE: - passthru->features = ATA_SMART_AUTO_OFFLINE; - // Enable or disable? - passthru->sector_count = select; - break; - case AUTOSAVE: - passthru->features = ATA_SMART_AUTOSAVE; - // Enable or disable? - passthru->sector_count = select; - break; - case IMMEDIATE_OFFLINE: - passthru->features = ATA_SMART_IMMEDIATE_OFFLINE; - // What test type to run? - passthru->sector_num = select; - break; - case STATUS_CHECK: - passthru->features = ATA_SMART_STATUS; - break; - case STATUS: - // This is JUST to see if SMART is enabled, by giving SMART status - // command. But it doesn't say if status was good, or failing. - // See below for the difference. - passthru->features = ATA_SMART_STATUS; - break; - default: - pout("Unrecognized command %d in linux_3ware_command_interface(disk %d)\n" - "Please contact " PACKAGE_BUGREPORT "\n", command, disknum); - errno=ENOSYS; - return -1; - } - - // Now send the command down through an ioctl() - if (escalade_type==CONTROLLER_3WARE_9000_CHAR) - ioctlreturn=ioctl(fd, TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache); - else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) - ioctlreturn=ioctl(fd, TW_CMD_PACKET_WITH_DATA, tw_ioctl_char); - else - ioctlreturn=ioctl(fd, SCSI_IOCTL_SEND_COMMAND, tw_ioctl); - - // Deal with the different error cases - if (ioctlreturn) { - if (CONTROLLER_3WARE_678K==escalade_type && ((command==AUTO_OFFLINE || command==AUTOSAVE) && select)){ - // error here is probably a kernel driver whose version is too old - printwarning(command); - errno=ENOTSUP; - } - if (!errno) - errno=EIO; - return -1; - } - - // 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 (CONTROLLER_3WARE_678K==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))) { - errno=EIO; - return -1; - } - - // If this is a read data command, copy data to output buffer - if (readdata) { - if (escalade_type==CONTROLLER_3WARE_9000_CHAR) - memcpy(data, (unsigned char *)tw_ioctl_apache->data_buffer, 512); - else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) - memcpy(data, (unsigned char *)tw_ioctl_char->data_buffer, 512); - else - memcpy(data, tw_output->output_data, 512); - } - - // For STATUS_CHECK, we need to check register values - if (command==STATUS_CHECK) { - - // To find out if the SMART RETURN STATUS is good or failing, we - // need to examine the values of the Cylinder Low and Cylinder - // High Registers. - - unsigned short cyl_lo=passthru->cylinder_lo; - unsigned short cyl_hi=passthru->cylinder_hi; - - // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. - if (cyl_lo==0x4F && cyl_hi==0xC2) - return 0; - - // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL - if (cyl_lo==0xF4 && cyl_hi==0x2C) - return 1; - - // Any other values mean that something has gone wrong with the command - if (CONTROLLER_3WARE_678K==escalade_type) { - printwarning(command); - errno=ENOSYS; - return 0; - } - else { - errno=EIO; - return -1; - } - } - - // copy sector count register (one byte!) to return data - if (command==CHECK_POWER_MODE) - *data=*(char *)&(passthru->sector_count); - - // look for nonexistent devices/ports - if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) { - errno=ENODEV; - return -1; - } - - return 0; -} - -// 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; -} - -// 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. -static const char * lin_dev_prefix = "/dev/"; -static const char * lin_dev_ata_disk_plus = "h"; -static const char * lin_dev_ata_devfs_disk_plus = "ide/"; -static const char * lin_dev_scsi_devfs_disk_plus = "scsi/"; -static const char * lin_dev_scsi_disk_plus = "s"; -static const char * lin_dev_scsi_tape1 = "ns"; -static const char * lin_dev_scsi_tape2 = "os"; -static const char * lin_dev_scsi_tape3 = "nos"; -static const char * lin_dev_3ware_9000_char = "twa"; -static const char * lin_dev_3ware_678k_char = "twe"; - -int guess_device_type(const char * dev_name) { - int len; - int dev_prefix_len = strlen(lin_dev_prefix); - - // if dev_name null, or string length zero - if (!dev_name || !(len = strlen(dev_name))) - return CONTROLLER_UNKNOWN; - - // Remove the leading /dev/... if it's there - if (!strncmp(lin_dev_prefix, dev_name, dev_prefix_len)) { - if (len <= dev_prefix_len) - // if nothing else in the string, unrecognized - return CONTROLLER_UNKNOWN; - // else advance pointer to following characters - dev_name += dev_prefix_len; - } - - // form /dev/h* or h* - if (!strncmp(lin_dev_ata_disk_plus, dev_name, - strlen(lin_dev_ata_disk_plus))) - return CONTROLLER_ATA; - - // form /dev/ide/* or ide/* - if (!strncmp(lin_dev_ata_devfs_disk_plus, dev_name, - strlen(lin_dev_ata_devfs_disk_plus))) - return CONTROLLER_ATA; - - // form /dev/s* or s* - if (!strncmp(lin_dev_scsi_disk_plus, dev_name, - strlen(lin_dev_scsi_disk_plus))) - return CONTROLLER_SCSI; - - // form /dev/scsi/* or scsi/* - if (!strncmp(lin_dev_scsi_devfs_disk_plus, dev_name, - strlen(lin_dev_scsi_devfs_disk_plus))) - return CONTROLLER_SCSI; - - // form /dev/ns* or ns* - if (!strncmp(lin_dev_scsi_tape1, dev_name, - strlen(lin_dev_scsi_tape1))) - return CONTROLLER_SCSI; - - // form /dev/os* or os* - if (!strncmp(lin_dev_scsi_tape2, dev_name, - strlen(lin_dev_scsi_tape2))) - return CONTROLLER_SCSI; - - // form /dev/nos* or nos* - if (!strncmp(lin_dev_scsi_tape3, dev_name, - strlen(lin_dev_scsi_tape3))) - return CONTROLLER_SCSI; - - // form /dev/twa* - if (!strncmp(lin_dev_3ware_9000_char, dev_name, - strlen(lin_dev_3ware_9000_char))) - return CONTROLLER_3WARE_9000_CHAR; - - // form /dev/twe* - if (!strncmp(lin_dev_3ware_678k_char, dev_name, - strlen(lin_dev_3ware_678k_char))) - return CONTROLLER_3WARE_678K_CHAR; - - // we failed to recognize any of the forms - return CONTROLLER_UNKNOWN; -} - - -#if 0 - -[ed@firestorm ed]$ ls -l /dev/discs -total 0 -lr-xr-xr-x 1 root root 30 Dec 31 1969 disc0 -> ../ide/host2/bus0/target0/lun0/ -lr-xr-xr-x 1 root root 30 Dec 31 1969 disc1 -> ../ide/host2/bus1/target0/lun0/ -[ed@firestorm ed]$ ls -l dev/ide/host*/bus*/target*/lun*/disc -ls: dev/ide/host*/bus*/target*/lun*/disc: No such file or directory -[ed@firestorm ed]$ ls -l /dev/ide/host*/bus*/target*/lun*/disc -brw------- 1 root root 33, 0 Dec 31 1969 /dev/ide/host2/bus0/target0/lun0/disc -brw------- 1 root root 34, 0 Dec 31 1969 /dev/ide/host2/bus1/target0/lun0/disc -[ed@firestorm ed]$ ls -l /dev/ide/c*b*t*u* -ls: /dev/ide/c*b*t*u*: No such file or directory -[ed@firestorm ed]$ -Script done on Fri Nov 7 13:46:28 2003 - -#endif diff --git a/sm5/os_linux.h b/sm5/os_linux.h deleted file mode 100644 index 24c5e92df7816f2f66c2f571ff1985ac854964c0..0000000000000000000000000000000000000000 --- a/sm5/os_linux.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * os_linux.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * - * 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> - * - * - * 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., 675 Mass Ave, Cambridge, MA 02139, 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_XXXX_H_CVSID "$Id: os_linux.h,v 1.21 2004/08/16 22:44:27 ballen4705 Exp $\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; - struct { - unsigned char aport:4; - unsigned char host_id:4; - } byte3; - 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 - -#endif /* OS_LINUX_H_ */ diff --git a/sm5/os_netbsd.c b/sm5/os_netbsd.c deleted file mode 100644 index 0b4cf959fdc561da07d4b4d7efb6333a8dac5d82..0000000000000000000000000000000000000000 --- a/sm5/os_netbsd.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * os_netbsd.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "config.h" -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" -#include "os_netbsd.h" - -const char *os_XXXX_c_cvsid = "$Id: os_netbsd.c,v 1.8 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_NETBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -/* global variable holding byte count of allocated memory */ -extern long long bytes; - -enum warnings { - BAD_SMART, NO_3WARE, 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 = "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 = 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] = 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 = 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 = WDSM_RD_DATA; - req.command = WDCC_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 = WDSM_RD_THRESHOLDS; - req.command = WDCC_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 = WDCC_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 = WDCC_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 = WDSM_ENABLE_OPS; - req.command = WDCC_SMART; - req.cylinder = htole16(WDSMART_CYL); - req.timeout = 1000; - break; - case DISABLE: - req.flags = ATACMD_READ; - req.features = WDSM_DISABLE_OPS; - req.command = WDCC_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 = WDCC_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 = WDCC_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 = WDCC_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 = WDSM_STATUS; - req.command = WDCC_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 (le16toh(req.cylinder) == normal) - return 0; - - /* These values mean "Bad SMART status" */ - if (le16toh(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 (command == CHECK_POWER_MODE) - data[0] = req.sec_count; - - if (copydata) - memcpy(data, inbuf, 512); - - return 0; -} - -int -escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) -{ - printwarning(NO_3WARE, NULL); - return -1; -} - -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 : "<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("]"); - } - memset(&sc, 0, sizeof(sc)); - memcpy(sc.cmd, iop->cmnd, iop->cmnd_len); - sc.cmdlen = iop->cmnd_len; - sc.databuf = 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 : /* XXX */ - (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; -} diff --git a/sm5/os_netbsd.cpp b/sm5/os_netbsd.cpp deleted file mode 100644 index 255ec8ba294c7b84dde97189cffe4331cced18cc..0000000000000000000000000000000000000000 --- a/sm5/os_netbsd.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * os_netbsd.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "config.h" -#include "atacmds.h" -#include "scsicmds.h" -#include "utility.h" -#include "os_netbsd.h" - -const char *os_XXXX_c_cvsid = "$Id: os_netbsd.cpp,v 1.8 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID OS_NETBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -/* global variable holding byte count of allocated memory */ -extern long long bytes; - -enum warnings { - BAD_SMART, NO_3WARE, 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 = "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 = 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] = 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 = 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 = WDSM_RD_DATA; - req.command = WDCC_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 = WDSM_RD_THRESHOLDS; - req.command = WDCC_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 = WDCC_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 = WDCC_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 = WDSM_ENABLE_OPS; - req.command = WDCC_SMART; - req.cylinder = htole16(WDSMART_CYL); - req.timeout = 1000; - break; - case DISABLE: - req.flags = ATACMD_READ; - req.features = WDSM_DISABLE_OPS; - req.command = WDCC_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 = WDCC_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 = WDCC_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 = WDCC_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 = WDSM_STATUS; - req.command = WDCC_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 (le16toh(req.cylinder) == normal) - return 0; - - /* These values mean "Bad SMART status" */ - if (le16toh(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 (command == CHECK_POWER_MODE) - data[0] = req.sec_count; - - if (copydata) - memcpy(data, inbuf, 512); - - return 0; -} - -int -escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) -{ - printwarning(NO_3WARE, NULL); - return -1; -} - -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 : "<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("]"); - } - memset(&sc, 0, sizeof(sc)); - memcpy(sc.cmd, iop->cmnd, iop->cmnd_len); - sc.cmdlen = iop->cmnd_len; - sc.databuf = 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 : /* XXX */ - (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; -} diff --git a/sm5/os_netbsd.h b/sm5/os_netbsd.h deleted file mode 100644 index 58a81b3568ec399a0bd4d646a2abb99f0dd7cff2..0000000000000000000000000000000000000000 --- a/sm5/os_netbsd.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * os_netbsd.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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,v 1.7 2004/04/29 19:00:36 shattered Exp $\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_ */ diff --git a/sm5/os_solaris.c b/sm5/os_solaris.c deleted file mode 100644 index 4a74980a168da73c4dc632b133146e614be04a30..0000000000000000000000000000000000000000 --- a/sm5/os_solaris.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * os_solaris.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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 "atacmds.h" -#include "scsicmds.h" -#include "utility.h" - -// This is to include whatever prototypes you define in os_solaris.h -#include "os_solaris.h" - -extern long long bytes; - -static const char *filenameandversion="$Id: os_solaris.c,v 1.19 2004/08/13 13:57:12 arvoreen Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_solaris.c,v 1.19 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_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_UNKNOW; -} - -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 = 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 = 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); -} - -static void swap_sector(void *p) -{ - int i; - unsigned char t, *cp = p; - for(i = 0; i < 256; i++) { - t = cp[0]; cp[0] = cp[1]; cp[1] = t; - cp += 2; - } -} - -// 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(data); - return 0; - case PIDENTIFY: - err = ata_pidentify(fd, data); - if(err) return err; - swap_sector(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 */ - // avoid gcc warnings// - fd=command=select=0; - data=NULL; - - /* Above smart_* routines uses undocumented ioctls of "dada" - * driver, which is specific to SPARC Solaris. x86 Solaris seems - * not to provide similar or alternative interface... */ - if (printwarning(0)) - return -1; -#endif - return -1; -} - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - // avoid gcc warnings// - fd=disknum=escalade_type=command=select=0; - data=NULL; - - if (printwarning(1)) - return -1; - 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]); - 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((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); - } - else - pout("]"); - } - - - memset(&uscsi, 0, sizeof (uscsi)); - - uscsi.uscsi_cdb = (void *)iop->cmnd; - uscsi.uscsi_cdblen = iop->cmnd_len; - if (iop->timeout == 0) - uscsi.uscsi_timeout = 60; /* XXX */ - else - uscsi.uscsi_timeout = iop->timeout; - uscsi.uscsi_bufaddr = (void *)iop->dxferp; - uscsi.uscsi_buflen = iop->dxfer_len; - uscsi.uscsi_rqbuf = (void *)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; - - if (ioctl(fd, USCSICMD, &uscsi)) - return -errno; - - 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 = (iop->dxfer_len > 256) ? 1 : 0; - pout(" status=0\n"); - - pout(" Incoming 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); - } - - return (0); -} diff --git a/sm5/os_solaris.cpp b/sm5/os_solaris.cpp deleted file mode 100644 index ddf2ab4e6e84f56b113529cdb333951b3487a814..0000000000000000000000000000000000000000 --- a/sm5/os_solaris.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * os_solaris.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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 "atacmds.h" -#include "scsicmds.h" -#include "utility.h" - -// This is to include whatever prototypes you define in os_solaris.h -#include "os_solaris.h" - -extern long long bytes; - -static const char *filenameandversion="$Id: os_solaris.cpp,v 1.19 2004/08/13 13:57:12 arvoreen Exp $"; - -const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp,v 1.19 2004/08/13 13:57:12 arvoreen Exp $" \ -ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_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_UNKNOW; -} - -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 = 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 = 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); -} - -static void swap_sector(void *p) -{ - int i; - unsigned char t, *cp = p; - for(i = 0; i < 256; i++) { - t = cp[0]; cp[0] = cp[1]; cp[1] = t; - cp += 2; - } -} - -// 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(data); - return 0; - case PIDENTIFY: - err = ata_pidentify(fd, data); - if(err) return err; - swap_sector(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 */ - // avoid gcc warnings// - fd=command=select=0; - data=NULL; - - /* Above smart_* routines uses undocumented ioctls of "dada" - * driver, which is specific to SPARC Solaris. x86 Solaris seems - * not to provide similar or alternative interface... */ - if (printwarning(0)) - return -1; -#endif - return -1; -} - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data){ - // avoid gcc warnings// - fd=disknum=escalade_type=command=select=0; - data=NULL; - - if (printwarning(1)) - return -1; - 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]); - 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((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); - } - else - pout("]"); - } - - - memset(&uscsi, 0, sizeof (uscsi)); - - uscsi.uscsi_cdb = (void *)iop->cmnd; - uscsi.uscsi_cdblen = iop->cmnd_len; - if (iop->timeout == 0) - uscsi.uscsi_timeout = 60; /* XXX */ - else - uscsi.uscsi_timeout = iop->timeout; - uscsi.uscsi_bufaddr = (void *)iop->dxferp; - uscsi.uscsi_buflen = iop->dxfer_len; - uscsi.uscsi_rqbuf = (void *)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; - - if (ioctl(fd, USCSICMD, &uscsi)) - return -errno; - - 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 = (iop->dxfer_len > 256) ? 1 : 0; - pout(" status=0\n"); - - pout(" Incoming 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); - } - - return (0); -} diff --git a/sm5/os_solaris.h b/sm5/os_solaris.h deleted file mode 100644 index b62cbd89253e8ec3b14788cc2d291b8781820ff4..0000000000000000000000000000000000000000 --- a/sm5/os_solaris.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * os_solaris.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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_XXXX_H_CVSID "$Id: os_solaris.h,v 1.8 2004/02/12 18:30:30 card_captor Exp $\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 -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_ */ diff --git a/sm5/os_solaris_ata.s b/sm5/os_solaris_ata.s deleted file mode 100644 index 765e2ecdc9a626152309a919e38ebcdbb6c35c95..0000000000000000000000000000000000000000 --- a/sm5/os_solaris_ata.s +++ /dev/null @@ -1,721 +0,0 @@ -! -! os_solaris_ata.s -! -! Home page of code is: http://smartmontools.sourceforge.net -! -! Copyright (C) 2003-4 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., 675 Mass Ave, Cambridge, MA 02139, 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 "os_solaris_ata.s" - .global os_solaris_ata_s_cvsid - - .section ".rodata" - .align 8 -.LLC0: - .asciz "$Id: os_solaris_ata.s,v 1.2 2004/02/13 17:29:09 ballen4705 Exp $" - - .section ".data" - .align 4 - .type os_solaris_ata_s_cvsid,#object - .size os_solaris_ata_s_cvsid,4 -os_solaris_ata_s_cvsid: - .uaword .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+88], %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 - ldub [%fp+75], %g1 - stb %g1, [%fp-72] - mov 1, %g1 - stb %g1, [%fp-71] - mov 1, %g1 - stb %g1, [%fp-70] - ldub [%fp+79], %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+84], %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+84], %g1 - sll %g1, 9, %g1 - st %g1, [%fp-44] - ld [%fp+84], %g1 - sll %g1, 9, %g1 - st %g1, [%fp-40] - ld [%fp+84], %g1 - cmp %g1, 0 - be .LL5 - nop - ld [%fp+88], %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, -640, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - st %i1, [%fp+72] - add %fp, -536, %g1 - ld [%fp+68], %o0 - mov 236, %o1 - mov 0, %o2 - mov 0, %o3 - mov 1, %o4 - mov %g1, %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, -640, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - st %i1, [%fp+72] - add %fp, -536, %g1 - ld [%fp+68], %o0 - mov 161, %o1 - mov 0, %o2 - mov 0, %o3 - mov 1, %o4 - mov %g1, %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, -640, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - st %i1, [%fp+72] - add %fp, -536, %o5 - ld [%fp+68], %o0 - mov 176, %o1 - mov 208, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %o3 - mov 1, %o4 - 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, -640, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - st %i1, [%fp+72] - add %fp, -536, %o5 - ld [%fp+68], %o0 - mov 176, %o1 - mov 209, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %o3 - mov 1, %o4 - 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, -120, %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 - ld [%fp+68], %o0 - mov 176, %o1 - mov 210, %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 .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, -120, %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 - 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+76], %g1 - sll %g1, 9, %g1 - mov %g1, %o0 - call malloc, 0 - nop - mov %o0, %g1 - st %g1, [%fp-24] - ld [%fp-24], %g1 - cmp %g1, 0 - bne .LL26 - nop - mov -1, %g1 - st %g1, [%fp-28] - b .LL25 - nop -.LL26: - ld [%fp+72], %g1 - and %g1, 255, %o5 - sethi %hi(12733440), %g1 - or %g1, 768, %g1 - or %o5, %g1, %g1 - ld [%fp+68], %o0 - mov 176, %o1 - mov 213, %o2 - mov %g1, %o3 - ld [%fp+76], %o4 - ld [%fp-24], %o5 - call ata_cmd, 0 - nop - mov %o0, %g1 - st %g1, [%fp-20] - ld [%fp+76], %g1 - sll %g1, 9, %g1 - ld [%fp+80], %o0 - ld [%fp-24], %o1 - mov %g1, %o2 - call memcpy, 0 - nop - ld [%fp-24], %o0 - call free, 0 - nop - ld [%fp-20], %g1 - cmp %g1, 0 - be .LL27 - nop - mov -1, %g1 - st %g1, [%fp-32] - b .LL28 - nop -.LL27: - st %g0, [%fp-32] -.LL28: - ld [%fp-32], %g1 - st %g1, [%fp-28] -.LL25: - ld [%fp-28], %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, -120, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - ld [%fp+68], %o0 - mov 176, %o1 - mov 216, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %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 .LL30 - nop - mov -1, %g1 - st %g1, [%fp-24] - b .LL31 - nop -.LL30: - st %g0, [%fp-24] -.LL31: - 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, -120, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - ld [%fp+68], %o0 - mov 176, %o1 - mov 217, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %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 .LL33 - nop - mov -1, %g1 - st %g1, [%fp-24] - b .LL34 - nop -.LL33: - st %g0, [%fp-24] -.LL34: - 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, -120, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - ld [%fp+68], %o0 - mov 176, %o1 - mov 218, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %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 .LL36 - nop - mov -1, %g1 - st %g1, [%fp-24] - b .LL37 - nop -.LL36: - st %g0, [%fp-24] -.LL37: - 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, -120, %sp - !#PROLOGUE# 1 - st %i0, [%fp+68] - ld [%fp+68], %o0 - mov 176, %o1 - mov 218, %o2 - sethi %hi(12733440), %g1 - or %g1, 769, %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 .LL39 - nop - mov -1, %g1 - st %g1, [%fp-24] - b .LL38 - nop -.LL39: - st %g0, [%fp-24] -.LL38: - 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, -120, %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 - ld [%fp+68], %o0 - mov 176, %o1 - mov 219, %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 .LL41 - nop - mov -1, %g1 - st %g1, [%fp-24] - b .LL42 - nop -.LL41: - st %g0, [%fp-24] -.LL42: - ld [%fp-24], %g1 - mov %g1, %i0 - ret - restore - .size smart_auto_offline, .-smart_auto_offline - .ident "GCC: (GNU) 3.3.2" diff --git a/sm5/os_win32.c b/sm5/os_win32.c deleted file mode 100644 index 7885eda26a09f294ef1503b94dd9dfd0b78568b3..0000000000000000000000000000000000000000 --- a/sm5/os_win32.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * os_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "config.h" -#include "atacmds.h" -#include "extern.h" -extern smartmonctrl * con; // con->permissive -#include "int64.h" -#include "scsicmds.h" -#include "utility.h" -extern int64_t bytes; // malloc() byte count - -#include <errno.h> -#ifdef _DEBUG -#include <assert.h> -#else -#define assert(x) /**/ -#endif -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <stddef.h> // offsetof() -#include <io.h> // access() - -#define ARGUSED(x) ((void)(x)) - -// Needed by '-V' option (CVS versioning) of smartd/smartctl -const char *os_XXXX_c_cvsid="$Id: os_win32.c,v 1.16 2004/08/13 13:57:12 arvoreen Exp $" -ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - - -static int ata_open(int drive); -static void ata_close(int fd); -static unsigned ata_scan(void); - -static int aspi_open(unsigned adapter, unsigned id); -static void aspi_close(int fd); -static unsigned long aspi_scan(void); - - -static int is_permissive() -{ - if (con->permissive <= 0) { - pout("To continue, add one or more '-T permissive' options.\n"); - return 0; - } - con->permissive--; - return 1; -} - -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) -{ - 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 -// others each contain null-terminated character strings. -int make_device_names (char*** devlist, const char* type) -{ - unsigned long drives; - int i, j, n, sz, scsi; - const char * path; - - if (!strcmp(type, "ATA")) { - // bit i set => drive i present - drives = ata_scan(); - path = "/dev/hda"; - scsi = 0; - } - else if (!strcmp(type, "SCSI")) { - // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present - drives = aspi_scan(); - path = "/dev/scsi00"; - scsi = 1; - } - else - return -1; - - if (!drives) - return 0; - - // Count #drives - n = 0; - for (i = 0; i < 32; i++) { - if (drives & (1 << i)) - n++; - } - assert(n > 0); - if (n == 0) - return 0; - - // Alloc devlist - assert(scsi || n <= 9); - sz = n * sizeof(char **); - *devlist = (char **)malloc(sz); bytes += sz; - - // Add devices - for (i = j = 0; i < n; i++) { - char * s; - sz = strlen(path)+1; - s = (char *)malloc(sz); bytes += sz; - strcpy(s, path); - while (j < 32 && !(drives & (1 << j))) - j++; - assert(j < 32); - if (!scsi) { - assert(j <= 9); - s[sz-2] += j; // /dev/hd[a-j] - } - else { - s[sz-3] += (j >> 3); // /dev/scsi[0-3]. - s[sz-2] += (j & 0x7); // .....[0-7] - } - (*devlist)[i] = s; - j++; - } - return n; -} - - -// Like open(). Return positive integer handle, only used by -// 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.c for an example). -int deviceopen(const char * pathname, char *type) -{ - int len; - pathname = skipdev(pathname); - len = strlen(pathname); - - if (!strcmp(type, "ATA")) { - // hd[a-z] => ATA 0-9 - if (!(len == 3 && pathname[0] == 'h' && pathname[1] == 'd' - && 'a' <= pathname[2] && pathname[2] <= 'j')) { - errno = ENOENT; - return -1; - } - return ata_open(pathname[2] - 'a'); - } - - if (!strcmp(type, "SCSI")) { - // scsi[0-9][0-f] => SCSI Adapter 0-9, ID 0-15, LUN 0 - unsigned adapter = ~0, id = ~0; int n = -1; - if (!(sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n) == 2 && n == len)) { - errno = ENOENT; - return -1; - } - return aspi_open(adapter, id); - } - errno = ENOENT; - return -1; -} - - -// Like close(). Acts only on handles returned by above function. -// (Never called in smartctl!) -int deviceclose(int fd) -{ - if (fd < 0x100) { - ata_close(fd); - } - else { - aspi_close(fd); - } - return 0; -} - - -// print examples for smartctl -void print_smartctl_examples(){ - printf("=================================================== SMARTCTL EXAMPLES =====\n\n" - " smartctl -a /dev/hda (Prints all SMART information)\n\n" -#ifdef HAVE_GETOPT_LONG - " 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" -#else - " 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" -#endif - " smartctl -a /dev/scsi21\n" - " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n" - ); -} - - -///////////////////////////////////////////////////////////////////////////// -// ATA Interface -///////////////////////////////////////////////////////////////////////////// - -// SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection) - -// Deklarations from: -// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3 - -#define FILE_READ_ACCESS 0x0001 -#define FILE_WRITE_ACCESS 0x0002 -#define METHOD_BUFFERED 0 -#define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) - -#define FILE_DEVICE_DISK 7 -#define IOCTL_DISK_BASE FILE_DEVICE_DISK - -#define SMART_GET_VERSION \ - CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define SMART_RCV_DRIVE_DATA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define SMART_SEND_DRIVE_COMMAND \ - CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define SMART_CYL_LOW 0x4F -#define SMART_CYL_HI 0xC2 - -#pragma pack(1) - -typedef struct _GETVERSIONOUTPARAMS { - UCHAR bVersion; - UCHAR bRevision; - UCHAR bReserved; - UCHAR bIDEDeviceMap; - ULONG fCapabilities; - ULONG dwReserved[4]; -} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS; - -typedef struct _IDEREGS { - UCHAR bFeaturesReg; - UCHAR bSectorCountReg; - UCHAR bSectorNumberReg; - UCHAR bCylLowReg; - UCHAR bCylHighReg; - UCHAR bDriveHeadReg; - UCHAR bCommandReg; - UCHAR bReserved; -} IDEREGS, *PIDEREGS, *LPIDEREGS; - -typedef struct _SENDCMDINPARAMS { - ULONG cBufferSize; - IDEREGS irDriveRegs; - UCHAR bDriveNumber; - UCHAR bReserved[3]; - ULONG dwReserved[4]; - UCHAR bBuffer[1]; -} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; - -/* DRIVERSTATUS.bDriverError constants (just for info, not used) -#define SMART_NO_ERROR 0 -#define SMART_IDE_ERROR 1 -#define SMART_INVALID_FLAG 2 -#define SMART_INVALID_COMMAND 3 -#define SMART_INVALID_BUFFER 4 -#define SMART_INVALID_DRIVE 5 -#define SMART_INVALID_IOCTL 6 -#define SMART_ERROR_NO_MEM 7 -#define SMART_INVALID_REGISTER 8 -#define SMART_NOT_SUPPORTED 9 -#define SMART_NO_IDE_DEVICE 10 -*/ - -typedef struct _DRIVERSTATUS { - UCHAR bDriverError; - UCHAR bIDEError; - UCHAR bReserved[2]; - ULONG dwReserved[2]; -} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; - -typedef struct _SENDCMDOUTPARAMS { - ULONG cBufferSize; - DRIVERSTATUS DriverStatus; - UCHAR bBuffer[1]; -} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; - -#pragma pack() - - -///////////////////////////////////////////////////////////////////////////// - -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); -} - - -///////////////////////////////////////////////////////////////////////////// - -// call SMART_* ioctl - -static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize) -{ - SENDCMDINPARAMS inpar; - unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512]; - const SENDCMDOUTPARAMS * outpar; - DWORD code, num_out; - unsigned int size_out; - - assert(SMART_SEND_DRIVE_COMMAND == 0x07c084); - assert(SMART_RCV_DRIVE_DATA == 0x07c088); - assert(sizeof(SENDCMDINPARAMS)-1 == 32); - assert(sizeof(SENDCMDOUTPARAMS)-1 == 16); - - memset(&inpar, 0, sizeof(inpar)); - inpar.irDriveRegs = *regs; - // drive is set to 0-3 on Win9x only - inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4); - inpar.bDriveNumber = drive; - - assert(datasize == 0 || datasize == 512); - if (datasize) { - inpar.cBufferSize = size_out = 512; - code = SMART_RCV_DRIVE_DATA; - } - else if (regs->bFeaturesReg == ATA_SMART_STATUS) { - size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data - code = SMART_SEND_DRIVE_COMMAND; - } - else { - size_out = 0; - code = SMART_SEND_DRIVE_COMMAND; - } - - memset(&outbuf, 0, sizeof(outbuf)); - -#ifdef _DEBUG - pout("DeviceIoControl(.,0x%lx,.,%lu,.,%lu,.,NULL)\n", - code, sizeof(SENDCMDINPARAMS)-1, sizeof(SENDCMDOUTPARAMS)-1 + size_out); - print_ide_regs(&inpar.irDriveRegs, 0); -#endif - 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 ata_command_interface() - long err = GetLastError(); -#ifdef _DEBUG - pout("DeviceIoControl failed, Error=%ld\n", err); -#endif - errno = ( err == ERROR_INVALID_FUNCTION /*9x*/ - || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO); - return -1; - } - // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs - - outpar = (const SENDCMDOUTPARAMS *)outbuf; -#ifdef _DEBUG - pout("DeviceIoControl returns %lu (%lu) bytes\n", num_out, outpar->cBufferSize); -#endif - - if (outpar->DriverStatus.bDriverError) { - pout("Error SMART IOCTL DriverError=0x%02x, IDEError=0x%02x\n", - outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError); - errno = EIO; - return -1; - } - - if (datasize) - memcpy(data, outpar->bBuffer, 512); - else if (regs->bFeaturesReg == ATA_SMART_STATUS) { - *regs = *(const IDEREGS *)(outpar->bBuffer); -#ifdef _DEBUG - print_ide_regs(regs, 1); -#endif - } - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// - -// IDE PASS THROUGH for W2K/XP (does not work on W9x/NT4) -// Only used for SMART commands not supported by SMART_* IOCTLs -// -// Based on WinATA.cpp, 2002 c't/Matthias Withopf -// ftp://ftp.heise.de/pub/ct/listings/0207-218.zip - -#define FILE_DEVICE_CONTROLLER 4 -#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER - -#define IOCTL_IDE_PASS_THROUGH \ - CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#pragma pack(1) - -typedef struct { - IDEREGS IdeReg; - ULONG DataBufferSize; - UCHAR DataBuffer[1]; -} ATA_PASS_THROUGH; - -#pragma pack() - - -///////////////////////////////////////////////////////////////////////////// - -static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize) -{ - 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; - assert(sizeof(ATA_PASS_THROUGH)-1 == 12); - assert(IOCTL_IDE_PASS_THROUGH == 0x04d028); - - buf->IdeReg = *regs; - buf->DataBufferSize = datasize; - -#ifdef _DEBUG - pout("DeviceIoControl(.,0x%x,.,%u,.,%u,.,NULL)\n", - IOCTL_IDE_PASS_THROUGH, size, size); - print_ide_regs(&buf->IdeReg, 0); -#endif - - if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH, - buf, size, buf, size, &num_out, NULL)) { - long err = GetLastError(); -#ifdef _DEBUG - pout("DeviceIoControl failed, Error=%ld\n", err); -#endif - VirtualFree(buf, size, MEM_RELEASE); - errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); - return -1; - } - -#ifdef _DEBUG - pout("DeviceIoControl returns %lu (%lu) bytes\n", num_out, buf->DataBufferSize); - print_ide_regs(&buf->IdeReg, 1); -#endif - - if (datasize) - memcpy(data, buf->DataBuffer, datasize); - VirtualFree(buf, size, MEM_RELEASE); - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// - -static HANDLE h_ata_ioctl = 0; -static int ide_pass_through_broken = 0; - - -// Print SMARTVSD error message, return errno - -static int smartvsd_error() -{ - char path[MAX_PATH]; - unsigned len; - if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2)) - return ENOENT; - strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD"); - if (!access(path, 0)) { -#ifdef _DEBUG - pout("Driver \"%s\" not loaded,\n" - " possibly no IDE/ATA devices present.\n", path); -#endif - return ENOENT; - } - // Some Windows versions install SMARTVSD.VXD in SYSTEM directory - // http://support.microsoft.com/default.aspx?scid=kb;en-us;265854 - strcpy(path+len, "\\SMARTVSD.VXD"); - if (!access(path, 0)) { - path[len] = 0; - pout("SMART driver is not properly installed,\n" - " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n" - " and reboot Windows.\n", path, path); - return ENOSYS; - } - path[len] = 0; - pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path); - return ENOENT; -} - - -static int ata_open(int drive) -{ - int win9x; - char devpath[30]; - GETVERSIONOUTPARAMS vers; - DWORD num_out; - - assert(SMART_GET_VERSION == 0x074080); - assert(sizeof(GETVERSIONOUTPARAMS) == 24); - - // TODO: This version does not allow to open more than 1 ATA devices - if (h_ata_ioctl) { - errno = ENFILE; - return -1; - } - - win9x = ((GetVersion() & 0x80000000) != 0); - - if (!(0 <= drive && drive <= (win9x ? 3 : 9))) { - errno = ENOENT; - return -1; - } - // path depends on Windows Version - if (win9x) - strcpy(devpath, "\\\\.\\SMARTVSD"); - else - snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", drive); - - // Open device - if ((h_ata_ioctl = CreateFileA(devpath, - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { - long err = GetLastError(); - pout("Cannot open device %s, Error=%ld\n", devpath, err); - if (win9x && err == ERROR_FILE_NOT_FOUND) - errno = smartvsd_error(); - else - errno = (err == ERROR_FILE_NOT_FOUND ? ENOENT : EPERM); - h_ata_ioctl = 0; - return -1; - } - - // Get drive map - memset(&vers, 0, sizeof(vers)); - if (!DeviceIoControl(h_ata_ioctl, SMART_GET_VERSION, - NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { - pout("%s: SMART_GET_VERSION failed, Error=%ld\n", devpath, GetLastError()); - if (!win9x) - pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n"); - if (!is_permissive()) { - CloseHandle(h_ata_ioctl); h_ata_ioctl = 0; - errno = ENOSYS; - return -1; - } - } - -#ifdef _DEBUG - pout("SMART_GET_VERSION (%ld bytes): Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n", - num_out, vers.bVersion, vers.bRevision, vers.fCapabilities, vers.bIDEDeviceMap); -#endif - - // TODO: Check vers.fCapabilities here? - - if (!win9x) - // NT4/2K/XP: Drive exists, Drive number not necessary for ioctl - return 0; - - // Win9x/ME: Check device presence & type - if (((vers.bIDEDeviceMap >> drive) & 0x11) != 0x01) { - unsigned char atapi = (vers.bIDEDeviceMap >> drive) & 0x10; - pout(( atapi - ? "Drive %d is an ATAPI device (IDEDeviceMap=0x%02x).\n" - : "Drive %d does not exist (IDEDeviceMap=0x%02x).\n"), - drive, vers.bIDEDeviceMap); - // Win9x Drive existence check may not work as expected - // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01 - // http://support.microsoft.com/support/kb/articles/Q196/1/20.ASP - if (!is_permissive()) { - CloseHandle(h_ata_ioctl); h_ata_ioctl = 0; - errno = (atapi ? ENOSYS : ENOENT); - return -1; - } - } - // Use drive number as fd for ioctl - return drive; -} - - -static void ata_close(int fd) -{ - ARGUSED(fd); - CloseHandle(h_ata_ioctl); - h_ata_ioctl = 0; -} - - -// Scan for ATA drives, return bitmask of drives present - -static unsigned ata_scan() -{ - unsigned drives = 0; - int win9x = ((GetVersion() & 0x80000000) != 0); - int i; - - for (i = 0; i <= 9; i++) { - char devpath[30]; - GETVERSIONOUTPARAMS vers; - DWORD num_out; - HANDLE h; - if (win9x) - strcpy(devpath, "\\\\.\\SMARTVSD"); - else - snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", i); - - // Open device - if ((h = CreateFileA(devpath, - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { - if (win9x) - break; // SMARTVSD.VXD missing or no ATA devices - continue; // Disk not found or access denied (break;?) - } - - // Get drive map - memset(&vers, 0, sizeof(vers)); - if (!DeviceIoControl(h, SMART_GET_VERSION, - NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { - CloseHandle(h); - if (win9x) - break; // Should not happen - continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk) - } - CloseHandle(h); - - if (win9x) { - // Check ATA device presence, remove ATAPI devices - drives = (vers.bIDEDeviceMap & 0xf) & ~((vers.bIDEDeviceMap >> 4) & 0xf); - break; - } - - // ATA drive exists and driver supports SMART ioctl - drives |= 1 << i; - } - - return drives; -} - - -///////////////////////////////////////////////////////////////////////////// - -// Interface to ATA devices. See os_linux.c -int ata_command_interface(int fd, smart_command_set command, int select, char * data) -{ - IDEREGS regs; - int copydata; - - if (!(0 <= fd && fd <= 3)) { - errno = EBADF; - return -1; - } - - // CMD,CYL default to SMART, changed by P?IDENTIFY - memset(®s, 0, sizeof(regs)); - regs.bCommandReg = ATA_SMART_CMD; - regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW; - copydata = 0; - - switch (command) { - case CHECK_POWER_MODE: - case WRITE_LOG: - // TODO. Not supported by SMART IOCTL - errno = ENOSYS; - return -1; - case READ_VALUES: - regs.bFeaturesReg = ATA_SMART_READ_VALUES; - regs.bSectorNumberReg = regs.bSectorCountReg = 1; - copydata = 1; - break; - case READ_THRESHOLDS: - regs.bFeaturesReg = ATA_SMART_READ_THRESHOLDS; - regs.bSectorNumberReg = regs.bSectorCountReg = 1; - copydata = 1; - break; - case READ_LOG: - regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR; - regs.bSectorNumberReg = select; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case IDENTIFY: - regs.bCommandReg = ATA_IDENTIFY_DEVICE; - regs.bCylLowReg = regs.bCylHighReg = 0; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case PIDENTIFY: - regs.bCommandReg = ATA_IDENTIFY_PACKET_DEVICE; - regs.bCylLowReg = regs.bCylHighReg = 0; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case ENABLE: - regs.bFeaturesReg = ATA_SMART_ENABLE; - regs.bSectorNumberReg = 1; - break; - case DISABLE: - regs.bFeaturesReg = ATA_SMART_DISABLE; - regs.bSectorNumberReg = 1; - break; - case STATUS: - case STATUS_CHECK: - regs.bFeaturesReg = ATA_SMART_STATUS; - break; - case AUTO_OFFLINE: - regs.bFeaturesReg = ATA_SMART_AUTO_OFFLINE; - regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! - break; - case AUTOSAVE: - regs.bFeaturesReg = ATA_SMART_AUTOSAVE; - regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! - break; - case IMMEDIATE_OFFLINE: - regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE; - regs.bSectorNumberReg = select; - break; - default: - pout("Unrecognized command %d in win32_ata_command_interface()\n" - "Please contact " PACKAGE_BUGREPORT "\n", command); - errno = ENOSYS; - return -1; - } - - if (smart_ioctl(h_ata_ioctl, fd, ®s, data, (copydata?512:0))) { - // Read log only supported on Win9x, retry with pass through command - // CAUTION: smart_ioctl() MUST NOT change "regs" Parameter in this case - if (errno == ENOSYS && command == READ_LOG && !ide_pass_through_broken) { - errno = 0; - memset(data, 0, 512); - if (ide_pass_through_ioctl(h_ata_ioctl, ®s, data, 512)) - return -1; - if (!nonempty(data, 512)) { - // Nothing useful returned => ioctl probably broken - pout("IOCTL_IDE_PASS_THROUGH does not work on your version of Windows\n"); - ide_pass_through_broken = 1; // Do not retry (smartd) - errno = ENOSYS; - return -1; - } - return 0; - } - return -1; - } - - if (command == STATUS_CHECK) { - // Cyl low and Cyl high unchanged means "Good SMART status" - if (regs.bCylHighReg == SMART_CYL_HI && regs.bCylLowReg == SMART_CYL_LOW) - return 0; - - // These values mean "Bad SMART status" - if (regs.bCylHighReg == 0x2c && regs.bCylLowReg == 0xf4) - 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_HOMEPAGE); - print_ide_regs(®s, 1); - errno = EIO; - return -1; - } - - return 0; -} - - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) -{ - static int warned = 0; - ARGUSED(fd); ARGUSED(disknum); ARGUSED(escalade_type); ARGUSED(command); ARGUSED(select); ARGUSED(data); - if (!warned) { - pout( - "#######################################################################\n" - "3ware Escalade Controller command routine escalade_command_interface()\n" - "NOT IMPLEMENTED under Win32.\n" - "Please contact " PACKAGE_BUGREPORT " if\n" - "you want to help in porting smartmontools to Win32.\n" - "#######################################################################\n" - "\n"); - warned = 1; - } - errno = ENOSYS; - return -1; -} - - -///////////////////////////////////////////////////////////////////////////// -// ASPI Interface -///////////////////////////////////////////////////////////////////////////// - -#pragma pack(1) - -#define ASPI_SENSE_SIZE 18 - -// ASPI SCSI Request block header - -typedef struct { - unsigned char cmd; // 00: Command code - unsigned char status; // 01: ASPI status - unsigned char adapter; // 02: Host adapter number - unsigned char flags; // 03: Request flags - unsigned char reserved[4]; // 04: 0 -} ASPI_SRB_HEAD; - -// SRB for host adapter inquiry - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char adapters; // 08: Number of adapters - unsigned char target_id; // 09: Target ID ? - char manager_id[16]; // 10: SCSI manager ID - char adapter_id[16]; // 26: Host adapter ID - unsigned char parameters[16]; // 42: Host adapter unique parmameters -} ASPI_SRB_INQUIRY; - -// SRB for get device type - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char target_id; // 08: Target ID - unsigned char lun; // 09: LUN - unsigned char devtype; // 10: Device type - unsigned char reserved; // 11: Reserved -} ASPI_SRB_DEVTYPE; - -// SRB for SCSI I/O - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char target_id; // 08: Target ID - unsigned char lun; // 09: LUN - unsigned char reserved[2]; // 10: Reserved - unsigned long data_size; // 12: Data alloc. lenght - void * data_addr; // 16: Data buffer pointer - unsigned char sense_size; // 20: Sense alloc. length - unsigned char cdb_size; // 21: CDB length - unsigned char host_status; // 22: Host status - unsigned char target_status; // 23: Target status - void * event_handle; // 24: Event handle - unsigned char workspace[20]; // 28: ASPI workspace - unsigned char cdb[16+ASPI_SENSE_SIZE]; -} ASPI_SRB_IO; - -// Macro to retrieve start of sense information -#define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16) - -// SRB union - -typedef union { - ASPI_SRB_HEAD h; // Common header - ASPI_SRB_INQUIRY q; // Inquiry - ASPI_SRB_DEVTYPE t; // Device type - ASPI_SRB_IO i; // I/O -} ASPI_SRB; - -#pragma pack() - -// ASPI commands -#define ASPI_CMD_ADAPTER_INQUIRE 0x00 -#define ASPI_CMD_GET_DEVICE_TYPE 0x01 -#define ASPI_CMD_EXECUTE_IO 0x02 -#define ASPI_CMD_ABORT_IO 0x03 - -// Request flags -#define ASPI_REQFLAG_DIR_TO_HOST 0x08 -#define ASPI_REQFLAG_DIR_TO_TARGET 0x10 -#define ASPI_REQFLAG_DIR_NO_XFER 0x18 -#define ASPI_REQFLAG_EVENT_NOTIFY 0x40 - -// ASPI status -#define ASPI_STATUS_IN_PROGRESS 0x00 -#define ASPI_STATUS_NO_ERROR 0x01 -#define ASPI_STATUS_ABORTED 0x02 -#define ASPI_STATUS_ABORT_ERR 0x03 -#define ASPI_STATUS_ERROR 0x04 -#define ASPI_STATUS_INVALID_COMMAND 0x80 -#define ASPI_STATUS_INVALID_ADAPTER 0x81 -#define ASPI_STATUS_INVALID_TARGET 0x82 -#define ASPI_STATUS_NO_ADAPTERS 0xE8 - -// Adapter (host) status -#define ASPI_HSTATUS_NO_ERROR 0x00 -#define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11 -#define ASPI_HSTATUS_DATA_OVERRUN 0x12 -#define ASPI_HSTATUS_BUS_FREE 0x13 -#define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14 -#define ASPI_HSTATUS_BAD_SGLIST 0x1A - -// Target status -#define ASPI_TSTATUS_NO_ERROR 0x00 -#define ASPI_TSTATUS_CHECK_CONDITION 0x02 -#define ASPI_TSTATUS_BUSY 0x08 -#define ASPI_TSTATUS_RESERV_CONFLICT 0x18 - - -static HINSTANCE h_aspi_dll; // DLL handle -static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint -static unsigned num_aspi_adapters; - -#ifdef __CYGWIN__ -// h_aspi_dll+aspi_entry is not inherited by Cygwin's fork() -static DWORD aspi_dll_pid; // PID of DLL owner to detect fork() -#define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId())) -#else -#define aspi_entry_valid() (!!aspi_entry) -#endif - - -static int aspi_call(ASPI_SRB * srb) -{ - int i; - aspi_entry(srb); - i = 0; - while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) { - if (++i > 100/*10sek*/) { - pout("ASPI Adapter %u: Timeout\n", srb->h.adapter); - aspi_entry = 0; - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = EIO; - return -1; - } -#ifdef _DEBUG - pout("ASPI Wait %d\n", i); -#endif - Sleep(100); - } - return 0; -} - - -// Get ASPI entrypoint from wnaspi32.dll - -static FARPROC aspi_get_address(const char * name, int verbose) -{ - FARPROC addr; - assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE); - - if (!(addr = GetProcAddress(h_aspi_dll, name))) { - if (verbose) - pout("Missing %s() in WNASPI32.DLL\n", name); - aspi_entry = 0; - FreeLibrary(h_aspi_dll); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOSYS; - return 0; - } - return addr; -} - - -static int aspi_open_dll(int verbose) -{ - UINT (*aspi_info)(void); - UINT info, rc; - - assert(!aspi_entry_valid()); - - // Check structure layout - assert(sizeof(ASPI_SRB_HEAD) == 8); - assert(sizeof(ASPI_SRB_INQUIRY) == 58); - assert(sizeof(ASPI_SRB_DEVTYPE) == 12); - assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE); - assert(offsetof(ASPI_SRB,h.cmd) == 0); - assert(offsetof(ASPI_SRB,h.flags) == 3); - assert(offsetof(ASPI_SRB_IO,lun) == 9); - assert(offsetof(ASPI_SRB_IO,data_addr) == 16); - assert(offsetof(ASPI_SRB_IO,workspace) == 28); - assert(offsetof(ASPI_SRB_IO,cdb) == 48); - - if (h_aspi_dll == INVALID_HANDLE_VALUE) { - // do not retry - errno = ENOENT; - return -1; - } - - // Load ASPI DLL - if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) { - if (verbose) - pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError()); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOENT; - return -1; - } - - // Get ASPI entrypoints - if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose))) - return -1; - if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose))) - return -1; - - // Init ASPI manager and get number of adapters - info = (aspi_info)(); -#ifdef _DEBUG - pout("GetASPI32SupportInfo() returns 0x%04x\n", info); -#endif - rc = (info >> 8) & 0xff; - if (rc == ASPI_STATUS_NO_ADAPTERS) { - num_aspi_adapters = 0; - } - else if (rc == ASPI_STATUS_NO_ERROR) { - num_aspi_adapters = info & 0xff; - } - else { - if (verbose) - pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info); - aspi_entry = 0; - FreeLibrary(h_aspi_dll); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOENT; - return -1; - } - -#ifdef __CYGWIN__ - // save PID to detect fork() in aspi_entry_valid() - aspi_dll_pid = GetCurrentProcessId(); -#endif - assert(aspi_entry_valid()); - return 0; -} - - -static int aspi_io_call(ASPI_SRB * srb) -{ - HANDLE event; - // Create event - if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) { - pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO; - } - srb->i.event_handle = event; - srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY; - // Start ASPI request - aspi_entry(srb); - if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) { - // Wait for event - DWORD rc = WaitForSingleObject(event, 30*1000L); - if (rc != WAIT_OBJECT_0) { - if (rc == WAIT_TIMEOUT) { - pout("ASPI Timeout\n"); - } - else { - pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n", - (unsigned long)event, rc, rc, GetLastError()); - } - // TODO: ASPI_ABORT_IO command - aspi_entry = 0; - h_aspi_dll = INVALID_HANDLE_VALUE; - return -EIO; - } - } - CloseHandle(event); - return 0; -} - - -static int aspi_open(unsigned adapter, unsigned id) -{ - if (!(adapter <= 9 && id < 16)) { - errno = ENOENT; - return -1; - } - - if (!aspi_entry_valid()) { - if (aspi_open_dll(1/*verbose*/)) - return -1; - } - - // Adapter OK? - if (adapter >= num_aspi_adapters) { - pout("ASPI Adapter %d does not exist (%d Adapter(s) detected).\n", adapter, num_aspi_adapters); - if (!is_permissive()) { - errno = ENOENT; - return -1; - } - } - - return (0x0100 | ((adapter & 0xf)<<4) | (id & 0xf)); -} - - -static void aspi_close(int fd) -{ - // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads - ARGUSED(fd); -} - - -// Scan for SCSI drives, return bitmask [adapter:0-3][id:0-7] of drives present - -static unsigned long aspi_scan() -{ - unsigned long drives = 0; - unsigned ad, nad; - - if (!aspi_entry_valid()) { - if (aspi_open_dll(0/*quiet*/)) - return 0; - } - - nad = num_aspi_adapters; - if (nad >= 4) - nad = 4; - for (ad = 0; ad < nad; ad++) { - ASPI_SRB srb; int id; - // Get adapter name - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE; - srb.h.adapter = ad; - if (aspi_call(&srb)) - return 0; -#ifdef _DEBUG - pout("ASPI Adapter %u: %02x,\"%.16s\"\n", ad, srb.h.status, srb.q.adapter_id); -#endif - if (srb.h.status != ASPI_STATUS_NO_ERROR) - continue; - - // Skip ATA/ATAPI devices - srb.q.adapter_id[sizeof(srb.q.adapter_id)-1] = 0; - if (strstr(srb.q.adapter_id, "ATAPI")) - continue; - - for (id = 0; id <= 7; id++) { - // Get device type - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE; - srb.h.adapter = ad; srb.i.target_id = id; - if (aspi_call(&srb)) - return 0; -#ifdef _DEBUG - pout("Device type for scsi%u%x: %02x,%02x\n", ad, id, srb.h.status, srb.t.devtype); -#endif - if (srb.h.status == ASPI_STATUS_NO_ERROR && srb.t.devtype == 0x00/*HDD*/) - drives |= 1 << ((ad<<3)+id); - } - } - return drives; -} - - -///////////////////////////////////////////////////////////////////////////// - -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) -{ - ASPI_SRB srb; - - if (!aspi_entry_valid()) - return -EBADF; - if (!((fd & ~0xff) == 0x100)) - return -EBADF; - - if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12)) { - pout("do_scsi_cmnd_io: bad CDB length\n"); - return -EINVAL; - } - - if (report > 0) { - // From os_linux.c - 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(buff); - } - - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_EXECUTE_IO; - srb.h.adapter = ((fd >> 4) & 0xf); - srb.i.target_id = (fd & 0xf); - //srb.i.lun = 0; - srb.i.sense_size = ASPI_SENSE_SIZE; - srb.i.cdb_size = iop->cmnd_len; - memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len); - - switch (iop->dxfer_dir) { - case DXFER_NONE: - srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER; - break; - case DXFER_FROM_DEVICE: - srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST; - srb.i.data_size = iop->dxfer_len; - srb.i.data_addr = iop->dxferp; - break; - case DXFER_TO_DEVICE: - srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET; - srb.i.data_size = iop->dxfer_len; - srb.i.data_addr = iop->dxferp; - 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 (aspi_io_call(&srb)) { - // Timeout - return -EIO; - } - - if (srb.h.status != ASPI_STATUS_NO_ERROR) { - if ( srb.h.status == ASPI_STATUS_ERROR - && srb.i.host_status == ASPI_HSTATUS_NO_ERROR - && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) { - // Sense valid - const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len); - int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len); - iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; - if (len > 0 && iop->sensep) { - memcpy(iop->sensep, sense, len); - iop->resp_sense_len = len; - if (report > 1) { - pout(" >>> Sense buffer, len=%d:\n", (int)len); - dStrHex(iop->sensep, len , 1); - } - } - if (report) { - pout(" sense_key=%x asc=%x ascq=%x\n", - sense[2] & 0xf, sense[12], sense[13]); - } - return 0; - } - else { - if (report) - pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status); - return -EIO; - } - } - - if (report > 0) - pout(" OK\n"); - - 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; -} diff --git a/sm5/os_win32.cpp b/sm5/os_win32.cpp deleted file mode 100644 index c21b201d1ed2cac78ccc60820e206d4619e1331c..0000000000000000000000000000000000000000 --- a/sm5/os_win32.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * os_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "config.h" -#include "atacmds.h" -#include "extern.h" -extern smartmonctrl * con; // con->permissive -#include "int64.h" -#include "scsicmds.h" -#include "utility.h" -extern int64_t bytes; // malloc() byte count - -#include <errno.h> -#ifdef _DEBUG -#include <assert.h> -#else -#define assert(x) /**/ -#endif -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <stddef.h> // offsetof() -#include <io.h> // access() - -#define ARGUSED(x) ((void)(x)) - -// Needed by '-V' option (CVS versioning) of smartd/smartctl -const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.16 2004/08/13 13:57:12 arvoreen Exp $" -ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - - -static int ata_open(int drive); -static void ata_close(int fd); -static unsigned ata_scan(void); - -static int aspi_open(unsigned adapter, unsigned id); -static void aspi_close(int fd); -static unsigned long aspi_scan(void); - - -static int is_permissive() -{ - if (con->permissive <= 0) { - pout("To continue, add one or more '-T permissive' options.\n"); - return 0; - } - con->permissive--; - return 1; -} - -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) -{ - 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 -// others each contain null-terminated character strings. -int make_device_names (char*** devlist, const char* type) -{ - unsigned long drives; - int i, j, n, sz, scsi; - const char * path; - - if (!strcmp(type, "ATA")) { - // bit i set => drive i present - drives = ata_scan(); - path = "/dev/hda"; - scsi = 0; - } - else if (!strcmp(type, "SCSI")) { - // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present - drives = aspi_scan(); - path = "/dev/scsi00"; - scsi = 1; - } - else - return -1; - - if (!drives) - return 0; - - // Count #drives - n = 0; - for (i = 0; i < 32; i++) { - if (drives & (1 << i)) - n++; - } - assert(n > 0); - if (n == 0) - return 0; - - // Alloc devlist - assert(scsi || n <= 9); - sz = n * sizeof(char **); - *devlist = (char **)malloc(sz); bytes += sz; - - // Add devices - for (i = j = 0; i < n; i++) { - char * s; - sz = strlen(path)+1; - s = (char *)malloc(sz); bytes += sz; - strcpy(s, path); - while (j < 32 && !(drives & (1 << j))) - j++; - assert(j < 32); - if (!scsi) { - assert(j <= 9); - s[sz-2] += j; // /dev/hd[a-j] - } - else { - s[sz-3] += (j >> 3); // /dev/scsi[0-3]. - s[sz-2] += (j & 0x7); // .....[0-7] - } - (*devlist)[i] = s; - j++; - } - return n; -} - - -// Like open(). Return positive integer handle, only used by -// 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.c for an example). -int deviceopen(const char * pathname, char *type) -{ - int len; - pathname = skipdev(pathname); - len = strlen(pathname); - - if (!strcmp(type, "ATA")) { - // hd[a-z] => ATA 0-9 - if (!(len == 3 && pathname[0] == 'h' && pathname[1] == 'd' - && 'a' <= pathname[2] && pathname[2] <= 'j')) { - errno = ENOENT; - return -1; - } - return ata_open(pathname[2] - 'a'); - } - - if (!strcmp(type, "SCSI")) { - // scsi[0-9][0-f] => SCSI Adapter 0-9, ID 0-15, LUN 0 - unsigned adapter = ~0, id = ~0; int n = -1; - if (!(sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n) == 2 && n == len)) { - errno = ENOENT; - return -1; - } - return aspi_open(adapter, id); - } - errno = ENOENT; - return -1; -} - - -// Like close(). Acts only on handles returned by above function. -// (Never called in smartctl!) -int deviceclose(int fd) -{ - if (fd < 0x100) { - ata_close(fd); - } - else { - aspi_close(fd); - } - return 0; -} - - -// print examples for smartctl -void print_smartctl_examples(){ - printf("=================================================== SMARTCTL EXAMPLES =====\n\n" - " smartctl -a /dev/hda (Prints all SMART information)\n\n" -#ifdef HAVE_GETOPT_LONG - " 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" -#else - " 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" -#endif - " smartctl -a /dev/scsi21\n" - " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n" - ); -} - - -///////////////////////////////////////////////////////////////////////////// -// ATA Interface -///////////////////////////////////////////////////////////////////////////// - -// SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection) - -// Deklarations from: -// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntdddisk.h?rev=1.3 - -#define FILE_READ_ACCESS 0x0001 -#define FILE_WRITE_ACCESS 0x0002 -#define METHOD_BUFFERED 0 -#define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) - -#define FILE_DEVICE_DISK 7 -#define IOCTL_DISK_BASE FILE_DEVICE_DISK - -#define SMART_GET_VERSION \ - CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define SMART_RCV_DRIVE_DATA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define SMART_SEND_DRIVE_COMMAND \ - CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define SMART_CYL_LOW 0x4F -#define SMART_CYL_HI 0xC2 - -#pragma pack(1) - -typedef struct _GETVERSIONOUTPARAMS { - UCHAR bVersion; - UCHAR bRevision; - UCHAR bReserved; - UCHAR bIDEDeviceMap; - ULONG fCapabilities; - ULONG dwReserved[4]; -} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS; - -typedef struct _IDEREGS { - UCHAR bFeaturesReg; - UCHAR bSectorCountReg; - UCHAR bSectorNumberReg; - UCHAR bCylLowReg; - UCHAR bCylHighReg; - UCHAR bDriveHeadReg; - UCHAR bCommandReg; - UCHAR bReserved; -} IDEREGS, *PIDEREGS, *LPIDEREGS; - -typedef struct _SENDCMDINPARAMS { - ULONG cBufferSize; - IDEREGS irDriveRegs; - UCHAR bDriveNumber; - UCHAR bReserved[3]; - ULONG dwReserved[4]; - UCHAR bBuffer[1]; -} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; - -/* DRIVERSTATUS.bDriverError constants (just for info, not used) -#define SMART_NO_ERROR 0 -#define SMART_IDE_ERROR 1 -#define SMART_INVALID_FLAG 2 -#define SMART_INVALID_COMMAND 3 -#define SMART_INVALID_BUFFER 4 -#define SMART_INVALID_DRIVE 5 -#define SMART_INVALID_IOCTL 6 -#define SMART_ERROR_NO_MEM 7 -#define SMART_INVALID_REGISTER 8 -#define SMART_NOT_SUPPORTED 9 -#define SMART_NO_IDE_DEVICE 10 -*/ - -typedef struct _DRIVERSTATUS { - UCHAR bDriverError; - UCHAR bIDEError; - UCHAR bReserved[2]; - ULONG dwReserved[2]; -} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; - -typedef struct _SENDCMDOUTPARAMS { - ULONG cBufferSize; - DRIVERSTATUS DriverStatus; - UCHAR bBuffer[1]; -} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; - -#pragma pack() - - -///////////////////////////////////////////////////////////////////////////// - -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); -} - - -///////////////////////////////////////////////////////////////////////////// - -// call SMART_* ioctl - -static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize) -{ - SENDCMDINPARAMS inpar; - unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512]; - const SENDCMDOUTPARAMS * outpar; - DWORD code, num_out; - unsigned int size_out; - - assert(SMART_SEND_DRIVE_COMMAND == 0x07c084); - assert(SMART_RCV_DRIVE_DATA == 0x07c088); - assert(sizeof(SENDCMDINPARAMS)-1 == 32); - assert(sizeof(SENDCMDOUTPARAMS)-1 == 16); - - memset(&inpar, 0, sizeof(inpar)); - inpar.irDriveRegs = *regs; - // drive is set to 0-3 on Win9x only - inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4); - inpar.bDriveNumber = drive; - - assert(datasize == 0 || datasize == 512); - if (datasize) { - inpar.cBufferSize = size_out = 512; - code = SMART_RCV_DRIVE_DATA; - } - else if (regs->bFeaturesReg == ATA_SMART_STATUS) { - size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data - code = SMART_SEND_DRIVE_COMMAND; - } - else { - size_out = 0; - code = SMART_SEND_DRIVE_COMMAND; - } - - memset(&outbuf, 0, sizeof(outbuf)); - -#ifdef _DEBUG - pout("DeviceIoControl(.,0x%lx,.,%lu,.,%lu,.,NULL)\n", - code, sizeof(SENDCMDINPARAMS)-1, sizeof(SENDCMDOUTPARAMS)-1 + size_out); - print_ide_regs(&inpar.irDriveRegs, 0); -#endif - 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 ata_command_interface() - long err = GetLastError(); -#ifdef _DEBUG - pout("DeviceIoControl failed, Error=%ld\n", err); -#endif - errno = ( err == ERROR_INVALID_FUNCTION /*9x*/ - || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO); - return -1; - } - // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs - - outpar = (const SENDCMDOUTPARAMS *)outbuf; -#ifdef _DEBUG - pout("DeviceIoControl returns %lu (%lu) bytes\n", num_out, outpar->cBufferSize); -#endif - - if (outpar->DriverStatus.bDriverError) { - pout("Error SMART IOCTL DriverError=0x%02x, IDEError=0x%02x\n", - outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError); - errno = EIO; - return -1; - } - - if (datasize) - memcpy(data, outpar->bBuffer, 512); - else if (regs->bFeaturesReg == ATA_SMART_STATUS) { - *regs = *(const IDEREGS *)(outpar->bBuffer); -#ifdef _DEBUG - print_ide_regs(regs, 1); -#endif - } - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// - -// IDE PASS THROUGH for W2K/XP (does not work on W9x/NT4) -// Only used for SMART commands not supported by SMART_* IOCTLs -// -// Based on WinATA.cpp, 2002 c't/Matthias Withopf -// ftp://ftp.heise.de/pub/ct/listings/0207-218.zip - -#define FILE_DEVICE_CONTROLLER 4 -#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER - -#define IOCTL_IDE_PASS_THROUGH \ - CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#pragma pack(1) - -typedef struct { - IDEREGS IdeReg; - ULONG DataBufferSize; - UCHAR DataBuffer[1]; -} ATA_PASS_THROUGH; - -#pragma pack() - - -///////////////////////////////////////////////////////////////////////////// - -static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize) -{ - 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; - assert(sizeof(ATA_PASS_THROUGH)-1 == 12); - assert(IOCTL_IDE_PASS_THROUGH == 0x04d028); - - buf->IdeReg = *regs; - buf->DataBufferSize = datasize; - -#ifdef _DEBUG - pout("DeviceIoControl(.,0x%x,.,%u,.,%u,.,NULL)\n", - IOCTL_IDE_PASS_THROUGH, size, size); - print_ide_regs(&buf->IdeReg, 0); -#endif - - if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH, - buf, size, buf, size, &num_out, NULL)) { - long err = GetLastError(); -#ifdef _DEBUG - pout("DeviceIoControl failed, Error=%ld\n", err); -#endif - VirtualFree(buf, size, MEM_RELEASE); - errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); - return -1; - } - -#ifdef _DEBUG - pout("DeviceIoControl returns %lu (%lu) bytes\n", num_out, buf->DataBufferSize); - print_ide_regs(&buf->IdeReg, 1); -#endif - - if (datasize) - memcpy(data, buf->DataBuffer, datasize); - VirtualFree(buf, size, MEM_RELEASE); - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// - -static HANDLE h_ata_ioctl = 0; -static int ide_pass_through_broken = 0; - - -// Print SMARTVSD error message, return errno - -static int smartvsd_error() -{ - char path[MAX_PATH]; - unsigned len; - if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2)) - return ENOENT; - strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD"); - if (!access(path, 0)) { -#ifdef _DEBUG - pout("Driver \"%s\" not loaded,\n" - " possibly no IDE/ATA devices present.\n", path); -#endif - return ENOENT; - } - // Some Windows versions install SMARTVSD.VXD in SYSTEM directory - // http://support.microsoft.com/default.aspx?scid=kb;en-us;265854 - strcpy(path+len, "\\SMARTVSD.VXD"); - if (!access(path, 0)) { - path[len] = 0; - pout("SMART driver is not properly installed,\n" - " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n" - " and reboot Windows.\n", path, path); - return ENOSYS; - } - path[len] = 0; - pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path); - return ENOENT; -} - - -static int ata_open(int drive) -{ - int win9x; - char devpath[30]; - GETVERSIONOUTPARAMS vers; - DWORD num_out; - - assert(SMART_GET_VERSION == 0x074080); - assert(sizeof(GETVERSIONOUTPARAMS) == 24); - - // TODO: This version does not allow to open more than 1 ATA devices - if (h_ata_ioctl) { - errno = ENFILE; - return -1; - } - - win9x = ((GetVersion() & 0x80000000) != 0); - - if (!(0 <= drive && drive <= (win9x ? 3 : 9))) { - errno = ENOENT; - return -1; - } - // path depends on Windows Version - if (win9x) - strcpy(devpath, "\\\\.\\SMARTVSD"); - else - snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", drive); - - // Open device - if ((h_ata_ioctl = CreateFileA(devpath, - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { - long err = GetLastError(); - pout("Cannot open device %s, Error=%ld\n", devpath, err); - if (win9x && err == ERROR_FILE_NOT_FOUND) - errno = smartvsd_error(); - else - errno = (err == ERROR_FILE_NOT_FOUND ? ENOENT : EPERM); - h_ata_ioctl = 0; - return -1; - } - - // Get drive map - memset(&vers, 0, sizeof(vers)); - if (!DeviceIoControl(h_ata_ioctl, SMART_GET_VERSION, - NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { - pout("%s: SMART_GET_VERSION failed, Error=%ld\n", devpath, GetLastError()); - if (!win9x) - pout("If this is a SCSI disk, try \"scsi<adapter><id>\".\n"); - if (!is_permissive()) { - CloseHandle(h_ata_ioctl); h_ata_ioctl = 0; - errno = ENOSYS; - return -1; - } - } - -#ifdef _DEBUG - pout("SMART_GET_VERSION (%ld bytes): Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n", - num_out, vers.bVersion, vers.bRevision, vers.fCapabilities, vers.bIDEDeviceMap); -#endif - - // TODO: Check vers.fCapabilities here? - - if (!win9x) - // NT4/2K/XP: Drive exists, Drive number not necessary for ioctl - return 0; - - // Win9x/ME: Check device presence & type - if (((vers.bIDEDeviceMap >> drive) & 0x11) != 0x01) { - unsigned char atapi = (vers.bIDEDeviceMap >> drive) & 0x10; - pout(( atapi - ? "Drive %d is an ATAPI device (IDEDeviceMap=0x%02x).\n" - : "Drive %d does not exist (IDEDeviceMap=0x%02x).\n"), - drive, vers.bIDEDeviceMap); - // Win9x Drive existence check may not work as expected - // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01 - // http://support.microsoft.com/support/kb/articles/Q196/1/20.ASP - if (!is_permissive()) { - CloseHandle(h_ata_ioctl); h_ata_ioctl = 0; - errno = (atapi ? ENOSYS : ENOENT); - return -1; - } - } - // Use drive number as fd for ioctl - return drive; -} - - -static void ata_close(int fd) -{ - ARGUSED(fd); - CloseHandle(h_ata_ioctl); - h_ata_ioctl = 0; -} - - -// Scan for ATA drives, return bitmask of drives present - -static unsigned ata_scan() -{ - unsigned drives = 0; - int win9x = ((GetVersion() & 0x80000000) != 0); - int i; - - for (i = 0; i <= 9; i++) { - char devpath[30]; - GETVERSIONOUTPARAMS vers; - DWORD num_out; - HANDLE h; - if (win9x) - strcpy(devpath, "\\\\.\\SMARTVSD"); - else - snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", i); - - // Open device - if ((h = CreateFileA(devpath, - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { - if (win9x) - break; // SMARTVSD.VXD missing or no ATA devices - continue; // Disk not found or access denied (break;?) - } - - // Get drive map - memset(&vers, 0, sizeof(vers)); - if (!DeviceIoControl(h, SMART_GET_VERSION, - NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { - CloseHandle(h); - if (win9x) - break; // Should not happen - continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk) - } - CloseHandle(h); - - if (win9x) { - // Check ATA device presence, remove ATAPI devices - drives = (vers.bIDEDeviceMap & 0xf) & ~((vers.bIDEDeviceMap >> 4) & 0xf); - break; - } - - // ATA drive exists and driver supports SMART ioctl - drives |= 1 << i; - } - - return drives; -} - - -///////////////////////////////////////////////////////////////////////////// - -// Interface to ATA devices. See os_linux.c -int ata_command_interface(int fd, smart_command_set command, int select, char * data) -{ - IDEREGS regs; - int copydata; - - if (!(0 <= fd && fd <= 3)) { - errno = EBADF; - return -1; - } - - // CMD,CYL default to SMART, changed by P?IDENTIFY - memset(®s, 0, sizeof(regs)); - regs.bCommandReg = ATA_SMART_CMD; - regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW; - copydata = 0; - - switch (command) { - case CHECK_POWER_MODE: - case WRITE_LOG: - // TODO. Not supported by SMART IOCTL - errno = ENOSYS; - return -1; - case READ_VALUES: - regs.bFeaturesReg = ATA_SMART_READ_VALUES; - regs.bSectorNumberReg = regs.bSectorCountReg = 1; - copydata = 1; - break; - case READ_THRESHOLDS: - regs.bFeaturesReg = ATA_SMART_READ_THRESHOLDS; - regs.bSectorNumberReg = regs.bSectorCountReg = 1; - copydata = 1; - break; - case READ_LOG: - regs.bFeaturesReg = ATA_SMART_READ_LOG_SECTOR; - regs.bSectorNumberReg = select; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case IDENTIFY: - regs.bCommandReg = ATA_IDENTIFY_DEVICE; - regs.bCylLowReg = regs.bCylHighReg = 0; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case PIDENTIFY: - regs.bCommandReg = ATA_IDENTIFY_PACKET_DEVICE; - regs.bCylLowReg = regs.bCylHighReg = 0; - regs.bSectorCountReg = 1; - copydata = 1; - break; - case ENABLE: - regs.bFeaturesReg = ATA_SMART_ENABLE; - regs.bSectorNumberReg = 1; - break; - case DISABLE: - regs.bFeaturesReg = ATA_SMART_DISABLE; - regs.bSectorNumberReg = 1; - break; - case STATUS: - case STATUS_CHECK: - regs.bFeaturesReg = ATA_SMART_STATUS; - break; - case AUTO_OFFLINE: - regs.bFeaturesReg = ATA_SMART_AUTO_OFFLINE; - regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! - break; - case AUTOSAVE: - regs.bFeaturesReg = ATA_SMART_AUTOSAVE; - regs.bSectorCountReg = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! - break; - case IMMEDIATE_OFFLINE: - regs.bFeaturesReg = ATA_SMART_IMMEDIATE_OFFLINE; - regs.bSectorNumberReg = select; - break; - default: - pout("Unrecognized command %d in win32_ata_command_interface()\n" - "Please contact " PACKAGE_BUGREPORT "\n", command); - errno = ENOSYS; - return -1; - } - - if (smart_ioctl(h_ata_ioctl, fd, ®s, data, (copydata?512:0))) { - // Read log only supported on Win9x, retry with pass through command - // CAUTION: smart_ioctl() MUST NOT change "regs" Parameter in this case - if (errno == ENOSYS && command == READ_LOG && !ide_pass_through_broken) { - errno = 0; - memset(data, 0, 512); - if (ide_pass_through_ioctl(h_ata_ioctl, ®s, data, 512)) - return -1; - if (!nonempty(data, 512)) { - // Nothing useful returned => ioctl probably broken - pout("IOCTL_IDE_PASS_THROUGH does not work on your version of Windows\n"); - ide_pass_through_broken = 1; // Do not retry (smartd) - errno = ENOSYS; - return -1; - } - return 0; - } - return -1; - } - - if (command == STATUS_CHECK) { - // Cyl low and Cyl high unchanged means "Good SMART status" - if (regs.bCylHighReg == SMART_CYL_HI && regs.bCylLowReg == SMART_CYL_LOW) - return 0; - - // These values mean "Bad SMART status" - if (regs.bCylHighReg == 0x2c && regs.bCylLowReg == 0xf4) - 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_HOMEPAGE); - print_ide_regs(®s, 1); - errno = EIO; - return -1; - } - - return 0; -} - - -// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c -int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) -{ - static int warned = 0; - ARGUSED(fd); ARGUSED(disknum); ARGUSED(escalade_type); ARGUSED(command); ARGUSED(select); ARGUSED(data); - if (!warned) { - pout( - "#######################################################################\n" - "3ware Escalade Controller command routine escalade_command_interface()\n" - "NOT IMPLEMENTED under Win32.\n" - "Please contact " PACKAGE_BUGREPORT " if\n" - "you want to help in porting smartmontools to Win32.\n" - "#######################################################################\n" - "\n"); - warned = 1; - } - errno = ENOSYS; - return -1; -} - - -///////////////////////////////////////////////////////////////////////////// -// ASPI Interface -///////////////////////////////////////////////////////////////////////////// - -#pragma pack(1) - -#define ASPI_SENSE_SIZE 18 - -// ASPI SCSI Request block header - -typedef struct { - unsigned char cmd; // 00: Command code - unsigned char status; // 01: ASPI status - unsigned char adapter; // 02: Host adapter number - unsigned char flags; // 03: Request flags - unsigned char reserved[4]; // 04: 0 -} ASPI_SRB_HEAD; - -// SRB for host adapter inquiry - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char adapters; // 08: Number of adapters - unsigned char target_id; // 09: Target ID ? - char manager_id[16]; // 10: SCSI manager ID - char adapter_id[16]; // 26: Host adapter ID - unsigned char parameters[16]; // 42: Host adapter unique parmameters -} ASPI_SRB_INQUIRY; - -// SRB for get device type - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char target_id; // 08: Target ID - unsigned char lun; // 09: LUN - unsigned char devtype; // 10: Device type - unsigned char reserved; // 11: Reserved -} ASPI_SRB_DEVTYPE; - -// SRB for SCSI I/O - -typedef struct { - ASPI_SRB_HEAD h; // 00: Header - unsigned char target_id; // 08: Target ID - unsigned char lun; // 09: LUN - unsigned char reserved[2]; // 10: Reserved - unsigned long data_size; // 12: Data alloc. lenght - void * data_addr; // 16: Data buffer pointer - unsigned char sense_size; // 20: Sense alloc. length - unsigned char cdb_size; // 21: CDB length - unsigned char host_status; // 22: Host status - unsigned char target_status; // 23: Target status - void * event_handle; // 24: Event handle - unsigned char workspace[20]; // 28: ASPI workspace - unsigned char cdb[16+ASPI_SENSE_SIZE]; -} ASPI_SRB_IO; - -// Macro to retrieve start of sense information -#define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16) - -// SRB union - -typedef union { - ASPI_SRB_HEAD h; // Common header - ASPI_SRB_INQUIRY q; // Inquiry - ASPI_SRB_DEVTYPE t; // Device type - ASPI_SRB_IO i; // I/O -} ASPI_SRB; - -#pragma pack() - -// ASPI commands -#define ASPI_CMD_ADAPTER_INQUIRE 0x00 -#define ASPI_CMD_GET_DEVICE_TYPE 0x01 -#define ASPI_CMD_EXECUTE_IO 0x02 -#define ASPI_CMD_ABORT_IO 0x03 - -// Request flags -#define ASPI_REQFLAG_DIR_TO_HOST 0x08 -#define ASPI_REQFLAG_DIR_TO_TARGET 0x10 -#define ASPI_REQFLAG_DIR_NO_XFER 0x18 -#define ASPI_REQFLAG_EVENT_NOTIFY 0x40 - -// ASPI status -#define ASPI_STATUS_IN_PROGRESS 0x00 -#define ASPI_STATUS_NO_ERROR 0x01 -#define ASPI_STATUS_ABORTED 0x02 -#define ASPI_STATUS_ABORT_ERR 0x03 -#define ASPI_STATUS_ERROR 0x04 -#define ASPI_STATUS_INVALID_COMMAND 0x80 -#define ASPI_STATUS_INVALID_ADAPTER 0x81 -#define ASPI_STATUS_INVALID_TARGET 0x82 -#define ASPI_STATUS_NO_ADAPTERS 0xE8 - -// Adapter (host) status -#define ASPI_HSTATUS_NO_ERROR 0x00 -#define ASPI_HSTATUS_SELECTION_TIMEOUT 0x11 -#define ASPI_HSTATUS_DATA_OVERRUN 0x12 -#define ASPI_HSTATUS_BUS_FREE 0x13 -#define ASPI_HSTATUS_BUS_PHASE_ERROR 0x14 -#define ASPI_HSTATUS_BAD_SGLIST 0x1A - -// Target status -#define ASPI_TSTATUS_NO_ERROR 0x00 -#define ASPI_TSTATUS_CHECK_CONDITION 0x02 -#define ASPI_TSTATUS_BUSY 0x08 -#define ASPI_TSTATUS_RESERV_CONFLICT 0x18 - - -static HINSTANCE h_aspi_dll; // DLL handle -static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint -static unsigned num_aspi_adapters; - -#ifdef __CYGWIN__ -// h_aspi_dll+aspi_entry is not inherited by Cygwin's fork() -static DWORD aspi_dll_pid; // PID of DLL owner to detect fork() -#define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId())) -#else -#define aspi_entry_valid() (!!aspi_entry) -#endif - - -static int aspi_call(ASPI_SRB * srb) -{ - int i; - aspi_entry(srb); - i = 0; - while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) { - if (++i > 100/*10sek*/) { - pout("ASPI Adapter %u: Timeout\n", srb->h.adapter); - aspi_entry = 0; - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = EIO; - return -1; - } -#ifdef _DEBUG - pout("ASPI Wait %d\n", i); -#endif - Sleep(100); - } - return 0; -} - - -// Get ASPI entrypoint from wnaspi32.dll - -static FARPROC aspi_get_address(const char * name, int verbose) -{ - FARPROC addr; - assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE); - - if (!(addr = GetProcAddress(h_aspi_dll, name))) { - if (verbose) - pout("Missing %s() in WNASPI32.DLL\n", name); - aspi_entry = 0; - FreeLibrary(h_aspi_dll); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOSYS; - return 0; - } - return addr; -} - - -static int aspi_open_dll(int verbose) -{ - UINT (*aspi_info)(void); - UINT info, rc; - - assert(!aspi_entry_valid()); - - // Check structure layout - assert(sizeof(ASPI_SRB_HEAD) == 8); - assert(sizeof(ASPI_SRB_INQUIRY) == 58); - assert(sizeof(ASPI_SRB_DEVTYPE) == 12); - assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE); - assert(offsetof(ASPI_SRB,h.cmd) == 0); - assert(offsetof(ASPI_SRB,h.flags) == 3); - assert(offsetof(ASPI_SRB_IO,lun) == 9); - assert(offsetof(ASPI_SRB_IO,data_addr) == 16); - assert(offsetof(ASPI_SRB_IO,workspace) == 28); - assert(offsetof(ASPI_SRB_IO,cdb) == 48); - - if (h_aspi_dll == INVALID_HANDLE_VALUE) { - // do not retry - errno = ENOENT; - return -1; - } - - // Load ASPI DLL - if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) { - if (verbose) - pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError()); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOENT; - return -1; - } - - // Get ASPI entrypoints - if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose))) - return -1; - if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose))) - return -1; - - // Init ASPI manager and get number of adapters - info = (aspi_info)(); -#ifdef _DEBUG - pout("GetASPI32SupportInfo() returns 0x%04x\n", info); -#endif - rc = (info >> 8) & 0xff; - if (rc == ASPI_STATUS_NO_ADAPTERS) { - num_aspi_adapters = 0; - } - else if (rc == ASPI_STATUS_NO_ERROR) { - num_aspi_adapters = info & 0xff; - } - else { - if (verbose) - pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info); - aspi_entry = 0; - FreeLibrary(h_aspi_dll); - h_aspi_dll = INVALID_HANDLE_VALUE; - errno = ENOENT; - return -1; - } - -#ifdef __CYGWIN__ - // save PID to detect fork() in aspi_entry_valid() - aspi_dll_pid = GetCurrentProcessId(); -#endif - assert(aspi_entry_valid()); - return 0; -} - - -static int aspi_io_call(ASPI_SRB * srb) -{ - HANDLE event; - // Create event - if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) { - pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO; - } - srb->i.event_handle = event; - srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY; - // Start ASPI request - aspi_entry(srb); - if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) { - // Wait for event - DWORD rc = WaitForSingleObject(event, 30*1000L); - if (rc != WAIT_OBJECT_0) { - if (rc == WAIT_TIMEOUT) { - pout("ASPI Timeout\n"); - } - else { - pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n", - (unsigned long)event, rc, rc, GetLastError()); - } - // TODO: ASPI_ABORT_IO command - aspi_entry = 0; - h_aspi_dll = INVALID_HANDLE_VALUE; - return -EIO; - } - } - CloseHandle(event); - return 0; -} - - -static int aspi_open(unsigned adapter, unsigned id) -{ - if (!(adapter <= 9 && id < 16)) { - errno = ENOENT; - return -1; - } - - if (!aspi_entry_valid()) { - if (aspi_open_dll(1/*verbose*/)) - return -1; - } - - // Adapter OK? - if (adapter >= num_aspi_adapters) { - pout("ASPI Adapter %d does not exist (%d Adapter(s) detected).\n", adapter, num_aspi_adapters); - if (!is_permissive()) { - errno = ENOENT; - return -1; - } - } - - return (0x0100 | ((adapter & 0xf)<<4) | (id & 0xf)); -} - - -static void aspi_close(int fd) -{ - // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads - ARGUSED(fd); -} - - -// Scan for SCSI drives, return bitmask [adapter:0-3][id:0-7] of drives present - -static unsigned long aspi_scan() -{ - unsigned long drives = 0; - unsigned ad, nad; - - if (!aspi_entry_valid()) { - if (aspi_open_dll(0/*quiet*/)) - return 0; - } - - nad = num_aspi_adapters; - if (nad >= 4) - nad = 4; - for (ad = 0; ad < nad; ad++) { - ASPI_SRB srb; int id; - // Get adapter name - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE; - srb.h.adapter = ad; - if (aspi_call(&srb)) - return 0; -#ifdef _DEBUG - pout("ASPI Adapter %u: %02x,\"%.16s\"\n", ad, srb.h.status, srb.q.adapter_id); -#endif - if (srb.h.status != ASPI_STATUS_NO_ERROR) - continue; - - // Skip ATA/ATAPI devices - srb.q.adapter_id[sizeof(srb.q.adapter_id)-1] = 0; - if (strstr(srb.q.adapter_id, "ATAPI")) - continue; - - for (id = 0; id <= 7; id++) { - // Get device type - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE; - srb.h.adapter = ad; srb.i.target_id = id; - if (aspi_call(&srb)) - return 0; -#ifdef _DEBUG - pout("Device type for scsi%u%x: %02x,%02x\n", ad, id, srb.h.status, srb.t.devtype); -#endif - if (srb.h.status == ASPI_STATUS_NO_ERROR && srb.t.devtype == 0x00/*HDD*/) - drives |= 1 << ((ad<<3)+id); - } - } - return drives; -} - - -///////////////////////////////////////////////////////////////////////////// - -// Interface to SCSI devices. See os_linux.c -int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) -{ - ASPI_SRB srb; - - if (!aspi_entry_valid()) - return -EBADF; - if (!((fd & ~0xff) == 0x100)) - return -EBADF; - - if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12)) { - pout("do_scsi_cmnd_io: bad CDB length\n"); - return -EINVAL; - } - - if (report > 0) { - // From os_linux.c - 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(buff); - } - - memset(&srb, 0, sizeof(srb)); - srb.h.cmd = ASPI_CMD_EXECUTE_IO; - srb.h.adapter = ((fd >> 4) & 0xf); - srb.i.target_id = (fd & 0xf); - //srb.i.lun = 0; - srb.i.sense_size = ASPI_SENSE_SIZE; - srb.i.cdb_size = iop->cmnd_len; - memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len); - - switch (iop->dxfer_dir) { - case DXFER_NONE: - srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER; - break; - case DXFER_FROM_DEVICE: - srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST; - srb.i.data_size = iop->dxfer_len; - srb.i.data_addr = iop->dxferp; - break; - case DXFER_TO_DEVICE: - srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET; - srb.i.data_size = iop->dxfer_len; - srb.i.data_addr = iop->dxferp; - 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 (aspi_io_call(&srb)) { - // Timeout - return -EIO; - } - - if (srb.h.status != ASPI_STATUS_NO_ERROR) { - if ( srb.h.status == ASPI_STATUS_ERROR - && srb.i.host_status == ASPI_HSTATUS_NO_ERROR - && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) { - // Sense valid - const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len); - int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len); - iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; - if (len > 0 && iop->sensep) { - memcpy(iop->sensep, sense, len); - iop->resp_sense_len = len; - if (report > 1) { - pout(" >>> Sense buffer, len=%d:\n", (int)len); - dStrHex(iop->sensep, len , 1); - } - } - if (report) { - pout(" sense_key=%x asc=%x ascq=%x\n", - sense[2] & 0xf, sense[12], sense[13]); - } - return 0; - } - else { - if (report) - pout(" ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status); - return -EIO; - } - } - - if (report > 0) - pout(" OK\n"); - - 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; -} diff --git a/sm5/os_win32/.cvsignore b/sm5/os_win32/.cvsignore deleted file mode 100644 index c8ca8dab0918d88de313969d7275190a8e76bb97..0000000000000000000000000000000000000000 --- a/sm5/os_win32/.cvsignore +++ /dev/null @@ -1,16 +0,0 @@ -config.h -smartctl.d -smartctl.r -smartctl.exe -smartctl_vc6.plg -smartd.d -smartd.r -smartd.exe -smartd_vc6.plg -smartmontools_vc6.ncb -smartmontools_vc6.opt -syslogevt.d -syslogevt.r -syslogevt.exe -syslogevt.h -syslogevt_vc6.plg diff --git a/sm5/os_win32/config_vc6.h b/sm5/os_win32/config_vc6.h deleted file mode 100644 index 46c1128e0f92279e5dada7d2d3031b8151e1b9b7..0000000000000000000000000000000000000000 --- a/sm5/os_win32/config_vc6.h +++ /dev/null @@ -1,100 +0,0 @@ -/* config.h for MSVC6, NOT Generated by configure. */ - -/* smartmontools CVS Tag */ -#define CONFIG_H_CVSID "$Id: config_vc6.h,v 1.2 2004/03/12 23:29:06 chrfranke Exp $" - -/* use mailx as default mailer */ -/* #undef DEFAULT_MAILER */ - -/* Define to 1 if you have the <dev/ata/atavar.h> header file. */ -/* #undef HAVE_DEV_ATA_ATAVAR_H */ - -/* Define to 1 if you have the `getdomainname' function. */ -#undef HAVE_GETDOMAINNAME - -/* Define to 1 if you have the `getopt' function. */ -#undef HAVE_GETOPT - -/* Define to 1 if you have the `getopt_long' function. */ -#define HAVE_GETOPT_LONG 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the <linux/hdreg.h> header file. */ -/* #undef HAVE_LINUX_HDREG_H */ - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `sigset' function. */ -#undef HAVE_SIGSET - -/* Define to 1 if you have the <stdint.h> header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the `uname' function. */ -#undef HAVE_UNAME - -/* Define to 1 if you have the <unistd.h> header file. */ -#undef HAVE_UNISTD_H - -/* need assembly code os_solaris_ata.s */ -/* #undef NEED_SOLARIS_ATA_CODE */ - -/* Name of package */ -#define PACKAGE "smartmontools" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "smartmontools-support@lists.sourceforge.net" - -/* smartmontools Home Page */ -#define PACKAGE_HOMEPAGE "http://smartmontools.sourceforge.net/" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "smartmontools" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "smartmontools "PACKAGE_VERSION - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "smartmontools" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION VERSION - -/* smartmontools Build Host */ -#define SMARTMONTOOLS_BUILD_HOST "i686-pc-win32" - -/* smartmontools Configure Arguments */ -#define SMARTMONTOOLS_CONFIGURE_ARGS "" - -/* smartmontools Configure Date */ -#define SMARTMONTOOLS_CONFIGURE_DATE "2004/03/12 18:42:00 UTC" - -/* smartmontools Release Date */ -#define SMARTMONTOOLS_RELEASE_DATE "2004/03/07" - -/* smartmontools Release Time */ -#define SMARTMONTOOLS_RELEASE_TIME "20:57:36 UTC" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "5.31" diff --git a/sm5/os_win32/daemon_win32.c b/sm5/os_win32/daemon_win32.c deleted file mode 100644 index c54caf75094c8c0c44956b167ba0c1049731eb39..0000000000000000000000000000000000000000 --- a/sm5/os_win32/daemon_win32.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * os_win32/daemon_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <io.h> - -#define WIN32_LEAN_AND_MEAN -// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP) -#define _WIN32_WINNT 0x0400 -#include <windows.h> -#ifdef _DEBUG -#include <crtdbg.h> -#endif - -#include "daemon_win32.h" - -const char *daemon_win32_c_cvsid = "$Id: daemon_win32.c,v 1.5 2004/08/09 14:35:59 chrfranke Exp $" -DAEMON_WIN32_H_CVSID; - - -///////////////////////////////////////////////////////////////////////////// - -#define ARGUSED(x) ((void)(x)) - -// 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; - make_name(name, sig); - if (exists) - *exists = FALSE; - if (!(h = CreateEventA(NULL, FALSE, initial, name))) { - 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 sigint_handle, sigbreak_handle, sigterm_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(sig, 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 SIGINT: sigint_handle = h; break; - case SIGTERM: sigterm_handle = h; break; - case SIGBREAK: sigbreak_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); - } - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// -// MessageBox - -#ifndef _MT -//MT runtime not necessary, because mbox_thread uses no unsafe lib functions -//#error Program must be linked with multithreaded runtime library -#endif - -static LONG mbox_count; // # mbox_thread()s -static HANDLE mbox_mutex; // Show 1 box at a time (not necessary for service) - -typedef struct mbox_args_s { - HANDLE taken; const char * title, * text; int mode; -} mbox_args; - - -// Thread to display one message box - -static ULONG WINAPI mbox_thread(LPVOID arg) -{ - // Take args - mbox_args * mb = (mbox_args *)arg; - char title[100]; char text[1000]; int mode; - strncpy(title, mb->title, sizeof(title)-1); title[sizeof(title)-1] = 0; - strncpy(text , mb->text , sizeof(text )-1); text [sizeof(text )-1] = 0; - mode = mb->mode; - SetEvent(mb->taken); - - // Show only one box at a time - WaitForSingleObject(mbox_mutex, INFINITE); - MessageBoxA(NULL, text, title, mode); - ReleaseMutex(mbox_mutex); - - InterlockedDecrement(&mbox_count); - return 0; -} - - -// Display a message box -int daemon_messagebox(int system, const char * title, const char * text) -{ - mbox_args mb; - HANDLE ht; DWORD tid; - - // Create mutex during first call - if (!mbox_mutex) - mbox_mutex = CreateMutex(NULL/*!inherit*/, FALSE/*!owned*/, NULL/*unnamed*/); - - // Allow at most 10 threads - if (InterlockedIncrement(&mbox_count) > 10) { - InterlockedDecrement(&mbox_count); - return -1; - } - - // Create thread - mb.taken = CreateEvent(NULL/*!inherit*/, FALSE, FALSE/*!signaled*/, NULL/*unnamed*/); - mb.mode = MB_OK|MB_ICONWARNING - |(svc_mode?MB_SERVICE_NOTIFICATION:0) - |(system?MB_SYSTEMMODAL:MB_APPLMODAL); - mb.title = title; mb.text = text; - mb.text = text; - if (!(ht = CreateThread(NULL, 0, mbox_thread, &mb, 0, &tid))) - return -1; - - // Wait for args taken - if (WaitForSingleObject(mb.taken, 10000) != WAIT_OBJECT_0) - TerminateThread(ht, 0); - CloseHandle(mb.taken); - CloseHandle(ht); - 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 pipe_inp_r, pipe_inp_w, pipe_out_r, pipe_out_w, pipe_err_w, h; - DWORD num_io, exitcode; int i; - SECURITY_ATTRIBUTES sa; - STARTUPINFO si; PROCESS_INFORMATION pi; - HANDLE self = GetCurrentProcess(); - - // Create stdin pipe with inheritable read side - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!CreatePipe(&pipe_inp_r, &h, &sa, inpsize*2+13)) - return -1; - if (!DuplicateHandle(self, h, self, &pipe_inp_w, - 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - CloseHandle(h); - - // Create stdout pipe with inheritable write side - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!CreatePipe(&h, &pipe_out_w, &sa, outsize)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - if (!DuplicateHandle(self, h, self, &pipe_out_r, - 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS)) { - CloseHandle(h); CloseHandle(pipe_out_w); - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - CloseHandle(h); - - // Create stderr handle as dup of stdout write side - 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 - 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; - if (!CreateProcessA( - NULL, (char*)cmd, - NULL, NULL, TRUE/*inherit*/, - DETACHED_PROCESS/*no new console*/, - 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 - 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]; - int j; - if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) - break; - for (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 - WaitForSingleObject(pi.hProcess, INFINITE); - exitcode = 42; - 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; - sig_event(SIGTERM); - break; - case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP - service_report_status(svc_status.dwCurrentState, 0); - svc_paused = 0; - sig_event(SIGHUP); // 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; - sig_event(was_paused ? SIGHUP : SIGUSR1); // 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; - ARGUSED(argc); - - // Register control handler - svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); - - // Init service status - svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_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 - -// Set Service description (Win2000/XP) - -static int svcadm_setdesc(SC_HANDLE hs, const char * desc) -{ - HANDLE hdll; - BOOL (WINAPI * ChangeServiceConfig2A_p)(SC_HANDLE, DWORD, LPVOID); - BOOL ret; - if (!(hdll = LoadLibraryA("ADVAPI32.DLL"))) - return FALSE; - if (!((ChangeServiceConfig2A_p = (BOOL (WINAPI *)(SC_HANDLE, DWORD, LPVOID))GetProcAddress(hdll, "ChangeServiceConfig2A")))) - ret = FALSE; - else { - SERVICE_DESCRIPTIONA sd = { (char *)desc }; - ret = ChangeServiceConfig2A_p(hs, SERVICE_CONFIG_DESCRIPTION, &sd); - } - FreeLibrary(hdll); - return ret; -} - - -// Service install/remove commands - -static int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts, - int argc, char **argv ) -{ - int remove; - 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))) { - printf(" cannot open SCManager, Error=%ld\n", GetLastError()); - 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; - } - // Append options - strcat(path, " "); strcat(path, svc_opts->cmd_opt); - for (i = 2; i < argc; i++) { - const char * s = argv[i]; - if (strlen(path)+strlen(s)+1 >= sizeof(path)) - break; - strcat(path, " "); strcat(path, s); - } - // Create - if (!(hs = CreateService(hm, - svc_opts->svcname, svc_opts->dispname, - SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_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*/))) { - printf(" failed, Error=%ld\n", GetLastError()); - CloseServiceHandle(hm); - return 1; - } - // Set optional description - if (svc_opts->descript) - svcadm_setdesc(hs, svc_opts->descript); - } - else { - // Open - if (!(hs = OpenService(hm, ident, SERVICE_ALL_ACCESS))) { - puts(" not found"); - CloseServiceHandle(hm); - return 1; - } - // TODO: Stop service if running - // Remove - if (!DeleteService(hs)) { - printf(" failed, Error=%ld\n", GetLastError()); - CloseServiceHandle(hs); CloseServiceHandle(hm); - return 1; - } - } - puts(" done"); - CloseServiceHandle(hs); CloseServiceHandle(hm); - 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)) { - fprintf(stderr, "%s: cannot dispatch service, Error=%ld\n", ident, GetLastError()); -#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; - - 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; - } - - daemon_signal(SIGINT, sig_handler); - daemon_signal(SIGBREAK, sig_handler); - daemon_signal(SIGTERM, sig_handler); - daemon_signal(SIGHUP, 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(); - } - 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 diff --git a/sm5/os_win32/daemon_win32.cpp b/sm5/os_win32/daemon_win32.cpp deleted file mode 100644 index 5220f40cd31184186e85e7c811c9ed1bf2018d05..0000000000000000000000000000000000000000 --- a/sm5/os_win32/daemon_win32.cpp +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * os_win32/daemon_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <io.h> - -#define WIN32_LEAN_AND_MEAN -// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP) -#define _WIN32_WINNT 0x0400 -#include <windows.h> -#ifdef _DEBUG -#include <crtdbg.h> -#endif - -#include "daemon_win32.h" - -const char *daemon_win32_c_cvsid = "$Id: daemon_win32.cpp,v 1.5 2004/08/09 14:35:59 chrfranke Exp $" -DAEMON_WIN32_H_CVSID; - - -///////////////////////////////////////////////////////////////////////////// - -#define ARGUSED(x) ((void)(x)) - -// 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; - make_name(name, sig); - if (exists) - *exists = FALSE; - if (!(h = CreateEventA(NULL, FALSE, initial, name))) { - 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 sigint_handle, sigbreak_handle, sigterm_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(sig, 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 SIGINT: sigint_handle = h; break; - case SIGTERM: sigterm_handle = h; break; - case SIGBREAK: sigbreak_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); - } - - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// -// MessageBox - -#ifndef _MT -//MT runtime not necessary, because mbox_thread uses no unsafe lib functions -//#error Program must be linked with multithreaded runtime library -#endif - -static LONG mbox_count; // # mbox_thread()s -static HANDLE mbox_mutex; // Show 1 box at a time (not necessary for service) - -typedef struct mbox_args_s { - HANDLE taken; const char * title, * text; int mode; -} mbox_args; - - -// Thread to display one message box - -static ULONG WINAPI mbox_thread(LPVOID arg) -{ - // Take args - mbox_args * mb = (mbox_args *)arg; - char title[100]; char text[1000]; int mode; - strncpy(title, mb->title, sizeof(title)-1); title[sizeof(title)-1] = 0; - strncpy(text , mb->text , sizeof(text )-1); text [sizeof(text )-1] = 0; - mode = mb->mode; - SetEvent(mb->taken); - - // Show only one box at a time - WaitForSingleObject(mbox_mutex, INFINITE); - MessageBoxA(NULL, text, title, mode); - ReleaseMutex(mbox_mutex); - - InterlockedDecrement(&mbox_count); - return 0; -} - - -// Display a message box -int daemon_messagebox(int system, const char * title, const char * text) -{ - mbox_args mb; - HANDLE ht; DWORD tid; - - // Create mutex during first call - if (!mbox_mutex) - mbox_mutex = CreateMutex(NULL/*!inherit*/, FALSE/*!owned*/, NULL/*unnamed*/); - - // Allow at most 10 threads - if (InterlockedIncrement(&mbox_count) > 10) { - InterlockedDecrement(&mbox_count); - return -1; - } - - // Create thread - mb.taken = CreateEvent(NULL/*!inherit*/, FALSE, FALSE/*!signaled*/, NULL/*unnamed*/); - mb.mode = MB_OK|MB_ICONWARNING - |(svc_mode?MB_SERVICE_NOTIFICATION:0) - |(system?MB_SYSTEMMODAL:MB_APPLMODAL); - mb.title = title; mb.text = text; - mb.text = text; - if (!(ht = CreateThread(NULL, 0, mbox_thread, &mb, 0, &tid))) - return -1; - - // Wait for args taken - if (WaitForSingleObject(mb.taken, 10000) != WAIT_OBJECT_0) - TerminateThread(ht, 0); - CloseHandle(mb.taken); - CloseHandle(ht); - 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 pipe_inp_r, pipe_inp_w, pipe_out_r, pipe_out_w, pipe_err_w, h; - DWORD num_io, exitcode; int i; - SECURITY_ATTRIBUTES sa; - STARTUPINFO si; PROCESS_INFORMATION pi; - HANDLE self = GetCurrentProcess(); - - // Create stdin pipe with inheritable read side - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!CreatePipe(&pipe_inp_r, &h, &sa, inpsize*2+13)) - return -1; - if (!DuplicateHandle(self, h, self, &pipe_inp_w, - 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - CloseHandle(h); - - // Create stdout pipe with inheritable write side - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!CreatePipe(&h, &pipe_out_w, &sa, outsize)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - if (!DuplicateHandle(self, h, self, &pipe_out_r, - 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS)) { - CloseHandle(h); CloseHandle(pipe_out_w); - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - CloseHandle(h); - - // Create stderr handle as dup of stdout write side - 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 - 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; - if (!CreateProcessA( - NULL, (char*)cmd, - NULL, NULL, TRUE/*inherit*/, - DETACHED_PROCESS/*no new console*/, - 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 - 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]; - int j; - if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) - break; - for (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 - WaitForSingleObject(pi.hProcess, INFINITE); - exitcode = 42; - 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; - sig_event(SIGTERM); - break; - case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP - service_report_status(svc_status.dwCurrentState, 0); - svc_paused = 0; - sig_event(SIGHUP); // 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; - sig_event(was_paused ? SIGHUP : SIGUSR1); // 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; - ARGUSED(argc); - - // Register control handler - svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); - - // Init service status - svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_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 - -// Set Service description (Win2000/XP) - -static int svcadm_setdesc(SC_HANDLE hs, const char * desc) -{ - HANDLE hdll; - BOOL (WINAPI * ChangeServiceConfig2A_p)(SC_HANDLE, DWORD, LPVOID); - BOOL ret; - if (!(hdll = LoadLibraryA("ADVAPI32.DLL"))) - return FALSE; - if (!((ChangeServiceConfig2A_p = (BOOL (WINAPI *)(SC_HANDLE, DWORD, LPVOID))GetProcAddress(hdll, "ChangeServiceConfig2A")))) - ret = FALSE; - else { - SERVICE_DESCRIPTIONA sd = { (char *)desc }; - ret = ChangeServiceConfig2A_p(hs, SERVICE_CONFIG_DESCRIPTION, &sd); - } - FreeLibrary(hdll); - return ret; -} - - -// Service install/remove commands - -static int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts, - int argc, char **argv ) -{ - int remove; - 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))) { - printf(" cannot open SCManager, Error=%ld\n", GetLastError()); - 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; - } - // Append options - strcat(path, " "); strcat(path, svc_opts->cmd_opt); - for (i = 2; i < argc; i++) { - const char * s = argv[i]; - if (strlen(path)+strlen(s)+1 >= sizeof(path)) - break; - strcat(path, " "); strcat(path, s); - } - // Create - if (!(hs = CreateService(hm, - svc_opts->svcname, svc_opts->dispname, - SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_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*/))) { - printf(" failed, Error=%ld\n", GetLastError()); - CloseServiceHandle(hm); - return 1; - } - // Set optional description - if (svc_opts->descript) - svcadm_setdesc(hs, svc_opts->descript); - } - else { - // Open - if (!(hs = OpenService(hm, ident, SERVICE_ALL_ACCESS))) { - puts(" not found"); - CloseServiceHandle(hm); - return 1; - } - // TODO: Stop service if running - // Remove - if (!DeleteService(hs)) { - printf(" failed, Error=%ld\n", GetLastError()); - CloseServiceHandle(hs); CloseServiceHandle(hm); - return 1; - } - } - puts(" done"); - CloseServiceHandle(hs); CloseServiceHandle(hm); - 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)) { - fprintf(stderr, "%s: cannot dispatch service, Error=%ld\n", ident, GetLastError()); -#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; - - 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; - } - - daemon_signal(SIGINT, sig_handler); - daemon_signal(SIGBREAK, sig_handler); - daemon_signal(SIGTERM, sig_handler); - daemon_signal(SIGHUP, 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(); - } - 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 diff --git a/sm5/os_win32/daemon_win32.h b/sm5/os_win32/daemon_win32.h deleted file mode 100644 index 58a26895f3ece159f6b3113cb109d88354b352d1..0000000000000000000000000000000000000000 --- a/sm5/os_win32/daemon_win32.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * os_win32/daemon_win32.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef DAEMON_WIN32_H -#define DAEMON_WIN32_H - -#define DAEMON_WIN32_H_CVSID "$Id: daemon_win32.h,v 1.4 2004/08/06 13:08:45 chrfranke Exp $\n" - -#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); - -// Display a message box -int daemon_messagebox(int system, const char * title, const char * text); - -// 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 diff --git a/sm5/os_win32/hostname_win32.c b/sm5/os_win32/hostname_win32.c deleted file mode 100644 index 21928adf4da274e13cfc960b27f81150233b5bd7..0000000000000000000000000000000000000000 --- a/sm5/os_win32/hostname_win32.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * os_win32/hostname_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "hostname_win32.h" - -const char * hostname_win32_c_cvsid = "$Id: hostname_win32.c,v 1.1 2004/07/31 19:18:54 chrfranke Exp $" HOSTNAME_WIN32_H_CVSID; - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <string.h> - -#ifndef MAX_HOSTNAME_LEN - -// From IPHlpApi.dll: - -#define MAX_HOSTNAME_LEN 132 -#define MAX_DOMAIN_NAME_LEN 132 -#define MAX_SCOPE_ID_LEN 260 - -typedef struct { - char String[4 * 4]; -} IP_ADDRESS_STRING, -*PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING; - -typedef struct _IP_ADDR_STRING { - struct _IP_ADDR_STRING* Next; - IP_ADDRESS_STRING IpAddress; - IP_MASK_STRING IpMask; - DWORD Context; -} IP_ADDR_STRING, -*PIP_ADDR_STRING; - -typedef struct { - char HostName[MAX_HOSTNAME_LEN]; - char DomainName[MAX_DOMAIN_NAME_LEN]; - PIP_ADDR_STRING CurrentDnsServer; - IP_ADDR_STRING DnsServerList; - UINT NodeType; - char ScopeId[MAX_SCOPE_ID_LEN]; - UINT EnableRouting; - UINT EnableProxy; - UINT EnableDns; -} FIXED_INFO, -*PFIXED_INFO; - -DWORD WINAPI GetNetworkParams(PFIXED_INFO info, PULONG size); - -#endif // MAX_HOSTNAME_LEN - - -// Call GetComputerNameEx() if available (Win2000/XP) - -static BOOL CallGetComputerNameExA(int type, LPSTR name, LPDWORD size) -{ - HANDLE hdll; - BOOL (WINAPI * GetComputerNameExA_p)(int/*enum COMPUTER_NAME_FORMAT*/, LPSTR, LPDWORD); - BOOL ret; - if (!(hdll = LoadLibraryA("KERNEL32.DLL"))) - return FALSE; - if (!((FARPROC)GetComputerNameExA_p = GetProcAddress(hdll, "GetComputerNameExA"))) - ret = FALSE; - else - ret = GetComputerNameExA_p(type, name, size); - FreeLibrary(hdll); - return ret; -} - - -// Call GetNetworkParams() if available (Win98/ME/2000/XP) - -static DWORD CallGetNetworkParams(PFIXED_INFO info, PULONG size) -{ - HANDLE hdll; - DWORD (WINAPI * GetNetworkParams_p)(PFIXED_INFO info, PULONG size); - DWORD ret; - if (!(hdll = LoadLibraryA("IPHlpApi.dll"))) - return ERROR_NOT_SUPPORTED; - if (!((FARPROC)GetNetworkParams_p = GetProcAddress(hdll, "GetNetworkParams"))) - ret = ERROR_NOT_SUPPORTED; - else - ret = GetNetworkParams_p(info, size); - FreeLibrary(hdll); - return ret; -} - - -// Get host/domainname from registry (Win98/ME/NT4/2000/XP) - -static DWORD GetNamesFromRegistry(BOOL domain, char * name, int len) -{ - HKEY hk; DWORD size, type; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, - (GetVersion() & 0x80000000 - ? "System\\CurrentControlSet\\Services\\VxD\\MSTCP" //Win9x/ME - : "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"), - 0, KEY_READ, &hk) != ERROR_SUCCESS) - return 0; - size = len-1; - if (!(RegQueryValueExA(hk, (!domain?"HostName":"Domain"), 0, &type, name, &size) == ERROR_SUCCESS && type == REG_SZ)) - size = 0; - if (size == 0 && domain) { - size = len-1; - if (!(RegQueryValueExA(hk, "DhcpDomain", 0, &type, name, &size) == ERROR_SUCCESS && type == REG_SZ)) - size = 0; - } - RegCloseKey(hk); - return size; -} - - -static int gethostdomname(int domain, char * name, int len) -{ - DWORD size; FIXED_INFO info; - - // try KERNEL32.dll::GetComputerNameEx() - size = len - 1; - if (CallGetComputerNameExA((!domain ? 1:2/*ComputerNameDnsHost:Domain*/), name, &size)) - return 0; - - // try IPHlpApi.dll::GetNetworkParams() - size = sizeof(info); - if (CallGetNetworkParams(&info, &size) == ERROR_SUCCESS) { - strncpy(name, (!domain?info.HostName:info.DomainName), len-1); name[len-1] = 0; - return 0; - } - - // try registry - if (GetNamesFromRegistry(domain, name, len)) - return 0; - - if (domain) - return -1; - - // last resort: get NETBIOS name - size = len - 1; - if (GetComputerNameA(name, &size)) - return 0; - - return -1; -} - - -int gethostname(char * name, int len) -{ - return gethostdomname(0, name, len); -} - - -int getdomainname(char * name, int len) -{ - return gethostdomname(1, name, len); -} - - -#ifdef TEST - -#include <stdio.h> - -main() -{ - char name[256]; - if (gethostname(name, sizeof(name))) - strcpy(name, "Error"); - printf("hostname=\"%s\"\n", name); - if (getdomainname(name, sizeof(name))) - strcpy(name, "Error"); - printf("domainname=\"%s\"\n", name); - return 0; -} - -#endif diff --git a/sm5/os_win32/hostname_win32.cpp b/sm5/os_win32/hostname_win32.cpp deleted file mode 100644 index 439017d441e792031f70760a818c05edca87f2a6..0000000000000000000000000000000000000000 --- a/sm5/os_win32/hostname_win32.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* - * os_win32/hostname_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "hostname_win32.h" - -const char * hostname_win32_c_cvsid = "$Id: hostname_win32.cpp,v 1.1 2004/07/31 19:18:54 chrfranke Exp $" HOSTNAME_WIN32_H_CVSID; - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <string.h> - -#ifndef MAX_HOSTNAME_LEN - -// From IPHlpApi.dll: - -#define MAX_HOSTNAME_LEN 132 -#define MAX_DOMAIN_NAME_LEN 132 -#define MAX_SCOPE_ID_LEN 260 - -typedef struct { - char String[4 * 4]; -} IP_ADDRESS_STRING, -*PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING; - -typedef struct _IP_ADDR_STRING { - struct _IP_ADDR_STRING* Next; - IP_ADDRESS_STRING IpAddress; - IP_MASK_STRING IpMask; - DWORD Context; -} IP_ADDR_STRING, -*PIP_ADDR_STRING; - -typedef struct { - char HostName[MAX_HOSTNAME_LEN]; - char DomainName[MAX_DOMAIN_NAME_LEN]; - PIP_ADDR_STRING CurrentDnsServer; - IP_ADDR_STRING DnsServerList; - UINT NodeType; - char ScopeId[MAX_SCOPE_ID_LEN]; - UINT EnableRouting; - UINT EnableProxy; - UINT EnableDns; -} FIXED_INFO, -*PFIXED_INFO; - -DWORD WINAPI GetNetworkParams(PFIXED_INFO info, PULONG size); - -#endif // MAX_HOSTNAME_LEN - - -// Call GetComputerNameEx() if available (Win2000/XP) - -static BOOL CallGetComputerNameExA(int type, LPSTR name, LPDWORD size) -{ - HANDLE hdll; - BOOL (WINAPI * GetComputerNameExA_p)(int/*enum COMPUTER_NAME_FORMAT*/, LPSTR, LPDWORD); - BOOL ret; - if (!(hdll = LoadLibraryA("KERNEL32.DLL"))) - return FALSE; - if (!((FARPROC)GetComputerNameExA_p = GetProcAddress(hdll, "GetComputerNameExA"))) - ret = FALSE; - else - ret = GetComputerNameExA_p(type, name, size); - FreeLibrary(hdll); - return ret; -} - - -// Call GetNetworkParams() if available (Win98/ME/2000/XP) - -static DWORD CallGetNetworkParams(PFIXED_INFO info, PULONG size) -{ - HANDLE hdll; - DWORD (WINAPI * GetNetworkParams_p)(PFIXED_INFO info, PULONG size); - DWORD ret; - if (!(hdll = LoadLibraryA("IPHlpApi.dll"))) - return ERROR_NOT_SUPPORTED; - if (!((FARPROC)GetNetworkParams_p = GetProcAddress(hdll, "GetNetworkParams"))) - ret = ERROR_NOT_SUPPORTED; - else - ret = GetNetworkParams_p(info, size); - FreeLibrary(hdll); - return ret; -} - - -// Get host/domainname from registry (Win98/ME/NT4/2000/XP) - -static DWORD GetNamesFromRegistry(BOOL domain, char * name, int len) -{ - HKEY hk; DWORD size, type; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, - (GetVersion() & 0x80000000 - ? "System\\CurrentControlSet\\Services\\VxD\\MSTCP" //Win9x/ME - : "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"), - 0, KEY_READ, &hk) != ERROR_SUCCESS) - return 0; - size = len-1; - if (!(RegQueryValueExA(hk, (!domain?"HostName":"Domain"), 0, &type, name, &size) == ERROR_SUCCESS && type == REG_SZ)) - size = 0; - if (size == 0 && domain) { - size = len-1; - if (!(RegQueryValueExA(hk, "DhcpDomain", 0, &type, name, &size) == ERROR_SUCCESS && type == REG_SZ)) - size = 0; - } - RegCloseKey(hk); - return size; -} - - -static int gethostdomname(int domain, char * name, int len) -{ - DWORD size; FIXED_INFO info; - - // try KERNEL32.dll::GetComputerNameEx() - size = len - 1; - if (CallGetComputerNameExA((!domain ? 1:2/*ComputerNameDnsHost:Domain*/), name, &size)) - return 0; - - // try IPHlpApi.dll::GetNetworkParams() - size = sizeof(info); - if (CallGetNetworkParams(&info, &size) == ERROR_SUCCESS) { - strncpy(name, (!domain?info.HostName:info.DomainName), len-1); name[len-1] = 0; - return 0; - } - - // try registry - if (GetNamesFromRegistry(domain, name, len)) - return 0; - - if (domain) - return -1; - - // last resort: get NETBIOS name - size = len - 1; - if (GetComputerNameA(name, &size)) - return 0; - - return -1; -} - - -int gethostname(char * name, int len) -{ - return gethostdomname(0, name, len); -} - - -int getdomainname(char * name, int len) -{ - return gethostdomname(1, name, len); -} - - -#ifdef TEST - -#include <stdio.h> - -main() -{ - char name[256]; - if (gethostname(name, sizeof(name))) - strcpy(name, "Error"); - printf("hostname=\"%s\"\n", name); - if (getdomainname(name, sizeof(name))) - strcpy(name, "Error"); - printf("domainname=\"%s\"\n", name); - return 0; -} - -#endif diff --git a/sm5/os_win32/hostname_win32.h b/sm5/os_win32/hostname_win32.h deleted file mode 100644 index 3198cb1e9aa0236ad7c05ff75648eb6e44e9d883..0000000000000000000000000000000000000000 --- a/sm5/os_win32/hostname_win32.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * os_win32/hostname_win32.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef HOSTNAME_WIN32_H -#define HOSTNAME_WIN32_H - -#define HOSTNAME_WIN32_H_CVSID "$Id: hostname_win32.h,v 1.1 2004/07/31 19:18:54 chrfranke Exp $\n" - -int gethostname(char * name, int len); -int getdomainname(char * name, int len); - -#endif // HOSTNAME_WIN32_H diff --git a/sm5/os_win32/int64_vc6.c b/sm5/os_win32/int64_vc6.c deleted file mode 100644 index a31078a0f22dd7f511f8a8182f2c7d04b9a3ec40..0000000000000000000000000000000000000000 --- a/sm5/os_win32/int64_vc6.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * os_win32/int64_vc6.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "int64.h" - -#include <stdio.h> -#include <errno.h> - -const char *int64_vc6_c_cvsid = "$Id: int64_vc6.c,v 1.3 2004/07/29 21:05:26 chrfranke Exp $" \ -INT64_H_CVSID; - - -// Missing (why?-) "unsigned __int64 -> double" conversion - -double uint64_to_double(unsigned __int64 ull) -{ - if ((__int64)ull >= 0) - return (double)(__int64)ull; - else - return (double)(__int64)(ull - 9223372036854775808I64) - + 9223372036854775808.0; - // ~((~(uint64_t)0) >> 1) == 0x8000000000000000I64 -} - diff --git a/sm5/os_win32/smartctl_vc6.dsp b/sm5/os_win32/smartctl_vc6.dsp deleted file mode 100644 index 310497f3c446f40b832df03779dbd34d731ad5de..0000000000000000000000000000000000000000 --- a/sm5/os_win32/smartctl_vc6.dsp +++ /dev/null @@ -1,240 +0,0 @@ -# Microsoft Developer Studio Project File - Name="smartctl_vc6" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** NICHT BEARBEITEN ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=smartctl_vc6 - Win32 Debug -!MESSAGE Dies ist kein g�ltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE -!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und f�hren Sie den Befehl -!MESSAGE -!MESSAGE NMAKE /f "smartctl_vc6.mak". -!MESSAGE -!MESSAGE Sie k�nnen beim Ausf�hren von NMAKE eine Konfiguration angeben -!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: -!MESSAGE -!MESSAGE NMAKE /f "smartctl_vc6.mak" CFG="smartctl_vc6 - Win32 Debug" -!MESSAGE -!MESSAGE F�r die Konfiguration stehen zur Auswahl: -!MESSAGE -!MESSAGE "smartctl_vc6 - Win32 Release" (basierend auf "Win32 (x86) Console Application") -!MESSAGE "smartctl_vc6 - Win32 Debug" (basierend auf "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "smartctl_vc6 - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "smartctl.r" -# PROP Intermediate_Dir "smartctl.r" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O1 /I "." /I ".." /I "..\posix" /D "NDEBUG" /D "HAVE_CONFIG_H" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x407 /d "NDEBUG" -# ADD RSC /l 0x407 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"smartctl.exe" - -!ELSEIF "$(CFG)" == "smartctl_vc6 - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "smartctl.d" -# PROP Intermediate_Dir "smartctl.d" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\posix" /D "_DEBUG" /D "HAVE_CONFIG_H" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x407 /d "_DEBUG" -# ADD RSC /l 0x407 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "smartctl_vc6 - Win32 Release" -# Name "smartctl_vc6 - Win32 Debug" -# Begin Group "posix" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\posix\getopt.c -# End Source File -# Begin Source File - -SOURCE=..\posix\getopt.h -# End Source File -# Begin Source File - -SOURCE=..\posix\getopt1.c -# End Source File -# Begin Source File - -SOURCE=..\posix\regcomp.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex.c -# ADD CPP /w /W0 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex.h -# End Source File -# Begin Source File - -SOURCE=..\posix\regex_internal.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex_internal.h -# End Source File -# Begin Source File - -SOURCE=..\posix\regexec.c -# PROP Exclude_From_Build 1 -# End Source File -# End Group -# Begin Source File - -SOURCE=..\atacmdnames.c -# End Source File -# Begin Source File - -SOURCE=..\atacmdnames.h -# End Source File -# Begin Source File - -SOURCE=..\atacmds.c -# End Source File -# Begin Source File - -SOURCE=..\atacmds.h -# End Source File -# Begin Source File - -SOURCE=..\ataprint.c -# End Source File -# Begin Source File - -SOURCE=..\ataprint.h -# End Source File -# Begin Source File - -SOURCE=.\config_vc6.h - -!IF "$(CFG)" == "smartctl_vc6 - Win32 Release" - -# Begin Custom Build - Copy $(InputPath) config.h -InputPath=.\config_vc6.h - -"config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(InputPath) config.h - -# End Custom Build - -!ELSEIF "$(CFG)" == "smartctl_vc6 - Win32 Debug" - -# Begin Custom Build - Copy $(InputPath) config.h -InputPath=.\config_vc6.h - -"config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(InputPath) config.h - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\extern.h -# End Source File -# Begin Source File - -SOURCE=..\int64.h -# End Source File -# Begin Source File - -SOURCE=.\int64_vc6.c -# End Source File -# Begin Source File - -SOURCE=..\knowndrives.c -# End Source File -# Begin Source File - -SOURCE=..\knowndrives.h -# End Source File -# Begin Source File - -SOURCE=..\os_win32.c -# End Source File -# Begin Source File - -SOURCE=..\scsicmds.c -# End Source File -# Begin Source File - -SOURCE=..\scsicmds.h -# End Source File -# Begin Source File - -SOURCE=..\scsiprint.c -# End Source File -# Begin Source File - -SOURCE=..\scsiprint.h -# End Source File -# Begin Source File - -SOURCE=..\smartctl.c -# End Source File -# Begin Source File - -SOURCE=..\smartctl.h -# End Source File -# Begin Source File - -SOURCE=.\syslog.h -# End Source File -# Begin Source File - -SOURCE=..\utility.c -# End Source File -# Begin Source File - -SOURCE=..\utility.h -# End Source File -# End Target -# End Project diff --git a/sm5/os_win32/smartd_vc6.dsp b/sm5/os_win32/smartd_vc6.dsp deleted file mode 100644 index 64f13524101d0df6a892a2abe4350ce6d2ccb09f..0000000000000000000000000000000000000000 --- a/sm5/os_win32/smartd_vc6.dsp +++ /dev/null @@ -1,264 +0,0 @@ -# Microsoft Developer Studio Project File - Name="smartd_vc6" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** NICHT BEARBEITEN ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=smartd_vc6 - Win32 Debug -!MESSAGE Dies ist kein g�ltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE -!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und f�hren Sie den Befehl -!MESSAGE -!MESSAGE NMAKE /f "smartd_vc6.mak". -!MESSAGE -!MESSAGE Sie k�nnen beim Ausf�hren von NMAKE eine Konfiguration angeben -!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: -!MESSAGE -!MESSAGE NMAKE /f "smartd_vc6.mak" CFG="smartd_vc6 - Win32 Debug" -!MESSAGE -!MESSAGE F�r die Konfiguration stehen zur Auswahl: -!MESSAGE -!MESSAGE "smartd_vc6 - Win32 Release" (basierend auf "Win32 (x86) Console Application") -!MESSAGE "smartd_vc6 - Win32 Debug" (basierend auf "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "smartd_vc6 - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "smartd.r" -# PROP Intermediate_Dir "smartd.r" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O1 /I "." /I ".." /I "..\posix" /D "NDEBUG" /D "HAVE_CONFIG_H" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x407 /d "NDEBUG" -# ADD RSC /l 0x407 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"smartd.exe" - -!ELSEIF "$(CFG)" == "smartd_vc6 - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "smartd.d" -# PROP Intermediate_Dir "smartd.d" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".." /I "..\posix" /D "_DEBUG" /D "HAVE_CONFIG_H" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x407 /d "_DEBUG" -# ADD RSC /l 0x407 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "smartd_vc6 - Win32 Release" -# Name "smartd_vc6 - Win32 Debug" -# Begin Group "posix" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\posix\getopt.c -# End Source File -# Begin Source File - -SOURCE=..\posix\getopt.h -# End Source File -# Begin Source File - -SOURCE=..\posix\getopt1.c -# End Source File -# Begin Source File - -SOURCE=..\posix\regcomp.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex.c -# ADD CPP /w /W0 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex.h -# End Source File -# Begin Source File - -SOURCE=..\posix\regex_internal.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\posix\regex_internal.h -# End Source File -# Begin Source File - -SOURCE=..\posix\regexec.c -# PROP Exclude_From_Build 1 -# End Source File -# End Group -# Begin Source File - -SOURCE=..\atacmdnames.c -# End Source File -# Begin Source File - -SOURCE=..\atacmdnames.h -# End Source File -# Begin Source File - -SOURCE=..\atacmds.c -# End Source File -# Begin Source File - -SOURCE=..\atacmds.h -# End Source File -# Begin Source File - -SOURCE=..\ataprint.c -# End Source File -# Begin Source File - -SOURCE=..\ataprint.h -# End Source File -# Begin Source File - -SOURCE=.\config_vc6.h - -!IF "$(CFG)" == "smartd_vc6 - Win32 Release" - -# Begin Custom Build - Copy $(InputPath) config.h -InputPath=.\config_vc6.h - -"config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(InputPath) config.h - -# End Custom Build - -!ELSEIF "$(CFG)" == "smartd_vc6 - Win32 Debug" - -# Begin Custom Build - Copy $(InputPath) config.h -InputPath=.\config_vc6.h - -"config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(InputPath) config.h - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\daemon_win32.c -# End Source File -# Begin Source File - -SOURCE=.\daemon_win32.h -# End Source File -# Begin Source File - -SOURCE=..\extern.h -# End Source File -# Begin Source File - -SOURCE=.\hostname_win32.c -# End Source File -# Begin Source File - -SOURCE=.\hostname_win32.h -# End Source File -# Begin Source File - -SOURCE=..\int64.h -# End Source File -# Begin Source File - -SOURCE=.\int64_vc6.c -# End Source File -# Begin Source File - -SOURCE=..\knowndrives.c -# End Source File -# Begin Source File - -SOURCE=..\knowndrives.h -# End Source File -# Begin Source File - -SOURCE=..\os_win32.c -# End Source File -# Begin Source File - -SOURCE=..\scsicmds.c -# End Source File -# Begin Source File - -SOURCE=..\scsicmds.h -# End Source File -# Begin Source File - -SOURCE=..\scsiprint.c -# End Source File -# Begin Source File - -SOURCE=..\scsiprint.h -# End Source File -# Begin Source File - -SOURCE=..\smartctl.h -# End Source File -# Begin Source File - -SOURCE=..\smartd.c -# End Source File -# Begin Source File - -SOURCE=..\smartd.h -# End Source File -# Begin Source File - -SOURCE=.\syslog.h -# End Source File -# Begin Source File - -SOURCE=.\syslog_win32.c -# End Source File -# Begin Source File - -SOURCE=..\utility.c -# End Source File -# Begin Source File - -SOURCE=..\utility.h -# End Source File -# End Target -# End Project diff --git a/sm5/os_win32/smartmontools_vc6.dsw b/sm5/os_win32/smartmontools_vc6.dsw deleted file mode 100644 index 76e451e63a7815998f482c1bbfecf3f449332969..0000000000000000000000000000000000000000 --- a/sm5/os_win32/smartmontools_vc6.dsw +++ /dev/null @@ -1,53 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GEL�SCHT WERDEN! - -############################################################################### - -Project: "smartctl_vc6"=.\smartctl_vc6.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "smartd_vc6"=.\smartd_vc6.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "syslogevt_vc6"=.\syslogevt_vc6.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/sm5/os_win32/syslog.h b/sm5/os_win32/syslog.h deleted file mode 100644 index 4c403cefe4385f4d1427f51a54ce61b7a4daf042..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * os_win32/syslog.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef SYSLOG_H -#define SYSLOG_H - -#define SYSLOG_H_CVSID "$Id: syslog.h,v 1.2 2004/03/24 21:08:44 chrfranke Exp $\n" - -#include <stdarg.h> - -/* 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); - -#endif /* SYSLOG_H */ diff --git a/sm5/os_win32/syslog_win32.c b/sm5/os_win32/syslog_win32.c deleted file mode 100644 index 832854f8a9df1ffa14e9cce040a605f1232caaed..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslog_win32.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * os_win32/syslog_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -// Win32 Emulation of syslog() for smartd -// Writes to windows event log on NT4/2000/XP -// (Register syslogevt.exe as event message file) -// Writes to file "<ident>.log" on 9x/ME. -// 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_c_cvsid = "$Id: syslog_win32.c,v 1.4 2004/04/07 11:17:08 chrfranke Exp $" -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"); - if (GetVersion() & 0x80000000) - fprintf(stderr, "%s: No event log on Win9x/ME, writing to %s\n", - sl_ident, sl_logpath); - else - 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 diff --git a/sm5/os_win32/syslog_win32.cpp b/sm5/os_win32/syslog_win32.cpp deleted file mode 100644 index 2bb4da9ae83991fb7edb91b850e167cbad4a8f45..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslog_win32.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/* - * os_win32/syslog_win32.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -// Win32 Emulation of syslog() for smartd -// Writes to windows event log on NT4/2000/XP -// (Register syslogevt.exe as event message file) -// Writes to file "<ident>.log" on 9x/ME. -// 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_c_cvsid = "$Id: syslog_win32.cpp,v 1.4 2004/04/07 11:17:08 chrfranke Exp $" -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"); - if (GetVersion() & 0x80000000) - fprintf(stderr, "%s: No event log on Win9x/ME, writing to %s\n", - sl_ident, sl_logpath); - else - 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 diff --git a/sm5/os_win32/syslogevt.c b/sm5/os_win32/syslogevt.c deleted file mode 100644 index 65f8565f1e4e3e5aca8d215d710b7c2ed69bdd57..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslogevt.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * os_win32/syslogevt.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -static char rcsid[] = "$Id: syslogevt.c,v 1.2 2004/04/07 11:17:08 chrfranke Exp $"; - -#include <stdio.h> -#include <string.h> -#include <process.h> - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -#ifdef _DEBUG -#include "syslogevt.h" -#endif - - -static int usage() -{ - puts( - "syslogevt $Revision: 1.2 $ Copyright (C) 2004 Christian Franke\n" - "Home page is http://smartmontools.sourceforge.net/\n" - "\n" - "Usage: syslogevt [-ru] name [ident ...]\n" - "\n" - "Creates registry files \"name-r.reg\" and \"name-u.reg\" to (un)register\n" - "this program as an event message file for message source(s) \"ident\".\n" - "If \"ident\" is ommited, \"name\" is used. Options:\n" - "\n" - " -r run \"regedit name-r.reg\" after creating files\n" - " -u run \"regedit name-u.reg\" after creating files\n" - "\n" - "Examples:\n" - "\n" - "syslogevt smartd (Create smartd-r.reg and smartd-u.reg)\n" - "regedit smartd-r.reg (Register syslogevt.exe for smartd messages)\n" - "\n" - "syslogevt -r smartd (Same as above in one step)\n" - "\n" - "regedit smartd-u.reg (Undo the registration)\n" - "\n" - "CAUTION: A registry entry of an existing event source with the same \"ident\"\n" - " will be overwritten by regedit without notice." - ); - return 1; -} - -main(int argc, char ** argv) -{ - int regedit, a1, ai; - char name1[30+1], name2[30+1], mypath[MAX_PATH+1]; - const char * ident; - FILE * f1, * f2; - -#ifdef _DEBUG - if (!(MSG_SYSLOG == 0 && MSG_SYSLOG_01 == 1 && MSG_SYSLOG_10 == 10)) { - puts("Internal error: MSG_SYSLOG_n != n"); return 1; - } -#endif - - if (argc < 2) - return usage(); - - a1 = 1; - regedit = 0; - if (!strcmp(argv[a1], "-r")) { - regedit = 1; a1++; - } - else if (!strcmp(argv[a1], "-u")) { - regedit = -1; a1++; - } - - for (ai = a1; ai < argc; ai++) { - ident = argv[ai]; - if (!(ident[0] && strlen(ident) < sizeof(name1)-10 - && strcspn(ident, "-.:/\\") == strlen(ident) )) { - return usage(); - } - } - - if (!GetModuleFileName(NULL, mypath, sizeof(mypath)-1)) { - fputs("GetModuleFileName failed\n", stderr); - return 1; - } - - ident = argv[a1]; - strcpy(name1, ident); strcat(name1, "-r.reg"); - strcpy(name2, ident); strcat(name2, "-u.reg"); - - if (!(f1 = fopen(name1, "w"))) { - perror(name1); return 1; - } - if (!(f2 = fopen(name2, "w"))) { - perror(name2); unlink(name1); return 1; - } - - fputs("REGEDIT4\n\n", f1); - fputs("REGEDIT4\n\n", f2); - - for (ai = (argc > a1+1 ? a1+1 : a1); ai < argc; ai++) { - int i; - ident = argv[ai]; - fputs("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\", f1); - fputs(ident, f1); fputs("]\n\"EventMessageFile\"=\"", f1); - for (i = 0; mypath[i]; i++) { - if (mypath[i] == '\\') - fputc('\\', f1); - fputc(mypath[i], f1); - } - fputs("\"\n\"TypesSupported\"=dword:00000007\n\n", f1); - - fputs("[-HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\", f2); - fputs(ident, f2); fputs("]\n\n", f2); - } - - fclose(f1); - fclose(f2); - - if (GetVersion() & 0x80000000) { - puts("Warning: Event log not supported on Win9x/ME\n"); - if (regedit) - return 1; - } - - if (regedit) { - if (spawnlp(P_WAIT, "regedit", "regedit", (regedit > 0 ? name1 : name2), (const char *)0) == -1) { - fputs("regedit: cannot execute\n", stderr); - return 1; - } - } - else { - fputs("Files generated. Use\n\n regedit ", stdout); - puts(name1); - fputs("\nto register event message file, and\n\n regedit ", stdout); - puts(name2); - fputs("\nto remove registration later.\n\n" - "Do not remove this program when registered.\n", stdout); - } - - return 0; -} diff --git a/sm5/os_win32/syslogevt.mc b/sm5/os_win32/syslogevt.mc deleted file mode 100644 index 049f2eb5a2c2e79772cd9aeb41fd6a0f40ef39ae..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslogevt.mc +++ /dev/null @@ -1,161 +0,0 @@ -;/* -; * os_win32/syslogevt.mc -; * -; * Home page of code is: http://smartmontools.sourceforge.net -; * -; * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA. -; * -; */ -; -;// $Id: syslogevt.mc,v 1.2 2004/04/07 11:17:08 chrfranke Exp $ -; -;// Use message compiler "mc" 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 -; -; - -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 -. diff --git a/sm5/os_win32/syslogevt_vc6.dsp b/sm5/os_win32/syslogevt_vc6.dsp deleted file mode 100644 index 3f8a8af44f28dc8e78138e8a51f79202ec8ae129..0000000000000000000000000000000000000000 --- a/sm5/os_win32/syslogevt_vc6.dsp +++ /dev/null @@ -1,148 +0,0 @@ -# Microsoft Developer Studio Project File - Name="syslogevt_vc6" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** NICHT BEARBEITEN ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=syslogevt_vc6 - Win32 Debug -!MESSAGE Dies ist kein g�ltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE -!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und f�hren Sie den Befehl -!MESSAGE -!MESSAGE NMAKE /f "syslogevt_vc6.mak". -!MESSAGE -!MESSAGE Sie k�nnen beim Ausf�hren von NMAKE eine Konfiguration angeben -!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: -!MESSAGE -!MESSAGE NMAKE /f "syslogevt_vc6.mak" CFG="syslogevt_vc6 - Win32 Debug" -!MESSAGE -!MESSAGE F�r die Konfiguration stehen zur Auswahl: -!MESSAGE -!MESSAGE "syslogevt_vc6 - Win32 Release" (basierend auf "Win32 (x86) Console Application") -!MESSAGE "syslogevt_vc6 - Win32 Debug" (basierend auf "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "syslogevt_vc6 - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "syslogevt.r" -# PROP Intermediate_Dir "syslogevt.r" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x407 /d "NDEBUG" -# ADD RSC /l 0x407 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 $(IntDir)\syslogevt.res kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"syslogevt.exe" -# SUBTRACT LINK32 /pdb:none -# Begin Special Build Tool -IntDir=.\syslogevt.r -SOURCE="$(InputPath)" -PreLink_Desc=Compiling Resources -PreLink_Cmds=rc $(IntDir)\syslogevt.rc -# End Special Build Tool - -!ELSEIF "$(CFG)" == "syslogevt_vc6 - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "syslogevt.d" -# PROP Intermediate_Dir "syslogevt.d" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD BASE RSC /l 0x407 /d "_DEBUG" -# ADD RSC /l 0x407 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 $(IntDir)\syslogevt.res kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# Begin Special Build Tool -IntDir=.\syslogevt.d -SOURCE="$(InputPath)" -PreLink_Desc=Compiling Resources -PreLink_Cmds=rc $(IntDir)\syslogevt.rc -# End Special Build Tool - -!ENDIF - -# Begin Target - -# Name "syslogevt_vc6 - Win32 Release" -# Name "syslogevt_vc6 - Win32 Debug" -# Begin Source File - -SOURCE=.\syslogevt.c -# End Source File -# Begin Source File - -SOURCE=.\syslogevt.mc - -!IF "$(CFG)" == "syslogevt_vc6 - Win32 Release" - -# Begin Custom Build - Compiling Messages -IntDir=.\syslogevt.r -InputPath=.\syslogevt.mc - -BuildCmds= \ - mc -r $(IntDir) syslogevt.mc - -"$(IntDir)\syslogevt.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"$(IntDir)\msg00001.bin" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"syslogevt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) -# End Custom Build - -!ELSEIF "$(CFG)" == "syslogevt_vc6 - Win32 Debug" - -# Begin Custom Build - Compiling Messages -IntDir=.\syslogevt.d -InputPath=.\syslogevt.mc - -BuildCmds= \ - mc -r $(IntDir) syslogevt.mc - -"$(IntDir)\syslogevt.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"$(IntDir)\msg00001.bin" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"syslogevt.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) -# End Custom Build - -!ENDIF - -# End Source File -# End Target -# End Project diff --git a/sm5/posix/getopt.c b/sm5/posix/getopt.c deleted file mode 100644 index 289d137e20babf967f75a5baa19c904b2ff5b68a..0000000000000000000000000000000000000000 --- a/sm5/posix/getopt.c +++ /dev/null @@ -1,1277 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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 */ diff --git a/sm5/posix/getopt.h b/sm5/posix/getopt.h deleted file mode 100644 index 4283c35b168acb3a4a4770cd6f646797478128ab..0000000000000000000000000000000000000000 --- a/sm5/posix/getopt.h +++ /dev/null @@ -1,181 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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 */ diff --git a/sm5/posix/getopt1.c b/sm5/posix/getopt1.c deleted file mode 100644 index ad06cc7f9e84b3ee030c454f85805dbd290e06cf..0000000000000000000000000000000000000000 --- a/sm5/posix/getopt1.c +++ /dev/null @@ -1,196 +0,0 @@ -/* 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 */ diff --git a/sm5/posix/regcomp.c b/sm5/posix/regcomp.c deleted file mode 100644 index f25ecae5fd7a966d0c7235cb7410680e43cca59b..0000000000000000000000000000000000000000 --- a/sm5/posix/regcomp.c +++ /dev/null @@ -1,3544 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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; -} diff --git a/sm5/posix/regex.c b/sm5/posix/regex.c deleted file mode 100644 index 98d86e1b8059fe3e061e53f4df02e53acacccf38..0000000000000000000000000000000000000000 --- a/sm5/posix/regex.c +++ /dev/null @@ -1,61 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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 diff --git a/sm5/posix/regex.h b/sm5/posix/regex.h deleted file mode 100644 index 314292b69645111a0a46e89a5ccf1a830ccd9b64..0000000000000000000000000000000000000000 --- a/sm5/posix/regex.h +++ /dev/null @@ -1,574 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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 __STDC__ - -# 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) -# 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: -*/ diff --git a/sm5/posix/regex_internal.c b/sm5/posix/regex_internal.c deleted file mode 100644 index f969c7c89fd3d61a2f0a8096d33d2038bdc945f3..0000000000000000000000000000000000000000 --- a/sm5/posix/regex_internal.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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); -} diff --git a/sm5/posix/regex_internal.h b/sm5/posix/regex_internal.h deleted file mode 100644 index bf84ad6270f5d06ada1cf10e82f8517ebec3a00f..0000000000000000000000000000000000000000 --- a/sm5/posix/regex_internal.h +++ /dev/null @@ -1,742 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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 */ diff --git a/sm5/posix/regexec.c b/sm5/posix/regexec.c deleted file mode 100644 index 6ea14a6c480335feb0a1d11c4572a5edc6960c58..0000000000000000000000000000000000000000 --- a/sm5/posix/regexec.c +++ /dev/null @@ -1,3977 +0,0 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 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); -} diff --git a/sm5/scsicmds.c b/sm5/scsicmds.c deleted file mode 100644 index 19c55a198c8cf7c4bd2c2e13c74bbb3cf87a5daa..0000000000000000000000000000000000000000 --- a/sm5/scsicmds.c +++ /dev/null @@ -1,1942 +0,0 @@ -/* - * scsicmds.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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 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 "config.h" -#include "int64.h" -#include "extern.h" -#include "scsicmds.h" -#include "utility.h" - -const char *scsicmds_c_cvsid="$Id: scsicmds.c,v 1.76 2004/07/11 15:16:31 dpgilbert Exp $" -CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -/* for passing global control variables */ -extern smartmonctrl *con; - -/* 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 = sprintf(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++; - sprintf(&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 = sprintf(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"}, /* 0x15 */ - {MODE_SENSE, "mode sense"}, /* 0x1a */ - {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */ - {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */ - {LOG_SENSE, "log sense"}, /* 0x4d */ - {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */ - {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */ -}; - -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; - - 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) -{ - memset(out, 0, sizeof(struct scsi_sense_disect)); - if ((SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) && - (io_buf->resp_sense_len > 7)) { - out->error_code = (io_buf->sensep[0] & 0x7f); - 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]; - } - } -} - -static int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo) -{ - if (SCSI_SK_NOT_READY == sinfo->sense_key) { - 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; - } else if (SCSI_SK_ILLEGAL_REQUEST == sinfo->sense_key) { - if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc) - return SIMPLE_ERR_BAD_OPCODE; - else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc) - return SIMPLE_ERR_BAD_FIELD; - else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc) - return SIMPLE_ERR_BAD_PARAM; - } else if (SCSI_SK_UNIT_ATTENTION == sinfo->sense_key) - return SIMPLE_ERR_TRY_AGAIN; - return SIMPLE_NO_ERROR; -} - -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"; - default: - return "unknown error"; - } -} - -/* 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 sections 7.6 and 8.2 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(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - if ((res = scsiSimpleSenseFilter(&sinfo))) - return res; - /* sanity check on response */ - if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != 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; - /* 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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] != pagenum)) - return SIMPLE_ERR_BAD_RESP; - if (0 == ((pBuf[2] << 8) + pBuf[3])) - return SIMPLE_ERR_BAD_RESP; - return 0; -} - -/* 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 sections 7.9 and 8.4 [mode subpage==0] */ -int scsiModeSense(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - status = scsiSimpleSenseFilter(&sinfo); - if (SIMPLE_ERR_TRY_AGAIN == status) { - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.7 and 8.4 */ -int scsiModeSelect(int 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 status, 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] &= 0x3f; /* Mask of 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.10 and 8.4 [mode subpage==0] */ -int scsiModeSense10(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - status = scsiSimpleSenseFilter(&sinfo); - if (SIMPLE_ERR_TRY_AGAIN == status) { - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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. SAM sections 7.8 and 8.4 */ -int scsiModeSelect10(int 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 status, 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] &= 0x3f; /* Mask of 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.4 and 8.6 */ -int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen) -{ - struct scsi_sense_disect sinfo; - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - 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] = INQUIRY; - cdb[4] = bufLen; - io_hdr.cmnd = cdb; - io_hdr.cmnd_len = sizeof(cdb); - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 section 7.4 and 8.6 */ -int scsiInquiryVpd(int 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 status, res; - - if ((bufLen < 0) || (bufLen > 255)) - return -EINVAL; - 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - 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 section 7.24 */ -int scsiRequestSense(int device, struct scsi_sense_disect * sense_info) -{ - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - UINT8 buff[18]; - int status, len; - UINT8 ecode; - - 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); - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if ((0 == status) && (sense_info)) { - ecode = buff[0] & 0x7f; - sense_info->error_code = ecode; - sense_info->sense_key = buff[2] & 0xf; - sense_info->asc = 0; - sense_info->ascq = 0; - if ((0x70 == ecode) || (0x71 == ecode)) { - len = buff[7] + 8; - if (len > 13) { - sense_info->asc = buff[12]; - sense_info->ascq = buff[13]; - } - } - } - return status; -} - -/* 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 section 7.25 */ -int scsiSendDiagnostic(int device, int functioncode, UINT8 *pBuf, int bufLen) -{ - struct scsi_cmnd_io io_hdr; - struct scsi_sense_disect sinfo; - UINT8 cdb[6]; - UINT8 sense[32]; - int status; - - 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); - io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST; - /* worst case is an extended foreground self test on a big disk */ - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 section 7.17 */ -int scsiReceiveDiagnostic(int 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]; - 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] = 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - return scsiSimpleSenseFilter(&sinfo); -} - -/* TEST UNIT READY command. SPC section 7.28 (probably in SBC as well) */ -static int _testunitready(int device, struct scsi_sense_disect * sinfo) -{ - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - UINT8 sense[32]; - int status; - - 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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(int 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; -} - -/* 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) { - 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(int 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, - 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, - 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, - MPAGE_CONTROL_CHANGEABLE, - iecp->raw_chg, sizeof(iecp->raw_chg)); - else if (6 == iecp->modese_len) - err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, - 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(int 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; - memset(rout, 0, 2); /* mode data length==0 for mode select */ - } else { - resp_len = rout[0] + 1; - memset(rout, 0, 1); /* mode data length==0 for mode select */ - } - sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ - rout[offset] &= 0x7f; /* mask off PS bit */ - if (enabled) { - rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED; - if (con->reportscsiioctl > 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 (con->reportscsiioctl > 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 (con->reportscsiioctl > 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(int device, UINT8 *currenttemp, UINT8 *triptemp) -{ - UINT8 tBuf[252]; - int err; - - memset(tBuf, 0, sizeof(tBuf)); - if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 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(int 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, 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(int device) -{ - UINT8 tBuf[256]; - - 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 */ - return scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8); -} - -int scsiSmartDefaultSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0); -} - -int scsiSmartShortSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0); -} - -int scsiSmartExtendSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, - NULL, 0); -} - -int scsiSmartShortCapSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0); -} - -int scsiSmartExtendCapSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, - NULL, 0); -} - -int scsiSmartSelfTestAbort(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0); -} - -/* Returns 0 and the expected duration of an extended self test (in seconds) - if successful; any other return value indicates a failure. */ -int scsiFetchExtendedSelfTestTime(int 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, - 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, - 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; - 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 15 */ -int scsiCountFailedSelfTests(int 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, resp, - LOG_RESP_SELF_TEST_LEN, 0))) { - if (noisy) - pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err)); - return -1; - } - if (resp[0] != 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(int fd, int * inProgress) -{ - int num; - UINT8 * ucp; - unsigned char resp[LOG_RESP_SELF_TEST_LEN]; - - if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 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(int 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, 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, 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; -} - -/* 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(int 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, - 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, - 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, - MPAGE_CONTROL_CHANGEABLE, - ch_buff, sizeof(ch_buff)); - else - err = scsiModeSense10(device, CONTROL_MODE_PAGE, - 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; - memset(buff, 0, 2); - } else { - resp_len = buff[0] + 1; - memset(buff, 0, 1); - } - sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ - buff[offset] &= 0x7f; /* mask off PS 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(int 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, - 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, - 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; -} - diff --git a/sm5/scsicmds.cpp b/sm5/scsicmds.cpp deleted file mode 100644 index 6672a95e034d1d0f6ee5ebefa0c93a78978e49eb..0000000000000000000000000000000000000000 --- a/sm5/scsicmds.cpp +++ /dev/null @@ -1,1942 +0,0 @@ -/* - * scsicmds.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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 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 "config.h" -#include "int64.h" -#include "extern.h" -#include "scsicmds.h" -#include "utility.h" - -const char *scsicmds_c_cvsid="$Id: scsicmds.cpp,v 1.76 2004/07/11 15:16:31 dpgilbert Exp $" -CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; - -/* for passing global control variables */ -extern smartmonctrl *con; - -/* 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 = sprintf(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++; - sprintf(&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 = sprintf(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"}, /* 0x15 */ - {MODE_SENSE, "mode sense"}, /* 0x1a */ - {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */ - {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */ - {LOG_SENSE, "log sense"}, /* 0x4d */ - {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */ - {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */ -}; - -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; - - 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) -{ - memset(out, 0, sizeof(struct scsi_sense_disect)); - if ((SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) && - (io_buf->resp_sense_len > 7)) { - out->error_code = (io_buf->sensep[0] & 0x7f); - 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]; - } - } -} - -static int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo) -{ - if (SCSI_SK_NOT_READY == sinfo->sense_key) { - 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; - } else if (SCSI_SK_ILLEGAL_REQUEST == sinfo->sense_key) { - if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc) - return SIMPLE_ERR_BAD_OPCODE; - else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc) - return SIMPLE_ERR_BAD_FIELD; - else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc) - return SIMPLE_ERR_BAD_PARAM; - } else if (SCSI_SK_UNIT_ATTENTION == sinfo->sense_key) - return SIMPLE_ERR_TRY_AGAIN; - return SIMPLE_NO_ERROR; -} - -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"; - default: - return "unknown error"; - } -} - -/* 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 sections 7.6 and 8.2 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(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - if ((res = scsiSimpleSenseFilter(&sinfo))) - return res; - /* sanity check on response */ - if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != 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; - /* 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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] != pagenum)) - return SIMPLE_ERR_BAD_RESP; - if (0 == ((pBuf[2] << 8) + pBuf[3])) - return SIMPLE_ERR_BAD_RESP; - return 0; -} - -/* 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 sections 7.9 and 8.4 [mode subpage==0] */ -int scsiModeSense(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - status = scsiSimpleSenseFilter(&sinfo); - if (SIMPLE_ERR_TRY_AGAIN == status) { - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.7 and 8.4 */ -int scsiModeSelect(int 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 status, 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] &= 0x3f; /* Mask of 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.10 and 8.4 [mode subpage==0] */ -int scsiModeSense10(int device, int pagenum, 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - status = scsiSimpleSenseFilter(&sinfo); - if (SIMPLE_ERR_TRY_AGAIN == status) { - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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. SAM sections 7.8 and 8.4 */ -int scsiModeSelect10(int 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 status, 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] &= 0x3f; /* Mask of 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 sections 7.4 and 8.6 */ -int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen) -{ - struct scsi_sense_disect sinfo; - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - 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] = INQUIRY; - cdb[4] = bufLen; - io_hdr.cmnd = cdb; - io_hdr.cmnd_len = sizeof(cdb); - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 section 7.4 and 8.6 */ -int scsiInquiryVpd(int 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 status, res; - - if ((bufLen < 0) || (bufLen > 255)) - return -EINVAL; - 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[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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - 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 section 7.24 */ -int scsiRequestSense(int device, struct scsi_sense_disect * sense_info) -{ - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - UINT8 buff[18]; - int status, len; - UINT8 ecode; - - 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); - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if ((0 == status) && (sense_info)) { - ecode = buff[0] & 0x7f; - sense_info->error_code = ecode; - sense_info->sense_key = buff[2] & 0xf; - sense_info->asc = 0; - sense_info->ascq = 0; - if ((0x70 == ecode) || (0x71 == ecode)) { - len = buff[7] + 8; - if (len > 13) { - sense_info->asc = buff[12]; - sense_info->ascq = buff[13]; - } - } - } - return status; -} - -/* 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 section 7.25 */ -int scsiSendDiagnostic(int device, int functioncode, UINT8 *pBuf, int bufLen) -{ - struct scsi_cmnd_io io_hdr; - struct scsi_sense_disect sinfo; - UINT8 cdb[6]; - UINT8 sense[32]; - int status; - - 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); - io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST; - /* worst case is an extended foreground self test on a big disk */ - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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 section 7.17 */ -int scsiReceiveDiagnostic(int 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]; - 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] = 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - scsi_do_sense_disect(&io_hdr, &sinfo); - return scsiSimpleSenseFilter(&sinfo); -} - -/* TEST UNIT READY command. SPC section 7.28 (probably in SBC as well) */ -static int _testunitready(int device, struct scsi_sense_disect * sinfo) -{ - struct scsi_cmnd_io io_hdr; - UINT8 cdb[6]; - UINT8 sense[32]; - int status; - - 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; - - status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); - if (0 != status) - return status; - 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(int 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; -} - -/* 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) { - 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(int 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, - 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, - 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, - MPAGE_CONTROL_CHANGEABLE, - iecp->raw_chg, sizeof(iecp->raw_chg)); - else if (6 == iecp->modese_len) - err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, - 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(int 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; - memset(rout, 0, 2); /* mode data length==0 for mode select */ - } else { - resp_len = rout[0] + 1; - memset(rout, 0, 1); /* mode data length==0 for mode select */ - } - sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ - rout[offset] &= 0x7f; /* mask off PS bit */ - if (enabled) { - rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED; - if (con->reportscsiioctl > 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 (con->reportscsiioctl > 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 (con->reportscsiioctl > 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(int device, UINT8 *currenttemp, UINT8 *triptemp) -{ - UINT8 tBuf[252]; - int err; - - memset(tBuf, 0, sizeof(tBuf)); - if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 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(int 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, 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(int device) -{ - UINT8 tBuf[256]; - - 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 */ - return scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8); -} - -int scsiSmartDefaultSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0); -} - -int scsiSmartShortSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0); -} - -int scsiSmartExtendSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, - NULL, 0); -} - -int scsiSmartShortCapSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0); -} - -int scsiSmartExtendCapSelfTest(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, - NULL, 0); -} - -int scsiSmartSelfTestAbort(int device) -{ - return scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0); -} - -/* Returns 0 and the expected duration of an extended self test (in seconds) - if successful; any other return value indicates a failure. */ -int scsiFetchExtendedSelfTestTime(int 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, - 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, - 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; - 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 15 */ -int scsiCountFailedSelfTests(int 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, resp, - LOG_RESP_SELF_TEST_LEN, 0))) { - if (noisy) - pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err)); - return -1; - } - if (resp[0] != 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(int fd, int * inProgress) -{ - int num; - UINT8 * ucp; - unsigned char resp[LOG_RESP_SELF_TEST_LEN]; - - if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 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(int 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, 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, 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; -} - -/* 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(int 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, - 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, - 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, - MPAGE_CONTROL_CHANGEABLE, - ch_buff, sizeof(ch_buff)); - else - err = scsiModeSense10(device, CONTROL_MODE_PAGE, - 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; - memset(buff, 0, 2); - } else { - resp_len = buff[0] + 1; - memset(buff, 0, 1); - } - sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ - buff[offset] &= 0x7f; /* mask off PS 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(int 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, - 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, - 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; -} - diff --git a/sm5/scsicmds.h b/sm5/scsicmds.h deleted file mode 100644 index 3aae4ab5d52e06599821d8e2a2e14039d01bc1e4..0000000000000000000000000000000000000000 --- a/sm5/scsicmds.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * scsicmds.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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,v 1.50 2004/07/11 15:16:09 dpgilbert Exp $\n" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "int64.h" - -/* #define SCSI_DEBUG 1 */ /* Comment out to disable command debugging */ - -/* Following conditional defines bypass inclusion of scsi/scsi.h and - * scsi/scsi_ioctl.h . Issue will be resolved later ... */ -#ifndef TEST_UNIT_READY -#define TEST_UNIT_READY 0x0 -#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 - -typedef unsigned char UINT8; -typedef 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 error_code; - UINT8 sense_key; - UINT8 asc; - UINT8 ascq; -}; - -/* 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; -}; - -/* 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 TEMPERATURE_LPAGE 0x0d -#define STARTSTOP_CYCLE_COUNTER_LPAGE 0x0e -#define APPLICATION_CLIENT_LPAGE 0x0f -#define SELFTEST_RESULTS_LPAGE 0x10 -#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 - -#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 - -/* defines for useful SCSI Status codes */ -#define SCSI_STATUS_CHECK_CONDITION 0x2 - -/* defines for useful Sense Key codes */ -#define SCSI_SK_NOT_READY 0x2 -#define SCSI_SK_ILLEGAL_REQUEST 0x5 -#define SCSI_SK_UNIT_ATTENTION 0x6 - -/* 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_UNKNOWN_FIELD 0x24 -#define SCSI_ASC_UNKNOWN_PARAM 0x26 -#define SCSI_ASC_WARNING 0xb -#define SCSI_ASC_IMPENDING_FAILURE 0x5d - -/* 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 */ - - -/* 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 6 /* 6 seconds should be ample */ -#define SCSI_TIMEOUT_SELF_TEST (5 * 60 * 60) /* allow max 5 hours for */ - /* extended foreground self test */ - - - -#define LOGPAGEHDRSIZE 4 - -void scsi_do_sense_disect(const struct scsi_cmnd_io * in, - struct scsi_sense_disect * out); - -const char * scsiErrString(int scsiErr); - -/* STANDARD SCSI Commands */ -int scsiTestUnitReady(int device); - -int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen); - -int scsiInquiryVpd(int device, int vpd_page, UINT8 *pBuf, int bufLen); - -int scsiLogSense(int device, int pagenum, UINT8 *pBuf, int bufLen, - int known_resp_len); - -int scsiModeSense(int device, int pagenum, int pc, UINT8 *pBuf, int bufLen); - -int scsiModeSelect(int device, int sp, UINT8 *pBuf, int bufLen); - -int scsiModeSense10(int device, int pagenum, int pc, UINT8 *pBuf, int bufLen); - -int scsiModeSelect10(int device, int sp, UINT8 *pBuf, int bufLen); - -int scsiModePageOffset(const UINT8 * resp, int len, int modese_len); - -int scsiRequestSense(int device, struct scsi_sense_disect * sense_info); - -int scsiSendDiagnostic(int device, int functioncode, UINT8 *pBuf, int bufLen); - -int scsiReceiveDiagnostic(int device, int pcv, int pagenum, UINT8 *pBuf, - int bufLen); - -/* SMART specific commands */ -int scsiCheckIE(int device, int hasIELogPage, int hasTempLogPage, UINT8 *asc, - UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp); - -int scsiFetchIECmpage(int 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(int 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(int device, int * durationSec, - int modese_len); -int scsiCountFailedSelfTests(int fd, int noisy); -int scsiSelfTestInProgress(int fd, int * inProgress); -int scsiFetchControlGLTSD(int device, int modese_len, int current); -int scsiSetControlGLTSD(int device, int enabled, int modese_len); -int scsiFetchTransportProtocol(int device, int modese_len); - -/* T10 Standard IE Additional Sense Code strings taken from t10.org */ - -const char* scsiGetIEString(UINT8 asc, UINT8 ascq); -int scsiGetTemp(int device, UINT8 *currenttemp, UINT8 *triptemp); - - -int scsiSmartIBMOfflineTest(int device); - -int scsiSmartDefaultSelfTest(int device); -int scsiSmartShortSelfTest(int device); -int scsiSmartExtendSelfTest(int device); -int scsiSmartShortCapSelfTest(int device); -int scsiSmartExtendCapSelfTest(int device); -int scsiSmartSelfTestAbort(int device); - -const char * scsiTapeAlertsTapeDevice(unsigned short code); -const char * scsiTapeAlertsChangerDevice(unsigned short code); - -const char * scsi_get_opcode_name(UINT8 opcode); -void dStrHex(const char* str, int len, int no_ascii); - -/* 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. */ -int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); - -#endif - diff --git a/sm5/scsiprint.c b/sm5/scsiprint.c deleted file mode 100644 index 7633c404e59699613dc577277a5b1b3fc7fe2c40..0000000000000000000000000000000000000000 --- a/sm5/scsiprint.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * scsiprint.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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 "extern.h" -#include "scsicmds.h" -#include "scsiprint.h" -#include "smartctl.h" -#include "utility.h" - -#define GBUF_SIZE 65535 - -const char* scsiprint_c_cvsid="$Id: scsiprint.c,v 1.79 2004/07/18 07:33:13 makisara Exp $" -CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// control block which points to external global control variables -extern smartmonctrl *con; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -UINT8 gBuf[GBUF_SIZE]; -#define LOG_RESP_LEN 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 gTapeAlertsLPage = 0; -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; - -// Compares failure type to policy in effect, and either exits or -// simply returns to the calling routine. -extern void failuretest(int type, int returnvalue); - -static void scsiGetSupportedLogPages(int device) -{ - int i, err; - - if ((err = scsiLogSense(device, SUPPORTED_LPAGES, gBuf, - LOG_RESP_LEN, 0))) { - if (con->reportscsiioctl > 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 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 TAPE_ALERTS_LPAGE: - gTapeAlertsLPage = 1; - break; - case SEAGATE_CACHE_LPAGE: - gSeagateCacheLPage = 1; - break; - case SEAGATE_FACTORY_LPAGE: - gSeagateFactoryLPage = 1; - break; - default: - break; - } - } -} - -void scsiGetSmartData(int device, int attribs) -{ - UINT8 asc; - UINT8 ascq; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - const char * cp; - int err; - - PRINT_ON(con); - if ((err = scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, - &ascq, ¤ttemp, &triptemp))) { - /* error message already announced */ - PRINT_OFF(con); - return; - } - PRINT_OFF(con); - cp = scsiGetIEString(asc, ascq); - if (cp) { - PRINT_ON(con); - pout("SMART Health Status: %s [asc=%x,ascq=%x]\n", cp, asc, ascq); - PRINT_OFF(con); - } else if (gIecMPage) - pout("SMART Health Status: OK\n"); - - if (attribs && !gTempLPage) { - if (currenttemp || triptemp) - pout("\n"); - 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); - } -} - - -// Returns number of logged errors or zero if none or -1 if fetching -// TapeAlerts fails -static char *severities = "CWI"; - -static int scsiGetTapeAlertsData(int device, int peripheral_type) -{ - unsigned short pagelength; - unsigned short parametercode; - int i, err; - char *s; - const char *ts; - int failures = 0; - - PRINT_ON(con); - if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, gBuf, - LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) { - pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return -1; - } - if (gBuf[0] != 0x2e) { - pout("TapeAlerts Log Sense Failed\n"); - PRINT_OFF(con); - 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(con); - - if (! failures) - pout("TapeAlert: OK\n"); - - return failures; -} - -void scsiGetStartStopData(int device) -{ - UINT32 currentStartStop; - UINT32 recommendedStartStop; - int err, len, k; - char str[6]; - - if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != STARTSTOP_CYCLE_COUNTER_LPAGE) { - PRINT_ON(con); - pout("StartStop Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - return; - } - len = ((gBuf[2] << 8) | gBuf[3]) + 4; - if (len > 13) { - for (k = 0; k < 2; ++k) - str[k] = gBuf[12 + k]; - str[k] = '\0'; - pout("Manufactured in week %s of year ", str); - for (k = 0; k < 4; ++k) - str[k] = gBuf[8 + k]; - str[k] = '\0'; - pout("%s\n", str); - } - if (len > 39) { - recommendedStartStop = (gBuf[28] << 24) | (gBuf[29] << 16) | - (gBuf[30] << 8) | gBuf[31]; - currentStartStop = (gBuf[36] << 24) | (gBuf[37] << 16) | - (gBuf[38] << 8) | gBuf[39]; - pout("Current start stop count: %u times\n", currentStartStop); - pout("Recommended maximum start stop count: %u times\n", - recommendedStartStop); - } -} - -static void scsiPrintSeagateCacheLPage(int 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, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != SEAGATE_CACHE_LPAGE) { - PRINT_ON(con); - pout("Seagate Cache Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - 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 (con->reportscsiioctl > 0) { - PRINT_ON(con); - pout("Vendor (Seagate) cache lpage has unexpected parameter" - ", skip\n"); - PRINT_OFF(con); - } - 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; - } -} - -static void scsiPrintSeagateFactoryLPage(int device) -{ - int k, j, num, pl, pc, len, err; - unsigned char * ucp; - unsigned char * xp; - uint64_t ull; - - if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != SEAGATE_FACTORY_LPAGE) { - PRINT_ON(con); - pout("Seagate Factory Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - 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 8: - break; - default: - if (con->reportscsiioctl > 0) { - PRINT_ON(con); - pout("\nVendor (Seagate) factory lpage has unexpected " - "parameter, skip\n"); - PRINT_OFF(con); - } - return; - } - num -= pl; - ucp += pl; - } - pout("Vendor (Seagate) factory 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(" number of hours powered up"); break; - case 8: pout(" number of minutes until next internal SMART test"); - 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]; - } - if (0 == pc) - pout(" = %.2f\n", uint64_to_double(ull) / 60.0 ); - else - pout(" = %"PRIu64"\n", ull); - num -= pl; - ucp += pl; - } -} - -static void scsiPrintErrorCounterLog(int device) -{ - struct scsiErrorCounter errCounterArr[3]; - struct scsiErrorCounter * ecp; - struct scsiNonMediumError nme; - int found[3] = {0, 0, 0}; - const char * pageNames[3] = {"read: ", "write: ", "verify: "}; - int k; - double processed_gb; - - if (0 == scsiLogSense(device, READ_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]); - found[0] = 1; - } - if (0 == scsiLogSense(device, WRITE_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]); - found[1] = 1; - } - if (0 == scsiLogSense(device, VERIFY_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]); - ecp = &errCounterArr[2]; - for (k = 0; k < 7; ++k) { - if (ecp->gotPC[k] && ecp->counter[k]) { - found[2] = 1; - break; - } - } - } - if (found[0] || found[1] || found[2]) { - pout("\nError counter log:\n"); - pout(" Errors Corrected Total Total " - "Correction Gigabytes Total\n"); - pout(" delay: [rereads/ errors " - "algorithm processed uncorrected\n"); - pout(" minor | major rewrites] corrected " - "invocations [10^9 bytes] errors\n"); - for (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 = uint64_to_double(ecp->counter[5]) / 1000000000.0; - pout(" %12.3f %8"PRIu64"\n", processed_gb, ecp->counter[6]); - } - } - else - pout("\nDevice does not support Error Counter logging\n"); - if (0 == scsiLogSense(device, NON_MEDIUM_ERROR_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeNonMediumErrPage(gBuf, &nme); - if (nme.gotPC0) - pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0); - } -} - -const char * self_test_code[] = { - "Default ", - "Background short", - "Background long ", - "Reserved(3) ", - "Abort background", - "Foreground short", - "Foreground long ", - "Reserved(7) " -}; - -const char * self_test_result[] = { - "Completed ", - "Interrupted ('-X' switch)", - "Interrupted (bus 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 Working Draft SCSI Primary Commands - 3 (SPC-3) pages 231-233 -// T10/1416-D Rev 10 -static int scsiPrintSelfTest(int device) -{ - int num, k, n, res, err, durationSec; - int noheader = 1; - UINT8 * ucp; - uint64_t ull=0; - - if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, gBuf, - LOG_RESP_SELF_TEST_LEN, 0))) { - PRINT_ON(con); - pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return 1; - } - if (gBuf[0] != SELFTEST_RESULTS_LPAGE) { - PRINT_ON(con); - pout("Self-test Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - return 1; - } - // compute page length - num = (gBuf[2] << 8) + gBuf[3]; - // Log sense page length 0x190 bytes - if (num != 0x190) { - PRINT_ON(con); - pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num); - PRINT_OFF(con); - return 1; - } - // 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("\nSMART 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]); - - // self-test result - res = ucp[4] & 0xf; - 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)) - pout(" 0x%16"PRIx64, ull); - 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 - pout("\n"); - if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, - modese_len)) && (durationSec > 0)) { - pout("Long (extended) Self Test duration: %d seconds " - "[%.1f minutes]\n", durationSec, durationSec / 60.0); - } - 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 */ -static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) -{ - char manufacturer[9]; - char product[17]; - char revision[5]; - char timedatetz[DATEANDEPOCHLEN]; - struct scsi_iec_mode_page iec; - int err, iec_err, len, val; - int is_tape = 0; - int peri_dt = 0; - int returnval=0; - - memset(gBuf, 0, 36); - if ((err = scsiStdInquiry(device, gBuf, 36))) { - PRINT_ON(con); - pout("Standard Inquiry failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return 1; - } - len = gBuf[4] + 5; - peri_dt = gBuf[0] & 0x1f; - if (peripheral_type) - *peripheral_type = peri_dt; - if (! all) - return 0; - - if (len < 36) { - PRINT_ON(con); - pout("Short INQUIRY response, skip product id\n"); - PRINT_OFF(con); - return 1; - } - memset(manufacturer, 0, sizeof(manufacturer)); - strncpy(manufacturer, (char *)&gBuf[8], 8); - - memset(product, 0, sizeof(product)); - strncpy(product, (char *)&gBuf[16], 16); - - memset(revision, 0, sizeof(revision)); - strncpy(revision, (char *)&gBuf[32], 4); - pout("Device: %s %s Version: %s\n", manufacturer, product, revision); - - /* 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(con); - gIecMPage = 0; - return 1; - } - } else - modese_len = iec.modese_len; - - if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { - /* should use VPD page 0x83 and fall back to this page (0x80) - * if 0x83 not supported. NAA requires a lot of decoding code */ - len = gBuf[3]; - gBuf[4 + len] = '\0'; - pout("Serial number: %s\n", &gBuf[4]); - } - else if (con->reportscsiioctl > 0) { - PRINT_ON(con); - 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(con); - } - - // 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 - val = scsiFetchTransportProtocol(device, modese_len); - if ((val >= 0) && (val <= 0xf)) - pout("Transport protocol: %s\n", transport_proto_arr[val]); - - // 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(con); - 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(con); - } else if (SIMPLE_ERR_NO_MEDIUM == err) { - PRINT_ON(con); - pout("NO MEDIUM present on device\n"); - PRINT_OFF(con); - } else if (SIMPLE_ERR_BECOMING_READY == err) { - PRINT_ON(con); - pout("device becoming ready (wait)\n"); - PRINT_OFF(con); - } else { - PRINT_ON(con); - pout("device Test Unit Ready [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - } - failuretest(MANDATORY_CMD, returnval|=FAILID); - } - - if (iec_err) { - if (!is_tape) { - PRINT_ON(con); - pout("Device does not support SMART"); - if (con->reportscsiioctl > 0) - pout(" [%s]\n", scsiErrString(iec_err)); - else - pout("\n"); - PRINT_OFF(con); - } - gIecMPage = 0; - return 0; - } - - if (!is_tape) - pout("Device supports SMART and 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(int device) -{ - struct scsi_iec_mode_page iec; - int err; - - if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { - PRINT_ON(con); - pout("unable to fetch IEC (SMART) mode page [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - return 1; - } else - modese_len = iec.modese_len; - - if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) { - PRINT_ON(con); - pout("unable to enable Exception control and warning [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - 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(int device) -{ - struct scsi_iec_mode_page iec; - int err; - - if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { - PRINT_ON(con); - pout("unable to fetch IEC (SMART) mode page [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - return 1; - } else - modese_len = iec.modese_len; - - if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) { - PRINT_ON(con); - pout("unable to disable Exception control and warning [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - 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; -} - -void scsiPrintTemp(int 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); -} - -/* Main entry point used by smartctl command. Return 0 for success */ -int scsiPrintMain(int fd) -{ - int checkedSupportedLogPages = 0; - UINT8 peripheral_type = 0; - int returnval = 0; - int res, durationSec; - - if (scsiGetDriveInfo(fd, &peripheral_type, con->driveinfo)) { - failuretest(MANDATORY_CMD, returnval |= FAILID); - } - - if (con->smartenable) { - if (scsiSmartEnable(fd)) - failuretest(MANDATORY_CMD, returnval |= FAILSMART); - } - - if (con->smartdisable) { - if (scsiSmartDisable(fd)) - failuretest(MANDATORY_CMD,returnval |= FAILSMART); - } - - if (con->smartautosaveenable) { - if (scsiSetControlGLTSD(fd, 0, modese_len)) { - pout("Enable autosave (clear GLTSD bit) failed\n"); - failuretest(OPTIONAL_CMD,returnval |= FAILSMART); - } - } - - if (con->smartautosavedisable) { - if (scsiSetControlGLTSD(fd, 1, modese_len)) { - pout("Disable autosave (set GLTSD bit) failed\n"); - failuretest(OPTIONAL_CMD,returnval |= FAILSMART); - } - } - - if (con->checksmart) { - scsiGetSupportedLogPages(fd); - checkedSupportedLogPages = 1; - if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) || - (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */ - if (gTapeAlertsLPage) { - if (con->driveinfo) - pout("TapeAlert Supported\n"); - if (-1 == scsiGetTapeAlertsData(fd, peripheral_type)) - failuretest(OPTIONAL_CMD, returnval |= FAILSMART); - } - else - pout("TapeAlert Not Supported\n"); - } else { /* disk, cd/dvd, enclosure, etc */ - scsiGetSmartData(fd, con->smartvendorattrib); - } - } - if (con->smartvendorattrib) { - if (! checkedSupportedLogPages) - scsiGetSupportedLogPages(fd); - if (gTempLPage) { - if (con->checksmart) - pout("\n"); - scsiPrintTemp(fd); - } - if (gStartStopLPage) - scsiGetStartStopData(fd); - if (SCSI_PT_DIRECT_ACCESS == peripheral_type) { - if (gSeagateCacheLPage) - scsiPrintSeagateCacheLPage(fd); - if (gSeagateFactoryLPage) - scsiPrintSeagateFactoryLPage(fd); - } - } - if (con->smarterrorlog) { - scsiPrintErrorCounterLog(fd); - if (1 == scsiFetchControlGLTSD(fd, modese_len, 1)) - pout("\n[GLTSD (Global Logging Target Save Disable) set. " - "Enable Save with '-S on']\n"); - } - if (con->smartselftestlog) { - if (! checkedSupportedLogPages) - scsiGetSupportedLogPages(fd); - res = 0; - if (gSelfTestLPage) - res = scsiPrintSelfTest(fd); - else { - pout("Device does not support Self Test logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (0 != res) - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (con->smartexeoffimmediate) { - if (scsiSmartDefaultSelfTest(fd)) { - pout( "Default Self Test Failed\n"); - return returnval; - } - pout("Default Self Test Successful\n"); - } - if (con->smartshortcapselftest) { - if (scsiSmartShortCapSelfTest(fd)) { - pout("Short Foreground Self Test Failed\n"); - return returnval; - } - pout("Short Foreground Self Test Successful\n"); - } - if (con->smartshortselftest ) { - if ( scsiSmartShortSelfTest(fd)) { - pout("Short Background Self Test Failed\n"); - return returnval; - } - pout("Short Background Self Test has begun\n"); - pout("Use smartctl -X to abort test\n"); - } - if (con->smartextendselftest) { - if (scsiSmartExtendSelfTest(fd)) { - pout("Extended Background Self Test Failed\n"); - return returnval; - } - pout("Extended Background Self Test has begun\n"); - if ((0 == scsiFetchExtendedSelfTestTime(fd, &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"); - } - if (con->smartextendcapselftest) { - if (scsiSmartExtendCapSelfTest(fd)) { - pout("Extended Foreground Self Test Failed\n"); - return returnval; - } - pout("Extended Foreground Self Test Successful\n"); - } - if (con->smartselftestabort) { - if (scsiSmartSelfTestAbort(fd)) { - pout("Self Test Abort Failed\n"); - return returnval; - } - pout("Self Test returned without error\n"); - } - return returnval; -} diff --git a/sm5/scsiprint.cpp b/sm5/scsiprint.cpp deleted file mode 100644 index 4c1282300a54a220dfe9fb5ae24e93cbfc0139a7..0000000000000000000000000000000000000000 --- a/sm5/scsiprint.cpp +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * scsiprint.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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 "extern.h" -#include "scsicmds.h" -#include "scsiprint.h" -#include "smartctl.h" -#include "utility.h" - -#define GBUF_SIZE 65535 - -const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.79 2004/07/18 07:33:13 makisara Exp $" -CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// control block which points to external global control variables -extern smartmonctrl *con; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -UINT8 gBuf[GBUF_SIZE]; -#define LOG_RESP_LEN 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 gTapeAlertsLPage = 0; -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; - -// Compares failure type to policy in effect, and either exits or -// simply returns to the calling routine. -extern void failuretest(int type, int returnvalue); - -static void scsiGetSupportedLogPages(int device) -{ - int i, err; - - if ((err = scsiLogSense(device, SUPPORTED_LPAGES, gBuf, - LOG_RESP_LEN, 0))) { - if (con->reportscsiioctl > 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 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 TAPE_ALERTS_LPAGE: - gTapeAlertsLPage = 1; - break; - case SEAGATE_CACHE_LPAGE: - gSeagateCacheLPage = 1; - break; - case SEAGATE_FACTORY_LPAGE: - gSeagateFactoryLPage = 1; - break; - default: - break; - } - } -} - -void scsiGetSmartData(int device, int attribs) -{ - UINT8 asc; - UINT8 ascq; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - const char * cp; - int err; - - PRINT_ON(con); - if ((err = scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, - &ascq, ¤ttemp, &triptemp))) { - /* error message already announced */ - PRINT_OFF(con); - return; - } - PRINT_OFF(con); - cp = scsiGetIEString(asc, ascq); - if (cp) { - PRINT_ON(con); - pout("SMART Health Status: %s [asc=%x,ascq=%x]\n", cp, asc, ascq); - PRINT_OFF(con); - } else if (gIecMPage) - pout("SMART Health Status: OK\n"); - - if (attribs && !gTempLPage) { - if (currenttemp || triptemp) - pout("\n"); - 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); - } -} - - -// Returns number of logged errors or zero if none or -1 if fetching -// TapeAlerts fails -static char *severities = "CWI"; - -static int scsiGetTapeAlertsData(int device, int peripheral_type) -{ - unsigned short pagelength; - unsigned short parametercode; - int i, err; - char *s; - const char *ts; - int failures = 0; - - PRINT_ON(con); - if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, gBuf, - LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) { - pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return -1; - } - if (gBuf[0] != 0x2e) { - pout("TapeAlerts Log Sense Failed\n"); - PRINT_OFF(con); - 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(con); - - if (! failures) - pout("TapeAlert: OK\n"); - - return failures; -} - -void scsiGetStartStopData(int device) -{ - UINT32 currentStartStop; - UINT32 recommendedStartStop; - int err, len, k; - char str[6]; - - if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != STARTSTOP_CYCLE_COUNTER_LPAGE) { - PRINT_ON(con); - pout("StartStop Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - return; - } - len = ((gBuf[2] << 8) | gBuf[3]) + 4; - if (len > 13) { - for (k = 0; k < 2; ++k) - str[k] = gBuf[12 + k]; - str[k] = '\0'; - pout("Manufactured in week %s of year ", str); - for (k = 0; k < 4; ++k) - str[k] = gBuf[8 + k]; - str[k] = '\0'; - pout("%s\n", str); - } - if (len > 39) { - recommendedStartStop = (gBuf[28] << 24) | (gBuf[29] << 16) | - (gBuf[30] << 8) | gBuf[31]; - currentStartStop = (gBuf[36] << 24) | (gBuf[37] << 16) | - (gBuf[38] << 8) | gBuf[39]; - pout("Current start stop count: %u times\n", currentStartStop); - pout("Recommended maximum start stop count: %u times\n", - recommendedStartStop); - } -} - -static void scsiPrintSeagateCacheLPage(int 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, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != SEAGATE_CACHE_LPAGE) { - PRINT_ON(con); - pout("Seagate Cache Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - 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 (con->reportscsiioctl > 0) { - PRINT_ON(con); - pout("Vendor (Seagate) cache lpage has unexpected parameter" - ", skip\n"); - PRINT_OFF(con); - } - 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; - } -} - -static void scsiPrintSeagateFactoryLPage(int device) -{ - int k, j, num, pl, pc, len, err; - unsigned char * ucp; - unsigned char * xp; - uint64_t ull; - - if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, gBuf, - LOG_RESP_LEN, 0))) { - PRINT_ON(con); - pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return; - } - if (gBuf[0] != SEAGATE_FACTORY_LPAGE) { - PRINT_ON(con); - pout("Seagate Factory Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - 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 8: - break; - default: - if (con->reportscsiioctl > 0) { - PRINT_ON(con); - pout("\nVendor (Seagate) factory lpage has unexpected " - "parameter, skip\n"); - PRINT_OFF(con); - } - return; - } - num -= pl; - ucp += pl; - } - pout("Vendor (Seagate) factory 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(" number of hours powered up"); break; - case 8: pout(" number of minutes until next internal SMART test"); - 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]; - } - if (0 == pc) - pout(" = %.2f\n", uint64_to_double(ull) / 60.0 ); - else - pout(" = %"PRIu64"\n", ull); - num -= pl; - ucp += pl; - } -} - -static void scsiPrintErrorCounterLog(int device) -{ - struct scsiErrorCounter errCounterArr[3]; - struct scsiErrorCounter * ecp; - struct scsiNonMediumError nme; - int found[3] = {0, 0, 0}; - const char * pageNames[3] = {"read: ", "write: ", "verify: "}; - int k; - double processed_gb; - - if (0 == scsiLogSense(device, READ_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]); - found[0] = 1; - } - if (0 == scsiLogSense(device, WRITE_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]); - found[1] = 1; - } - if (0 == scsiLogSense(device, VERIFY_ERROR_COUNTER_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]); - ecp = &errCounterArr[2]; - for (k = 0; k < 7; ++k) { - if (ecp->gotPC[k] && ecp->counter[k]) { - found[2] = 1; - break; - } - } - } - if (found[0] || found[1] || found[2]) { - pout("\nError counter log:\n"); - pout(" Errors Corrected Total Total " - "Correction Gigabytes Total\n"); - pout(" delay: [rereads/ errors " - "algorithm processed uncorrected\n"); - pout(" minor | major rewrites] corrected " - "invocations [10^9 bytes] errors\n"); - for (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 = uint64_to_double(ecp->counter[5]) / 1000000000.0; - pout(" %12.3f %8"PRIu64"\n", processed_gb, ecp->counter[6]); - } - } - else - pout("\nDevice does not support Error Counter logging\n"); - if (0 == scsiLogSense(device, NON_MEDIUM_ERROR_LPAGE, gBuf, - LOG_RESP_LEN, 0)) { - scsiDecodeNonMediumErrPage(gBuf, &nme); - if (nme.gotPC0) - pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0); - } -} - -const char * self_test_code[] = { - "Default ", - "Background short", - "Background long ", - "Reserved(3) ", - "Abort background", - "Foreground short", - "Foreground long ", - "Reserved(7) " -}; - -const char * self_test_result[] = { - "Completed ", - "Interrupted ('-X' switch)", - "Interrupted (bus 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 Working Draft SCSI Primary Commands - 3 (SPC-3) pages 231-233 -// T10/1416-D Rev 10 -static int scsiPrintSelfTest(int device) -{ - int num, k, n, res, err, durationSec; - int noheader = 1; - UINT8 * ucp; - uint64_t ull=0; - - if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, gBuf, - LOG_RESP_SELF_TEST_LEN, 0))) { - PRINT_ON(con); - pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return 1; - } - if (gBuf[0] != SELFTEST_RESULTS_LPAGE) { - PRINT_ON(con); - pout("Self-test Log Sense Failed, page mismatch\n"); - PRINT_OFF(con); - return 1; - } - // compute page length - num = (gBuf[2] << 8) + gBuf[3]; - // Log sense page length 0x190 bytes - if (num != 0x190) { - PRINT_ON(con); - pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num); - PRINT_OFF(con); - return 1; - } - // 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("\nSMART 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]); - - // self-test result - res = ucp[4] & 0xf; - 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)) - pout(" 0x%16"PRIx64, ull); - 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 - pout("\n"); - if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, - modese_len)) && (durationSec > 0)) { - pout("Long (extended) Self Test duration: %d seconds " - "[%.1f minutes]\n", durationSec, durationSec / 60.0); - } - 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 */ -static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) -{ - char manufacturer[9]; - char product[17]; - char revision[5]; - char timedatetz[DATEANDEPOCHLEN]; - struct scsi_iec_mode_page iec; - int err, iec_err, len, val; - int is_tape = 0; - int peri_dt = 0; - int returnval=0; - - memset(gBuf, 0, 36); - if ((err = scsiStdInquiry(device, gBuf, 36))) { - PRINT_ON(con); - pout("Standard Inquiry failed [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - return 1; - } - len = gBuf[4] + 5; - peri_dt = gBuf[0] & 0x1f; - if (peripheral_type) - *peripheral_type = peri_dt; - if (! all) - return 0; - - if (len < 36) { - PRINT_ON(con); - pout("Short INQUIRY response, skip product id\n"); - PRINT_OFF(con); - return 1; - } - memset(manufacturer, 0, sizeof(manufacturer)); - strncpy(manufacturer, (char *)&gBuf[8], 8); - - memset(product, 0, sizeof(product)); - strncpy(product, (char *)&gBuf[16], 16); - - memset(revision, 0, sizeof(revision)); - strncpy(revision, (char *)&gBuf[32], 4); - pout("Device: %s %s Version: %s\n", manufacturer, product, revision); - - /* 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(con); - gIecMPage = 0; - return 1; - } - } else - modese_len = iec.modese_len; - - if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { - /* should use VPD page 0x83 and fall back to this page (0x80) - * if 0x83 not supported. NAA requires a lot of decoding code */ - len = gBuf[3]; - gBuf[4 + len] = '\0'; - pout("Serial number: %s\n", &gBuf[4]); - } - else if (con->reportscsiioctl > 0) { - PRINT_ON(con); - 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(con); - } - - // 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 - val = scsiFetchTransportProtocol(device, modese_len); - if ((val >= 0) && (val <= 0xf)) - pout("Transport protocol: %s\n", transport_proto_arr[val]); - - // 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(con); - 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(con); - } else if (SIMPLE_ERR_NO_MEDIUM == err) { - PRINT_ON(con); - pout("NO MEDIUM present on device\n"); - PRINT_OFF(con); - } else if (SIMPLE_ERR_BECOMING_READY == err) { - PRINT_ON(con); - pout("device becoming ready (wait)\n"); - PRINT_OFF(con); - } else { - PRINT_ON(con); - pout("device Test Unit Ready [%s]\n", scsiErrString(err)); - PRINT_OFF(con); - } - failuretest(MANDATORY_CMD, returnval|=FAILID); - } - - if (iec_err) { - if (!is_tape) { - PRINT_ON(con); - pout("Device does not support SMART"); - if (con->reportscsiioctl > 0) - pout(" [%s]\n", scsiErrString(iec_err)); - else - pout("\n"); - PRINT_OFF(con); - } - gIecMPage = 0; - return 0; - } - - if (!is_tape) - pout("Device supports SMART and 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(int device) -{ - struct scsi_iec_mode_page iec; - int err; - - if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { - PRINT_ON(con); - pout("unable to fetch IEC (SMART) mode page [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - return 1; - } else - modese_len = iec.modese_len; - - if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) { - PRINT_ON(con); - pout("unable to enable Exception control and warning [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - 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(int device) -{ - struct scsi_iec_mode_page iec; - int err; - - if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { - PRINT_ON(con); - pout("unable to fetch IEC (SMART) mode page [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - return 1; - } else - modese_len = iec.modese_len; - - if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) { - PRINT_ON(con); - pout("unable to disable Exception control and warning [%s]\n", - scsiErrString(err)); - PRINT_OFF(con); - 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; -} - -void scsiPrintTemp(int 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); -} - -/* Main entry point used by smartctl command. Return 0 for success */ -int scsiPrintMain(int fd) -{ - int checkedSupportedLogPages = 0; - UINT8 peripheral_type = 0; - int returnval = 0; - int res, durationSec; - - if (scsiGetDriveInfo(fd, &peripheral_type, con->driveinfo)) { - failuretest(MANDATORY_CMD, returnval |= FAILID); - } - - if (con->smartenable) { - if (scsiSmartEnable(fd)) - failuretest(MANDATORY_CMD, returnval |= FAILSMART); - } - - if (con->smartdisable) { - if (scsiSmartDisable(fd)) - failuretest(MANDATORY_CMD,returnval |= FAILSMART); - } - - if (con->smartautosaveenable) { - if (scsiSetControlGLTSD(fd, 0, modese_len)) { - pout("Enable autosave (clear GLTSD bit) failed\n"); - failuretest(OPTIONAL_CMD,returnval |= FAILSMART); - } - } - - if (con->smartautosavedisable) { - if (scsiSetControlGLTSD(fd, 1, modese_len)) { - pout("Disable autosave (set GLTSD bit) failed\n"); - failuretest(OPTIONAL_CMD,returnval |= FAILSMART); - } - } - - if (con->checksmart) { - scsiGetSupportedLogPages(fd); - checkedSupportedLogPages = 1; - if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) || - (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */ - if (gTapeAlertsLPage) { - if (con->driveinfo) - pout("TapeAlert Supported\n"); - if (-1 == scsiGetTapeAlertsData(fd, peripheral_type)) - failuretest(OPTIONAL_CMD, returnval |= FAILSMART); - } - else - pout("TapeAlert Not Supported\n"); - } else { /* disk, cd/dvd, enclosure, etc */ - scsiGetSmartData(fd, con->smartvendorattrib); - } - } - if (con->smartvendorattrib) { - if (! checkedSupportedLogPages) - scsiGetSupportedLogPages(fd); - if (gTempLPage) { - if (con->checksmart) - pout("\n"); - scsiPrintTemp(fd); - } - if (gStartStopLPage) - scsiGetStartStopData(fd); - if (SCSI_PT_DIRECT_ACCESS == peripheral_type) { - if (gSeagateCacheLPage) - scsiPrintSeagateCacheLPage(fd); - if (gSeagateFactoryLPage) - scsiPrintSeagateFactoryLPage(fd); - } - } - if (con->smarterrorlog) { - scsiPrintErrorCounterLog(fd); - if (1 == scsiFetchControlGLTSD(fd, modese_len, 1)) - pout("\n[GLTSD (Global Logging Target Save Disable) set. " - "Enable Save with '-S on']\n"); - } - if (con->smartselftestlog) { - if (! checkedSupportedLogPages) - scsiGetSupportedLogPages(fd); - res = 0; - if (gSelfTestLPage) - res = scsiPrintSelfTest(fd); - else { - pout("Device does not support Self Test logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (0 != res) - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); - } - if (con->smartexeoffimmediate) { - if (scsiSmartDefaultSelfTest(fd)) { - pout( "Default Self Test Failed\n"); - return returnval; - } - pout("Default Self Test Successful\n"); - } - if (con->smartshortcapselftest) { - if (scsiSmartShortCapSelfTest(fd)) { - pout("Short Foreground Self Test Failed\n"); - return returnval; - } - pout("Short Foreground Self Test Successful\n"); - } - if (con->smartshortselftest ) { - if ( scsiSmartShortSelfTest(fd)) { - pout("Short Background Self Test Failed\n"); - return returnval; - } - pout("Short Background Self Test has begun\n"); - pout("Use smartctl -X to abort test\n"); - } - if (con->smartextendselftest) { - if (scsiSmartExtendSelfTest(fd)) { - pout("Extended Background Self Test Failed\n"); - return returnval; - } - pout("Extended Background Self Test has begun\n"); - if ((0 == scsiFetchExtendedSelfTestTime(fd, &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"); - } - if (con->smartextendcapselftest) { - if (scsiSmartExtendCapSelfTest(fd)) { - pout("Extended Foreground Self Test Failed\n"); - return returnval; - } - pout("Extended Foreground Self Test Successful\n"); - } - if (con->smartselftestabort) { - if (scsiSmartSelfTestAbort(fd)) { - pout("Self Test Abort Failed\n"); - return returnval; - } - pout("Self Test returned without error\n"); - } - return returnval; -} diff --git a/sm5/scsiprint.h b/sm5/scsiprint.h deleted file mode 100644 index f1b2eae58084b78a94d13c752ba452601f772b3d..0000000000000000000000000000000000000000 --- a/sm5/scsiprint.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * scsiprint.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> - * - * Additional SCSI work: - * Copyright (C) 2003-4 Douglas Gilbert <dougg@torque.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., 675 Mass Ave, Cambridge, MA 02139, 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/ - * - */ - - -/* scsismart version number */ -#ifndef SCSI_PRINT_H_ -#define SCSI_PRINT_H_ - -#define SCSIPRINT_H_CVSID "$Id: scsiprint.h,v 1.18 2004/01/27 15:29:17 ballen4705 Exp $\n" - -int scsiPrintMain(int fd); - -#endif diff --git a/sm5/smartctl.8.in b/sm5/smartctl.8.in deleted file mode 100644 index e64f4a54b7b56b313b06837e3fffbd462cac777b..0000000000000000000000000000000000000000 --- a/sm5/smartctl.8.in +++ /dev/null @@ -1,1236 +0,0 @@ -.ig - Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - - $Id: smartctl.8.in,v 1.57 2004/07/16 15:49:56 ballen4705 Exp $ - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - 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., 675 - Mass Ave, Cambridge, MA 02139, 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/ - -.. -.TH SMARTCTL 8 CURRENT_CVS_DATE CURRENT_CVS_VERSION CURRENT_CVS_DATE -.SH NAME -\fBsmartctl\fP \- Control and Monitor Utility for SMART Disks - -.SH SYNOPSIS -.B smartctl [options] device - -.SH FULL PATH -.B /usr/sbin/smartctl - -.SH PACKAGE VERSION -CURRENT_CVS_VERSION released CURRENT_CVS_DATE at CURRENT_CVS_TIME - -.SH DESCRIPTION -\fBsmartctl\fP controls the Self\-Monitoring, Analysis and Reporting -Technology (SMART) system built into many ATA\-3 and later ATA, IDE and -SCSI\-3 hard 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 \fBsmartctl\fP -is compatible with ATA/ATAPI\-5 and earlier standards (see REFERENCES -below) - -\fBsmartctl\fP is a command line utility designed to perform SMART -tasks such as printing the SMART self\-test and error logs, enabling -and disabling SMART automatic testing, and initiating device -self\-tests. Note: if the user issues a SMART command that is -(apparently) not implemented by the device, \fBsmartctl\fP will print -a warning message but issue the command anyway (see the \fB\-T, -\-\-tolerance\fP option below). This should not cause problems: on -most devices, unimplemented SMART commands issued to a drive are -ignored and/or return an error. - -\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. Device paths are as follows: -.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. -More general paths (such as devfs ones) may also be specified. -.IP \fBFREEBSD\fP: 9 -Use the forms \fB"/dev/ad[0\-9]+"\fP for IDE/ATA -devices and \fB"/dev/da[0\-9]+"\fP for SCSI devices. -.IP \fBNETBSD\fP: 9 -Use the form \fB"/dev/wd[0\-9]+[cd]"\fP for IDE/ATA -devices. Be sure to specify correct "whole disk" partition letter -for your architecture. -.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. -.IP \fBWINDOWS\fP: 9 -Use the forms \fB"/dev/hd[a\-j]"\fP for IDE/ATA devices -"\\\\.\\PhysicalDisk[0\-9]" on WinNT4/2000/XP, -\fB"/dev/hd[a\-d]"\fP for standard IDE/ATA devices on Win95/98/98SE/ME, -and \fB"/dev/scsi[0\-9][0\-f]"\fP for SCSI devices on ASPI adapter 0\-9, ID 0\-15. -The prefix \fB"/dev/"\fP is optional. -.IP \fBCYGWIN\fP: 9 -See "WINDOWS" above. -.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 over\-ride -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 -(hexidecimal). 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. - -SCSI devices only accept the options \fB\-h, \-V, \-i, \-a, \-A, \-d, -\-s, \-S,\-H, \-t, \-C, \-l selftest, \-l error, \-r,\fP and -\fB\-X\fP. TapeAlert devices only accept the options \fB\-h, \-V, -\-i, \-a, \-A, \-d, \-s, \-S, \-t, \-l selftest, \-l error, \-r,\fP -and \fB\-H\fP. - -Long options are not supported on all systems. Use -.B \'smartctl \-h\' -to see the available options. - -.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 CVS\-id 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.) -.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 \'\-l -directory\' option. - -.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). -.TP -.B \-d TYPE, \-\-device=TYPE -Specifies the type of the device. The valid arguments to this option -are \fIata\fP, \fIscsi\fP, and \fI3ware,N\fP. If this option is not -used then \fBsmartctl\fP will attempt to guess the device type from -the device name. - -To look at ATA disks behind 3ware SCSI RAID controllers, use syntax -such as: -.nf -\fBsmartctl \-a \-d 3ware,2 /dev/sda\fP -.fi -.nf -\fBsmartctl \-a \-d 3ware,0 /dev/twe0\fP -.fi -.nf -\fBsmartctl \-a \-d 3ware,1 /dev/twa0\fP -.fi -where in the argument \fI3ware,N\fP, the integer N is the disk number -(3ware \'port\') within the 3ware ATA RAID controller. The allowed -values of N are from 0 to 15 inclusive. 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. The final form, which refers to devices /dev/twa0-15, must be -used with 3ware 9000 series controllers, which use the 3w-9xxx driver. - -Note that if the special character device nodes /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. Likewise /dev/twe0 refers to -the first 6/7/8000-series controller, /dev/twa1 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. See \fBhttp://smartmontools.sourceforge.net/\fP for -instructions. 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/twa0-15 and /dev/twe0-15. -The necessary WRITE LOG commands can not be passed through the SCSI -interface. - -.B 3ware controllers are currently ONLY supported under Linux. - -.TP -.B \-T TYPE, \-\-tolerance=TYPE -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/ATAPI\-5 Specification if the device implements -the SMART command set" and "\fBoptional\fP" means "not required by the -ATA/ATAPI\-5 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 implemented", -followed shortly by "Error: unable to enable Feature X". 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 -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. - -.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 -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 -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. - -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 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 someplace safe as soon as you can. -.TP -.B \-c, \-\-capabilities -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 -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 -ATA/ATAPI\-5 disks seem to respect their meaning, so we have retained -the option of printing the Attribute values. - -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 \-l TYPE, \-\-log=TYPE -Prints either the SMART Error Log, the SMART Self\-Test Log, the SMART -Selective Self-Test Log [ATA only], or the Log Directory [ATA only]. -The valid arguments to this option are: - -.I error -\- prints only the 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 -(ATA\-7) 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 selftest -\- 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. If any errors -were detected, 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. - -.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 selective [ATA] -\- Some ATA\-7 disks (example: Maxtor) also maintain a selective -self\-test log. 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). This is a new smartmontools feature; please -report unusual or incorrect behavior to the smartmontools\-support -mailing list. - -.I directory -\- if the device supports the General Purpose Logging feature set -(ATA\-6 and ATA\-7 only) 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. [Please note: this is a new, experimental -feature. We would like to add support for printing the contents of -extended and comprehensive SMART self\-test and error logs. If your -disk supports these, and you would like to assist, please contact the -\fBsmartmontools\fP developers.] - -.TP -.B \-v N,OPTION, \-\-vendorattribute=N,OPTION -Sets a vendor\-specific display OPTION for Attribute N. This option -may be used multiple times. Valid arguments to this option are: - -.I help -\- Prints (to STDOUT) a list of all valid arguments to this option, -then exits. - -.I 9,minutes -\- Raw Attribute number 9 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 9,seconds -\- Raw Attribute number 9 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 9,halfminutes -\- Raw Attribute number 9 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 9,temp -\- Raw Attribute number 9 is the disk temperature in Celsius. - -.I 192,emergencyretractcyclect -\- Raw Attribute number 192 is the Emergency Retract Cycle Count. - -.I 193,loadunload -\- Raw Attribute number 193 contains two 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 194,10xCelsius -\- Raw Attribute number 194 is ten times the disk temperature in -Celsius. This is used by some Samsung disks (example: model SV1204H -with RK100\-13 firmware). - -.I 194,unknown -\- Raw Attribute number 194 is NOT the disk temperature, and its -interpretation is unknown. This is primarily useful for the \-P -(presets) option. - -.I 198,offlinescanuncsectorct -\- Raw Attribute number 198 is the Offline Scan UNC Sector Count. - -.I 200,writeerrorcount -\- Raw Attribute number 200 is the Write Error Count. - -.I 201,detectedtacount -\- Raw Attribute number 201 is the Detected TA Count. - -.I 220,temp -\- Raw Attribute number 220 is the disk temperature in Celsius. - -Note: a table of hard drive models, listing which Attribute -corresponds to temperature, can be found at: -http://coredump.free.fr/linux/hddtemp.db - -.I N,raw8 -\- Print the Raw value of Attribute N as six 8\-bit unsigned base\-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw8\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw8\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw16 -\- Print the Raw value of Attribute N as three 16\-bit unsigned base\-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw16\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw16\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw48 -\- Print the Raw value of Attribute N as a 48\-bit unsigned base\-10 -integer. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw48\' prints Raw values for ALL Attributes in -this form. The form (for example) \'123,raw48\' only prints the Raw -value for Attribute 123 in this form. - -.TP -.B \-F TYPE, \-\-firmwarebug=TYPE -Modifies the behavior of \fBsmartctl\fP to compensate for some known -and understood device firmware bug. The arguments to this option are -exclusive, so that only the final option given is used. The valid -values 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 -device database (see note below). - -.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 more recent Samsung disks (firmware revisions ending in "\-23") -the number of ATA errors reported is byte swapped. Enabling this -option tells \fBsmartctl\fP to evaluate this quantity in byte\-reversed -order. - -Note that an explicit \'\-F\' option on the command line will -over\-ride any preset values for \'\-F\' (see the \'\-P\' option -below). - -.TP -.B \-P TYPE, \-\-presets=TYPE -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 over\-ride 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. - -.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 can be run at a time, so this option should only be used once per -command line. - -The valid arguments to this option are: - -.I offline -\- 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. [In the case of SCSI devices runs the default self test in -foreground. No entry is placed in the self test log.] - -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 short -\- runs SMART Short Self Test (usually under ten minutes). -[Note: in the case of SCSI devices, -this command option runs the "Background short" self\-test.] -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 long -\- runs SMART Extended Self Test (tens of minutes). -[Note: in the case of SCSI devices, -this command option runs the "Background long" self\-test.] -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 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 - -\- [ATA ONLY] [NEW EXPERIMENTAL SMARTCTL FEATURE] 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. For example -the command: -.nf - smartctl \-t select,10\-20 /dev/hda -.fi -runs a self test on one span consisting of LBAs ten to twenty -(inclusive). 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). - -[Note: this new experimental smartmontools feature is currently only -available under Linux. The Linux kernel must be compiled with the -configuration option CONFIG_IDE_TASKFILE_IO enabled. Please report -unusual or incorrect behavior to the smartmontools\-support mailing -list.] - -.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. - -.TP -.B \-C, \-\-captive -Runs self\-tests in captive mode. This has no effect with \'\-t -offline\' or if the \'\-t\' option is not used. [Note: in the case of -SCSI devices, this command option runs the self\-test in "Foreground" -mode.] - -\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 - -.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 EXAMPLES -.nf -.B smartctl \-a /dev/hda -.fi -Print all SMART information for drive /dev/hda (Primary Master). -.PP -.nf -.B smartctl \-s off /dev/hdd -.fi -Disable SMART on drive /dev/hdd (Secondary Slave). -.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 \-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. -.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 -.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, or device did not return an IDENTIFY DEVICE structure. -.TP -.B Bit 2: -Some SMART 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: -SMART status check returned "DISK OK" but we found prefail Attributes <= threshold. -.TP -.B Bit 5: -SMART status check returned "DISK OK" but we found that some (usage -or prefail) Attributes have been <= threshold at some time in the -past. -.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. - -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. - -.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 AUTHOR -\fBBruce Allen\fP smartmontools\-support@lists.sourceforge.net -.fi -University of Wisconsin \- Milwaukee Physics Department - -.PP -.SH CONTRIBUTORS -The following have made large contributions to smartmontools: -.nf -\fBCasper Dik\fP (Solaris SCSI interface) -\fBChristian Franke\fP (Windows interface) -\fBDouglas Gilbert\fP (SCSI subsystem) -\fBGuido Guenther\fP (Autoconf/Automake packaging) -\fBGeoffrey Keating\fP (Darwin ATA interface) -\fBEduard Martinescu\fP (FreeBSD interface) -\fBFr\*'ed\*'eric L. W. Meunier\fP (Web site and Mailing list) -\fBKeiji Sawada\fP (Solaris ATA interface) -\fBSergey Svishchev\fP (NetBSD interface) -\fBPhil Williams\fP (User interface and drive database) -.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: -.nf -.B -http://smartmontools.sourceforge.net/ - -.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 http://www.linuxjournal.com/article.php?sid=6983 -online. - -If you would like to understand better how SMART works, and what it -does, a good place to start is Section 8.41 of the "AT Attachment with -Packet Interface\-5" (ATA/ATAPI\-5) specification. This documents the -SMART functionality which the \fBsmartmontools\fP utilities provide -access to. You can find Revision 1 of this document at -\fBhttp://www.t13.org/project/d1321r1c.pdf\fP . - -.fi -Future versions of the specifications (ATA/ATAPI\-6 and ATA/ATAPI\-7), -and later revisions (2, 3) of the ATA/ATAPI\-5 specification are -available from \fBhttp://www.t13.org/#FTP_site\fP . - -.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 documents may be found in the References section of the -\fBsmartmontools\fP home page at -\fBhttp://smartmontools.sourceforge.net/\fP . - -.SH -CVS ID OF THIS PAGE: -$Id: smartctl.8.in,v 1.57 2004/07/16 15:49:56 ballen4705 Exp $ -.\" Local Variables: -.\" mode: nroff -.\" End: diff --git a/sm5/smartctl.c b/sm5/smartctl.c deleted file mode 100644 index 3cc41e9295c2a49d064d8cec36a22f443402a817..0000000000000000000000000000000000000000 --- a/sm5/smartctl.c +++ /dev/null @@ -1,889 +0,0 @@ -/* - * smartctl.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 "config.h" -#include <errno.h> -#include <stdio.h> -#include <sys/types.h> -#include <string.h> -#include <stdarg.h> -#ifdef HAVE_GETOPT_LONG -#include <getopt.h> -#endif -#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000) -#include <unistd.h> -#endif -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "scsicmds.h" -#include "scsiprint.h" -#include "smartctl.h" -#include "utility.h" - -#ifdef NEED_SOLARIS_ATA_CODE -extern const char *os_solaris_ata_s_cvsid; -#endif -#if defined(_WIN32) && defined(_MSC_VER) -extern const char *int64_vc6_c_cvsid; -#endif -extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid; -const char* smartctl_c_cvsid="$Id: smartctl.c,v 1.134 2004/08/16 22:44:27 ballen4705 Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// This is a block containing all the "control variables". We declare -// this globally in this file, and externally in other files. -smartmonctrl *con=NULL; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Track memory use -extern int64_t bytes; - -void printslogan(){ - pout("smartctl version %s [%s] Copyright (C) 2002-4 Bruce Allen\n", PACKAGE_VERSION, SMARTMONTOOLS_BUILD_HOST); - pout("Home page is " PACKAGE_HOMEPAGE "\n\n"); - return; -} - -void PrintOneCVS(const char *a_cvs_id){ - char out[CVSMAXLEN]; - printone(out,a_cvs_id); - pout("%s",out); - return; -} - -void printcopy(){ - char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; - - pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n"); - pout("is free software, and you are welcome to redistribute it\n"); - pout("under the terms of the GNU General Public License Version 2.\n"); - pout("See http://www.gnu.org for further details.\n\n"); - pout("CVS version IDs of files used to build this code are:\n"); - PrintOneCVS(atacmdnames_c_cvsid); - PrintOneCVS(atacmds_c_cvsid); - PrintOneCVS(ataprint_c_cvsid); -#if defined(_WIN32) && defined(_MSC_VER) - PrintOneCVS(int64_vc6_c_cvsid); -#endif - PrintOneCVS(knowndrives_c_cvsid); - PrintOneCVS(os_XXXX_c_cvsid); -#ifdef NEED_SOLARIS_ATA_CODE - PrintOneCVS(os_solaris_ata_s_cvsid); -#endif - PrintOneCVS(scsicmds_c_cvsid); - PrintOneCVS(scsiprint_c_cvsid); - PrintOneCVS(smartctl_c_cvsid); - PrintOneCVS(utility_c_cvsid); - pout("\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); - pout("smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); - pout("smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); - pout("smartctl compile dated " __DATE__ " at "__TIME__ "\n"); - pout("smartmontools configure arguments: %s\n", configargs); - return; -} - -void UsageSummary(){ - pout("\nUse smartctl -h to get a usage summary\n\n"); - return; -} - -/* void prints help information for command syntax */ -void Usage (void){ - printf("Usage: smartctl [options] device\n\n"); - printf("============================================ SHOW INFORMATION OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" -" -a, --all \n" -" Show all SMART information for device\n\n" - ); -#else - printf( -" -h Display this help and exit\n" -" -V Print license, copyright, and version information\n" -" -i Show identity information for device\n" -" -a Show all SMART information for device\n\n" - ); -#endif - printf("================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -q TYPE, --quietmode=TYPE (ATA)\n" -" Set smartctl quiet mode to one of: errorsonly, silent\n\n" -" -d TYPE, --device=TYPE\n" -" Specify device type to one of: ata, scsi, 3ware,N\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" - ); -#else - printf( -" -q TYPE Set smartctl quiet mode to one of: errorsonly, silent (ATA)\n" -" -d TYPE Specify device type to one of: ata, scsi, 3ware,N\n" -" -T TYPE Tolerance: normal, conservative,permissive,verypermissive (ATA\n" -" -b TYPE Set action on bad checksum to one of: warn, exit, ignore (ATA)\n" -" -r TYPE Report transactions (see man page)\n\n" - ); -#endif - printf("============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" - ); -#else - printf( -" -s VALUE Enable/disable SMART on device (on/off)\n" -" -o VALUE Enable/disable device automatic offline testing (on/off) (ATA)\n" -" -S VALUE Enable/disable device Attribute autosave (on/off) (ATA)\n\n" - ); -#endif - printf("======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" -" -l TYPE, --log=TYPE\n" -" Show device log. TYPE: error, selftest, selective, directory\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: none, samsung, samsung2\n\n" -" -P TYPE, --presets=TYPE (ATA)\n" -" Drive-specific presets: use, ignore, show, showall\n\n" - ); -#else - printf( -" -H Show device SMART health status\n" -" -c Show device SMART capabilities (ATA)\n" -" -A Show device SMART vendor-specific Attributes and values (ATA)\n" -" -l TYPE Show device log. TYPE: error,selftest,selective,directory\n" -" -v N,OPT Set display OPTion for vendor Attribute N (see man page) (ATA)\n" -" -F TYPE Use firmware bug workaround: none, samsung, samsung2 (ATA)\n" -" -P TYPE Drive-specific presets: use, ignore, show, showall (ATA)\n\n" - ); -#endif - printf("============================================ DEVICE SELF-TEST OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -t TEST, --test=TEST\n" -" Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,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" -); -#else - printf( -" -t TEST Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n" -" -C Do test in captive mode (along with -t)\n" -" -X Abort any non-captive test\n\n" - ); -#endif - print_smartctl_examples(); - return; -} - -/* Returns a pointer to a static string containing a formatted list of the valid - arguments to the option opt or NULL on failure. Note 'v' case different */ -const char *getvalidarglist(char opt) { - switch (opt) { - case 'q': - return "errorsonly, silent"; - case 'd': - return "ata, scsi, 3ware,N"; - case 'T': - return "normal, conservative, permissive, verypermissive"; - case 'b': - return "warn, exit, ignore"; - case 'r': - return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; - case 's': - case 'o': - case 'S': - return "on, off"; - case 'l': - return "error, selftest, selective, directory"; - case 'P': - return "use, ignore, show, showall"; - case 't': - return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,on, afterselect,off"; - case 'F': - return "none, samsung, samsung2"; - case 'v': - default: - return NULL; - } -} - -/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where - <LIST> is the list of valid arguments for option opt. */ -void printvalidarglistmessage(char opt) { - char *s; - - if (opt=='v') - s=create_vendor_attribute_arg_list(); - else - s=(char *)getvalidarglist(opt); - - if (!s) { - pout("Error whilst constructing argument list for option %c", opt); - return; - } - - if (opt=='v'){ - pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", s); - free(s); - } - else { - // getvalidarglist() might produce a multiline or single line string. We - // need to figure out which to get the formatting right. - char separator = strchr(s, '\n') ? '\n' : ' '; - pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, (char *)s, separator); - } - - return; -} - -/* Takes command options and sets features to be run */ -void ParseOpts (int argc, char** argv){ - int optchar; - int badarg; - int captive; - unsigned char *charp; - extern char *optarg; - extern int optopt, optind, opterr; - char extraerror[256]; - // Please update getvalidarglist() if you edit shortopts - const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iav:P:t:CXF:"; -#ifdef HAVE_GETOPT_LONG - char *arg; - // 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, 's' }, - { "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' }, - { "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' }, - { 0, 0, 0, 0 } - }; -#endif - - memset(extraerror, 0, sizeof(extraerror)); - memset(con,0,sizeof(*con)); - con->testcase=-1; - opterr=optopt=0; - badarg = captive = FALSE; - - // This miserable construction is needed to get emacs to do proper indenting. Sorry! - while (-1 != (optchar = -#ifdef HAVE_GETOPT_LONG - getopt_long(argc, argv, shortopts, longopts, NULL) -#else - getopt(argc, argv, shortopts) -#endif - )){ - switch (optchar){ - case 'V': - con->dont_print=FALSE; - printslogan(); - printcopy(); - exit(0); - break; - case 'q': - if (!strcmp(optarg,"errorsonly")) { - con->printing_switchable = TRUE; - con->dont_print = FALSE; - } else if (!strcmp(optarg,"silent")) { - con->printing_switchable = FALSE; - con->dont_print = TRUE; - } else { - badarg = TRUE; - } - break; - case 'd': - if (!strcmp(optarg,"ata")) { - con->controller_type = CONTROLLER_ATA; - con->controller_port = 0; - } else if (!strcmp(optarg,"scsi")) { - con->controller_type = CONTROLLER_SCSI; - con->controller_port = 0; - } else { - // look for RAID-type device - int i; - char *s; - - // make a copy of the string to mess with - if (!(s = strdup(optarg))) { - con->dont_print = FALSE; - pout("No memory for argument of -d. Exiting...\n"); - exit(FAILCMD); - } else if (strncmp(s,"3ware,",6)) { - badarg = TRUE; - } else if (split_report_arg2(s, &i)) { - sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n"); - badarg = TRUE; - } else if (i<0 || i>15) { - sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i); - badarg = TRUE; - } else { - // NOTE: controller_port == disk number + 1 - con->controller_type = CONTROLLER_3WARE; - con->controller_port = i+1; - } - free(s); - } - break; - case 'T': - if (!strcmp(optarg,"normal")) { - con->conservative = FALSE; - con->permissive = 0; - } else if (!strcmp(optarg,"conservative")) { - con->conservative = TRUE; - } else if (!strcmp(optarg,"permissive")) { - if (con->permissive<0xff) - con->permissive++; - } else if (!strcmp(optarg,"verypermissive")) { - con->permissive=0xff; - } else { - badarg = TRUE; - } - break; - case 'b': - if (!strcmp(optarg,"warn")) { - con->checksumfail = FALSE; - con->checksumignore = FALSE; - } else if (!strcmp(optarg,"exit")) { - con->checksumfail = TRUE; - con->checksumignore = FALSE; - } else if (!strcmp(optarg,"ignore")) { - con->checksumignore = TRUE; - con->checksumfail = FALSE; - } 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))) { - con->dont_print = FALSE; - pout("Can't allocate memory to copy argument to -r option" - " - exiting\n"); - EXIT(FAILCMD); - } - if (split_report_arg(s, &i)) { - badarg = TRUE; - } else if (!strcmp(s,"ioctl")) { - con->reportataioctl = con->reportscsiioctl = i; - } else if (!strcmp(s,"ataioctl")) { - con->reportataioctl = i; - } else if (!strcmp(s,"scsiioctl")) { - con->reportscsiioctl = i; - } else { - badarg = TRUE; - } - free(s); - } - break; - case 's': - if (!strcmp(optarg,"on")) { - con->smartenable = TRUE; - con->smartdisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartdisable = TRUE; - con->smartenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'o': - if (!strcmp(optarg,"on")) { - con->smartautoofflineenable = TRUE; - con->smartautoofflinedisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartautoofflinedisable = TRUE; - con->smartautoofflineenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'S': - if (!strcmp(optarg,"on")) { - con->smartautosaveenable = TRUE; - con->smartautosavedisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartautosavedisable = TRUE; - con->smartautosaveenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'H': - con->checksmart = TRUE; - break; - case 'F': - if (!strcmp(optarg,"none")) { - con->fixfirmwarebug = FIX_NONE; - } else if (!strcmp(optarg,"samsung")) { - con->fixfirmwarebug = FIX_SAMSUNG; - } else if (!strcmp(optarg,"samsung2")) { - con->fixfirmwarebug = FIX_SAMSUNG2; - } else { - badarg = TRUE; - } - break; - case 'c': - con->generalsmartvalues = TRUE; - break; - case 'A': - con->smartvendorattrib = TRUE; - break; - case 'l': - if (!strcmp(optarg,"error")) { - con->smarterrorlog = TRUE; - } else if (!strcmp(optarg,"selftest")) { - con->smartselftestlog = TRUE; - } else if (!strcmp(optarg, "selective")) { - con->selectivetestlog = TRUE; - } else if (!strcmp(optarg,"directory")) { - con->smartlogdirectory = TRUE; - } else { - badarg = TRUE; - } - break; - case 'i': - con->driveinfo = TRUE; - break; - case 'a': - con->driveinfo = TRUE; - con->checksmart = TRUE; - con->generalsmartvalues = TRUE; - con->smartvendorattrib = TRUE; - con->smarterrorlog = TRUE; - con->smartselftestlog = TRUE; - con->selectivetestlog = TRUE; - break; - case 'v': - // parse vendor-specific definitions of attributes - if (!strcmp(optarg,"help")) { - char *s; - con->dont_print=FALSE; - printslogan(); - if (!(s = create_vendor_attribute_arg_list())) { - pout("Insufficient memory to construct argument list\n"); - EXIT(FAILCMD); - } - pout("The valid arguments to -v are:\n\thelp\n%s\n", s); - free(s); - EXIT(0); - } - charp=con->attributedefs; - if (!charp){ - pout("Fatal internal error in ParseOpts()\n"); - EXIT(FAILCMD); - } - if (parse_attribute_def(optarg, &charp)) - badarg = TRUE; - break; - case 'P': - if (!strcmp(optarg, "use")) { - con->ignorepresets = FALSE; - } else if (!strcmp(optarg, "ignore")) { - con->ignorepresets = TRUE; - } else if (!strcmp(optarg, "show")) { - con->showpresets = TRUE; - } else if (!strcmp(optarg, "showall")) { - showallpresets(); - EXIT(0); - } else { - badarg = TRUE; - } - break; - case 't': - if (!strcmp(optarg,"offline")) { - con->smartexeoffimmediate = TRUE; - con->testcase = OFFLINE_FULL_SCAN; - } else if (!strcmp(optarg,"short")) { - con->smartshortselftest = TRUE; - con->testcase = SHORT_SELF_TEST; - } else if (!strcmp(optarg,"long")) { - con->smartextendselftest = TRUE; - con->testcase = EXTEND_SELF_TEST; - } else if (!strcmp(optarg,"conveyance")) { - con->smartconveyanceselftest = TRUE; - con->testcase = CONVEYANCE_SELF_TEST; - } else if (!strcmp(optarg,"afterselect,on")) { - // scan remainder of disk after doing selected segments - con->scanafterselect=2; - } else if (!strcmp(optarg,"afterselect,off")) { - // don't scan remainder of disk after doing selected segments - con->scanafterselect=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') { - sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n"); - badarg = TRUE; - } else if (i<0 || i>65535) { - sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i); - badarg = TRUE; - } else { - con->pendingtime=i+1; - } - } else if (!strncmp(optarg,"select",strlen("select"))) { - // parse range of LBAs to test - uint64_t start, stop; - - if (split_selective_arg(optarg, &start, &stop)) { - sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n"); - badarg = TRUE; - } else { - if (con->smartselectivenumspans >= 5 || start > stop) { - if (start > stop) { - sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n", - start, stop, optarg); - } else { - sprintf(extraerror,"ERROR: No more than five selective self-test spans may be" - " defined\n"); - } - badarg = TRUE; - } - con->smartselectivespan[con->smartselectivenumspans][0] = start; - con->smartselectivespan[con->smartselectivenumspans][1] = stop; - con->smartselectivenumspans++; - con->testcase = SELECTIVE_SELF_TEST; - } - } else { - badarg = TRUE; - } - break; - case 'C': - captive = TRUE; - break; - case 'X': - con->smartselftestabort = TRUE; - con->testcase = ABORT_SELF_TEST; - break; - case 'h': - con->dont_print=FALSE; - printslogan(); - Usage(); - EXIT(0); - break; - case '?': - default: - con->dont_print=FALSE; - printslogan(); -#ifdef HAVE_GETOPT_LONG - // 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)) { - 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); - } -#endif - if (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. - pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg); - printvalidarglistmessage(optchar); - if (extraerror[0]) - pout("=======> %s", extraerror); - UsageSummary(); - EXIT(FAILCMD); - } - } - // 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 (con->printing_switchable) - con->dont_print=TRUE; - - // error message if user has asked for more than one test - if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+ - con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){ - con->dont_print=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 ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){ - con->dont_print=FALSE; - printslogan(); - if (con->pendingtime) - 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 && con->smartshortselftest) { - con->smartshortselftest = FALSE; - con->smartshortcapselftest = TRUE; - con->testcase = SHORT_CAPTIVE_SELF_TEST; - } else if (captive && con->smartextendselftest) { - con->smartextendselftest = FALSE; - con->smartextendcapselftest = TRUE; - con->testcase = EXTEND_CAPTIVE_SELF_TEST; - } - else if (captive && con->smartconveyanceselftest) { - con->smartconveyanceselftest = FALSE; - con->smartconveyancecapselftest = TRUE; - con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST; - } - else if (captive && con->smartselectiveselftest) { - con->smartselectiveselftest = FALSE; - con->smartselectivecapselftest = TRUE; - con->testcase = SELECTIVE_CAPTIVE_SELF_TEST; - } - - // 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); - } -} - -// Printing function (controlled by global con->dont_print) -// [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(char *fmt, ...){ - va_list ap; - - // initialize variable argument list - va_start(ap,fmt); - if (con->dont_print){ - va_end(ap); - return; - } - - // print out - vprintf(fmt,ap); - va_end(ap); - fflush(stdout); - return; -} - -// This function is used by utility.c to report LOG_CRIT errors. -// The smartctl version prints to stdout instead of syslog(). -void PrintOut(int priority, char *fmt, ...) { - va_list ap; - - // avoid warning message about unused variable from gcc -W: just - // change value of local copy. - priority=0; - - va_start(ap,fmt); - vprintf(fmt,ap); - va_end(ap); - return; -} - - -/* Main Program */ -int main (int argc, char **argv){ - int fd,retval=0; - char *device; - smartmonctrl control; - char *mode=NULL; - - // define control block for external functions - con=&control; - - // Part input arguments - ParseOpts(argc,argv); - - device = argv[argc-1]; - - // If use has specified 3ware controller, determine which interface - if (con->controller_type == CONTROLLER_3WARE) { - con->controller_type=guess_device_type(device); - if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR) - con->controller_type = CONTROLLER_3WARE_678K; - } - - if (con->controller_type == CONTROLLER_UNKNOWN) - con->controller_type=guess_device_type(device); - - if (con->controller_type == CONTROLLER_UNKNOWN) { - pout("Smartctl: please specify device type with the -d option.\n"); - UsageSummary(); - return FAILCMD; - } - - // set up mode for open() call. SCSI case is: - switch (con->controller_type) { - case CONTROLLER_SCSI: - mode="SCSI"; - break; - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - mode="ATA"; - break; - case CONTROLLER_3WARE_9000_CHAR: - mode="ATA_3WARE_9000"; - break; - case CONTROLLER_3WARE_678K_CHAR: - mode="ATA_3WARE_678K"; - break; - } - - // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the - // scsi generic device can be used (needs write permission for MODE - // SELECT command) plus O_NONBLOCK to stop open hanging if media not - // present (e.g. with st). Opening is retried O_RDONLY if read-only - // media prevents opening O_RDWR (it cannot happen for scsi generic - // devices, but it can for the others). - fd = deviceopen(device, mode); - if (fd<0) { - char errmsg[256]; - snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]); - errmsg[255]='\0'; - syserror(errmsg); - return FAILDEV; - } - - // now call appropriate ATA or SCSI routine - switch (con->controller_type) { - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - case CONTROLLER_3WARE_9000_CHAR: - case CONTROLLER_3WARE_678K_CHAR: - retval = ataPrintMain(fd); - break; - case CONTROLLER_SCSI: - retval = scsiPrintMain(fd); - break; - default: - pout("Smartctl: specify if this is an ATA or SCSI device with the -d option.\n"); - UsageSummary(); - return FAILCMD; - } - - return retval; -} diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp deleted file mode 100644 index 05d2f4964993042f686fd976605b85e1a9df3de9..0000000000000000000000000000000000000000 --- a/sm5/smartctl.cpp +++ /dev/null @@ -1,889 +0,0 @@ -/* - * smartctl.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 "config.h" -#include <errno.h> -#include <stdio.h> -#include <sys/types.h> -#include <string.h> -#include <stdarg.h> -#ifdef HAVE_GETOPT_LONG -#include <getopt.h> -#endif -#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000) -#include <unistd.h> -#endif -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "scsicmds.h" -#include "scsiprint.h" -#include "smartctl.h" -#include "utility.h" - -#ifdef NEED_SOLARIS_ATA_CODE -extern const char *os_solaris_ata_s_cvsid; -#endif -#if defined(_WIN32) && defined(_MSC_VER) -extern const char *int64_vc6_c_cvsid; -#endif -extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid; -const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.134 2004/08/16 22:44:27 ballen4705 Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; - -// This is a block containing all the "control variables". We declare -// this globally in this file, and externally in other files. -smartmonctrl *con=NULL; - -// to hold onto exit code for atexit routine -extern int exitstatus; - -// Track memory use -extern int64_t bytes; - -void printslogan(){ - pout("smartctl version %s [%s] Copyright (C) 2002-4 Bruce Allen\n", PACKAGE_VERSION, SMARTMONTOOLS_BUILD_HOST); - pout("Home page is " PACKAGE_HOMEPAGE "\n\n"); - return; -} - -void PrintOneCVS(const char *a_cvs_id){ - char out[CVSMAXLEN]; - printone(out,a_cvs_id); - pout("%s",out); - return; -} - -void printcopy(){ - char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; - - pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n"); - pout("is free software, and you are welcome to redistribute it\n"); - pout("under the terms of the GNU General Public License Version 2.\n"); - pout("See http://www.gnu.org for further details.\n\n"); - pout("CVS version IDs of files used to build this code are:\n"); - PrintOneCVS(atacmdnames_c_cvsid); - PrintOneCVS(atacmds_c_cvsid); - PrintOneCVS(ataprint_c_cvsid); -#if defined(_WIN32) && defined(_MSC_VER) - PrintOneCVS(int64_vc6_c_cvsid); -#endif - PrintOneCVS(knowndrives_c_cvsid); - PrintOneCVS(os_XXXX_c_cvsid); -#ifdef NEED_SOLARIS_ATA_CODE - PrintOneCVS(os_solaris_ata_s_cvsid); -#endif - PrintOneCVS(scsicmds_c_cvsid); - PrintOneCVS(scsiprint_c_cvsid); - PrintOneCVS(smartctl_c_cvsid); - PrintOneCVS(utility_c_cvsid); - pout("\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); - pout("smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); - pout("smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); - pout("smartctl compile dated " __DATE__ " at "__TIME__ "\n"); - pout("smartmontools configure arguments: %s\n", configargs); - return; -} - -void UsageSummary(){ - pout("\nUse smartctl -h to get a usage summary\n\n"); - return; -} - -/* void prints help information for command syntax */ -void Usage (void){ - printf("Usage: smartctl [options] device\n\n"); - printf("============================================ SHOW INFORMATION OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" -" -a, --all \n" -" Show all SMART information for device\n\n" - ); -#else - printf( -" -h Display this help and exit\n" -" -V Print license, copyright, and version information\n" -" -i Show identity information for device\n" -" -a Show all SMART information for device\n\n" - ); -#endif - printf("================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -q TYPE, --quietmode=TYPE (ATA)\n" -" Set smartctl quiet mode to one of: errorsonly, silent\n\n" -" -d TYPE, --device=TYPE\n" -" Specify device type to one of: ata, scsi, 3ware,N\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" - ); -#else - printf( -" -q TYPE Set smartctl quiet mode to one of: errorsonly, silent (ATA)\n" -" -d TYPE Specify device type to one of: ata, scsi, 3ware,N\n" -" -T TYPE Tolerance: normal, conservative,permissive,verypermissive (ATA\n" -" -b TYPE Set action on bad checksum to one of: warn, exit, ignore (ATA)\n" -" -r TYPE Report transactions (see man page)\n\n" - ); -#endif - printf("============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" - ); -#else - printf( -" -s VALUE Enable/disable SMART on device (on/off)\n" -" -o VALUE Enable/disable device automatic offline testing (on/off) (ATA)\n" -" -S VALUE Enable/disable device Attribute autosave (on/off) (ATA)\n\n" - ); -#endif - printf("======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -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" -" -l TYPE, --log=TYPE\n" -" Show device log. TYPE: error, selftest, selective, directory\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: none, samsung, samsung2\n\n" -" -P TYPE, --presets=TYPE (ATA)\n" -" Drive-specific presets: use, ignore, show, showall\n\n" - ); -#else - printf( -" -H Show device SMART health status\n" -" -c Show device SMART capabilities (ATA)\n" -" -A Show device SMART vendor-specific Attributes and values (ATA)\n" -" -l TYPE Show device log. TYPE: error,selftest,selective,directory\n" -" -v N,OPT Set display OPTion for vendor Attribute N (see man page) (ATA)\n" -" -F TYPE Use firmware bug workaround: none, samsung, samsung2 (ATA)\n" -" -P TYPE Drive-specific presets: use, ignore, show, showall (ATA)\n\n" - ); -#endif - printf("============================================ DEVICE SELF-TEST OPTIONS =====\n\n"); -#ifdef HAVE_GETOPT_LONG - printf( -" -t TEST, --test=TEST\n" -" Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,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" -); -#else - printf( -" -t TEST Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n" -" -C Do test in captive mode (along with -t)\n" -" -X Abort any non-captive test\n\n" - ); -#endif - print_smartctl_examples(); - return; -} - -/* Returns a pointer to a static string containing a formatted list of the valid - arguments to the option opt or NULL on failure. Note 'v' case different */ -const char *getvalidarglist(char opt) { - switch (opt) { - case 'q': - return "errorsonly, silent"; - case 'd': - return "ata, scsi, 3ware,N"; - case 'T': - return "normal, conservative, permissive, verypermissive"; - case 'b': - return "warn, exit, ignore"; - case 'r': - return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; - case 's': - case 'o': - case 'S': - return "on, off"; - case 'l': - return "error, selftest, selective, directory"; - case 'P': - return "use, ignore, show, showall"; - case 't': - return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,on, afterselect,off"; - case 'F': - return "none, samsung, samsung2"; - case 'v': - default: - return NULL; - } -} - -/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where - <LIST> is the list of valid arguments for option opt. */ -void printvalidarglistmessage(char opt) { - char *s; - - if (opt=='v') - s=create_vendor_attribute_arg_list(); - else - s=(char *)getvalidarglist(opt); - - if (!s) { - pout("Error whilst constructing argument list for option %c", opt); - return; - } - - if (opt=='v'){ - pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", s); - free(s); - } - else { - // getvalidarglist() might produce a multiline or single line string. We - // need to figure out which to get the formatting right. - char separator = strchr(s, '\n') ? '\n' : ' '; - pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, (char *)s, separator); - } - - return; -} - -/* Takes command options and sets features to be run */ -void ParseOpts (int argc, char** argv){ - int optchar; - int badarg; - int captive; - unsigned char *charp; - extern char *optarg; - extern int optopt, optind, opterr; - char extraerror[256]; - // Please update getvalidarglist() if you edit shortopts - const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iav:P:t:CXF:"; -#ifdef HAVE_GETOPT_LONG - char *arg; - // 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, 's' }, - { "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' }, - { "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' }, - { 0, 0, 0, 0 } - }; -#endif - - memset(extraerror, 0, sizeof(extraerror)); - memset(con,0,sizeof(*con)); - con->testcase=-1; - opterr=optopt=0; - badarg = captive = FALSE; - - // This miserable construction is needed to get emacs to do proper indenting. Sorry! - while (-1 != (optchar = -#ifdef HAVE_GETOPT_LONG - getopt_long(argc, argv, shortopts, longopts, NULL) -#else - getopt(argc, argv, shortopts) -#endif - )){ - switch (optchar){ - case 'V': - con->dont_print=FALSE; - printslogan(); - printcopy(); - exit(0); - break; - case 'q': - if (!strcmp(optarg,"errorsonly")) { - con->printing_switchable = TRUE; - con->dont_print = FALSE; - } else if (!strcmp(optarg,"silent")) { - con->printing_switchable = FALSE; - con->dont_print = TRUE; - } else { - badarg = TRUE; - } - break; - case 'd': - if (!strcmp(optarg,"ata")) { - con->controller_type = CONTROLLER_ATA; - con->controller_port = 0; - } else if (!strcmp(optarg,"scsi")) { - con->controller_type = CONTROLLER_SCSI; - con->controller_port = 0; - } else { - // look for RAID-type device - int i; - char *s; - - // make a copy of the string to mess with - if (!(s = strdup(optarg))) { - con->dont_print = FALSE; - pout("No memory for argument of -d. Exiting...\n"); - exit(FAILCMD); - } else if (strncmp(s,"3ware,",6)) { - badarg = TRUE; - } else if (split_report_arg2(s, &i)) { - sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n"); - badarg = TRUE; - } else if (i<0 || i>15) { - sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i); - badarg = TRUE; - } else { - // NOTE: controller_port == disk number + 1 - con->controller_type = CONTROLLER_3WARE; - con->controller_port = i+1; - } - free(s); - } - break; - case 'T': - if (!strcmp(optarg,"normal")) { - con->conservative = FALSE; - con->permissive = 0; - } else if (!strcmp(optarg,"conservative")) { - con->conservative = TRUE; - } else if (!strcmp(optarg,"permissive")) { - if (con->permissive<0xff) - con->permissive++; - } else if (!strcmp(optarg,"verypermissive")) { - con->permissive=0xff; - } else { - badarg = TRUE; - } - break; - case 'b': - if (!strcmp(optarg,"warn")) { - con->checksumfail = FALSE; - con->checksumignore = FALSE; - } else if (!strcmp(optarg,"exit")) { - con->checksumfail = TRUE; - con->checksumignore = FALSE; - } else if (!strcmp(optarg,"ignore")) { - con->checksumignore = TRUE; - con->checksumfail = FALSE; - } 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))) { - con->dont_print = FALSE; - pout("Can't allocate memory to copy argument to -r option" - " - exiting\n"); - EXIT(FAILCMD); - } - if (split_report_arg(s, &i)) { - badarg = TRUE; - } else if (!strcmp(s,"ioctl")) { - con->reportataioctl = con->reportscsiioctl = i; - } else if (!strcmp(s,"ataioctl")) { - con->reportataioctl = i; - } else if (!strcmp(s,"scsiioctl")) { - con->reportscsiioctl = i; - } else { - badarg = TRUE; - } - free(s); - } - break; - case 's': - if (!strcmp(optarg,"on")) { - con->smartenable = TRUE; - con->smartdisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartdisable = TRUE; - con->smartenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'o': - if (!strcmp(optarg,"on")) { - con->smartautoofflineenable = TRUE; - con->smartautoofflinedisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartautoofflinedisable = TRUE; - con->smartautoofflineenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'S': - if (!strcmp(optarg,"on")) { - con->smartautosaveenable = TRUE; - con->smartautosavedisable = FALSE; - } else if (!strcmp(optarg,"off")) { - con->smartautosavedisable = TRUE; - con->smartautosaveenable = FALSE; - } else { - badarg = TRUE; - } - break; - case 'H': - con->checksmart = TRUE; - break; - case 'F': - if (!strcmp(optarg,"none")) { - con->fixfirmwarebug = FIX_NONE; - } else if (!strcmp(optarg,"samsung")) { - con->fixfirmwarebug = FIX_SAMSUNG; - } else if (!strcmp(optarg,"samsung2")) { - con->fixfirmwarebug = FIX_SAMSUNG2; - } else { - badarg = TRUE; - } - break; - case 'c': - con->generalsmartvalues = TRUE; - break; - case 'A': - con->smartvendorattrib = TRUE; - break; - case 'l': - if (!strcmp(optarg,"error")) { - con->smarterrorlog = TRUE; - } else if (!strcmp(optarg,"selftest")) { - con->smartselftestlog = TRUE; - } else if (!strcmp(optarg, "selective")) { - con->selectivetestlog = TRUE; - } else if (!strcmp(optarg,"directory")) { - con->smartlogdirectory = TRUE; - } else { - badarg = TRUE; - } - break; - case 'i': - con->driveinfo = TRUE; - break; - case 'a': - con->driveinfo = TRUE; - con->checksmart = TRUE; - con->generalsmartvalues = TRUE; - con->smartvendorattrib = TRUE; - con->smarterrorlog = TRUE; - con->smartselftestlog = TRUE; - con->selectivetestlog = TRUE; - break; - case 'v': - // parse vendor-specific definitions of attributes - if (!strcmp(optarg,"help")) { - char *s; - con->dont_print=FALSE; - printslogan(); - if (!(s = create_vendor_attribute_arg_list())) { - pout("Insufficient memory to construct argument list\n"); - EXIT(FAILCMD); - } - pout("The valid arguments to -v are:\n\thelp\n%s\n", s); - free(s); - EXIT(0); - } - charp=con->attributedefs; - if (!charp){ - pout("Fatal internal error in ParseOpts()\n"); - EXIT(FAILCMD); - } - if (parse_attribute_def(optarg, &charp)) - badarg = TRUE; - break; - case 'P': - if (!strcmp(optarg, "use")) { - con->ignorepresets = FALSE; - } else if (!strcmp(optarg, "ignore")) { - con->ignorepresets = TRUE; - } else if (!strcmp(optarg, "show")) { - con->showpresets = TRUE; - } else if (!strcmp(optarg, "showall")) { - showallpresets(); - EXIT(0); - } else { - badarg = TRUE; - } - break; - case 't': - if (!strcmp(optarg,"offline")) { - con->smartexeoffimmediate = TRUE; - con->testcase = OFFLINE_FULL_SCAN; - } else if (!strcmp(optarg,"short")) { - con->smartshortselftest = TRUE; - con->testcase = SHORT_SELF_TEST; - } else if (!strcmp(optarg,"long")) { - con->smartextendselftest = TRUE; - con->testcase = EXTEND_SELF_TEST; - } else if (!strcmp(optarg,"conveyance")) { - con->smartconveyanceselftest = TRUE; - con->testcase = CONVEYANCE_SELF_TEST; - } else if (!strcmp(optarg,"afterselect,on")) { - // scan remainder of disk after doing selected segments - con->scanafterselect=2; - } else if (!strcmp(optarg,"afterselect,off")) { - // don't scan remainder of disk after doing selected segments - con->scanafterselect=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') { - sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n"); - badarg = TRUE; - } else if (i<0 || i>65535) { - sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i); - badarg = TRUE; - } else { - con->pendingtime=i+1; - } - } else if (!strncmp(optarg,"select",strlen("select"))) { - // parse range of LBAs to test - uint64_t start, stop; - - if (split_selective_arg(optarg, &start, &stop)) { - sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n"); - badarg = TRUE; - } else { - if (con->smartselectivenumspans >= 5 || start > stop) { - if (start > stop) { - sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n", - start, stop, optarg); - } else { - sprintf(extraerror,"ERROR: No more than five selective self-test spans may be" - " defined\n"); - } - badarg = TRUE; - } - con->smartselectivespan[con->smartselectivenumspans][0] = start; - con->smartselectivespan[con->smartselectivenumspans][1] = stop; - con->smartselectivenumspans++; - con->testcase = SELECTIVE_SELF_TEST; - } - } else { - badarg = TRUE; - } - break; - case 'C': - captive = TRUE; - break; - case 'X': - con->smartselftestabort = TRUE; - con->testcase = ABORT_SELF_TEST; - break; - case 'h': - con->dont_print=FALSE; - printslogan(); - Usage(); - EXIT(0); - break; - case '?': - default: - con->dont_print=FALSE; - printslogan(); -#ifdef HAVE_GETOPT_LONG - // 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)) { - 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); - } -#endif - if (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. - pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg); - printvalidarglistmessage(optchar); - if (extraerror[0]) - pout("=======> %s", extraerror); - UsageSummary(); - EXIT(FAILCMD); - } - } - // 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 (con->printing_switchable) - con->dont_print=TRUE; - - // error message if user has asked for more than one test - if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+ - con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){ - con->dont_print=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 ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){ - con->dont_print=FALSE; - printslogan(); - if (con->pendingtime) - 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 && con->smartshortselftest) { - con->smartshortselftest = FALSE; - con->smartshortcapselftest = TRUE; - con->testcase = SHORT_CAPTIVE_SELF_TEST; - } else if (captive && con->smartextendselftest) { - con->smartextendselftest = FALSE; - con->smartextendcapselftest = TRUE; - con->testcase = EXTEND_CAPTIVE_SELF_TEST; - } - else if (captive && con->smartconveyanceselftest) { - con->smartconveyanceselftest = FALSE; - con->smartconveyancecapselftest = TRUE; - con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST; - } - else if (captive && con->smartselectiveselftest) { - con->smartselectiveselftest = FALSE; - con->smartselectivecapselftest = TRUE; - con->testcase = SELECTIVE_CAPTIVE_SELF_TEST; - } - - // 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); - } -} - -// Printing function (controlled by global con->dont_print) -// [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(char *fmt, ...){ - va_list ap; - - // initialize variable argument list - va_start(ap,fmt); - if (con->dont_print){ - va_end(ap); - return; - } - - // print out - vprintf(fmt,ap); - va_end(ap); - fflush(stdout); - return; -} - -// This function is used by utility.c to report LOG_CRIT errors. -// The smartctl version prints to stdout instead of syslog(). -void PrintOut(int priority, char *fmt, ...) { - va_list ap; - - // avoid warning message about unused variable from gcc -W: just - // change value of local copy. - priority=0; - - va_start(ap,fmt); - vprintf(fmt,ap); - va_end(ap); - return; -} - - -/* Main Program */ -int main (int argc, char **argv){ - int fd,retval=0; - char *device; - smartmonctrl control; - char *mode=NULL; - - // define control block for external functions - con=&control; - - // Part input arguments - ParseOpts(argc,argv); - - device = argv[argc-1]; - - // If use has specified 3ware controller, determine which interface - if (con->controller_type == CONTROLLER_3WARE) { - con->controller_type=guess_device_type(device); - if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR) - con->controller_type = CONTROLLER_3WARE_678K; - } - - if (con->controller_type == CONTROLLER_UNKNOWN) - con->controller_type=guess_device_type(device); - - if (con->controller_type == CONTROLLER_UNKNOWN) { - pout("Smartctl: please specify device type with the -d option.\n"); - UsageSummary(); - return FAILCMD; - } - - // set up mode for open() call. SCSI case is: - switch (con->controller_type) { - case CONTROLLER_SCSI: - mode="SCSI"; - break; - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - mode="ATA"; - break; - case CONTROLLER_3WARE_9000_CHAR: - mode="ATA_3WARE_9000"; - break; - case CONTROLLER_3WARE_678K_CHAR: - mode="ATA_3WARE_678K"; - break; - } - - // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the - // scsi generic device can be used (needs write permission for MODE - // SELECT command) plus O_NONBLOCK to stop open hanging if media not - // present (e.g. with st). Opening is retried O_RDONLY if read-only - // media prevents opening O_RDWR (it cannot happen for scsi generic - // devices, but it can for the others). - fd = deviceopen(device, mode); - if (fd<0) { - char errmsg[256]; - snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]); - errmsg[255]='\0'; - syserror(errmsg); - return FAILDEV; - } - - // now call appropriate ATA or SCSI routine - switch (con->controller_type) { - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - case CONTROLLER_3WARE_9000_CHAR: - case CONTROLLER_3WARE_678K_CHAR: - retval = ataPrintMain(fd); - break; - case CONTROLLER_SCSI: - retval = scsiPrintMain(fd); - break; - default: - pout("Smartctl: specify if this is an ATA or SCSI device with the -d option.\n"); - UsageSummary(); - return FAILCMD; - } - - return retval; -} diff --git a/sm5/smartctl.h b/sm5/smartctl.h deleted file mode 100644 index 5519a791d501dd01abd3ab22e8f0c5602e091235..0000000000000000000000000000000000000000 --- a/sm5/smartctl.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * smartctl.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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,v 1.21 2004/01/29 03:21:06 ballen4705 Exp $\n" - -/* Boolean Values */ -#define TRUE 0x01 -#define FALSE 0x00 - -// 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) - -// 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. -#define OPTIONAL_CMD 1 -#define MANDATORY_CMD 2 - -void print_smartctl_examples(); - -#endif diff --git a/sm5/smartd.8.in b/sm5/smartd.8.in deleted file mode 100644 index 40a517e82c0b4bce2ec0bf2ede081de3ac203d90..0000000000000000000000000000000000000000 --- a/sm5/smartd.8.in +++ /dev/null @@ -1,1771 +0,0 @@ -.ig -Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - -$Id: smartd.8.in,v 1.78 2004/08/06 19:48:42 chrfranke Exp $ - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free 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., -675 Mass Ave, Cambridge, MA 02139, 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/ -.. -.TH SMARTD 8 CURRENT_CVS_DATE CURRENT_CVS_VERSION CURRENT_CVS_DATE -.SH NAME -\fBsmartd\fP \- SMART Disk Monitoring Daemon - -.SH SYNOPSIS -.B smartd [options] - -.SH FULL PATH -.B /usr/sbin/smartd - -.SH PACKAGE VERSION -CURRENT_CVS_VERSION released CURRENT_CVS_DATE at CURRENT_CVS_TIME - -.SH DESCRIPTION -\fBsmartd\fP is a daemon that monitors the Self-Monitoring, Analysis -and Reporting Technology (SMART) system built into many ATA-3 and -later ATA, IDE and SCSI-3 hard 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 ATA/ATAPI-5 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 \fB/var/log/messages\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/etc/smartd.conf\fP (Windows: \fB./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 -(Windows: See NOTES below.) - -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 \fBQUIT\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 -(Cygwin: 2x CONTROL\-C, Windows: CONTROL\-Break). - -On startup, in the absence of the configuration file -\fB/etc/smartd.conf\fP, the \fBsmartd\fP daemon first scans for all -devices that support SMART. The scanning is done as follows: -.IP \fBLINUX:\fP 9 -Examine all entries \fB"/dev/hd[a-t]"\fP for IDE/ATA -devices, and \fB"/dev/sd[a-z]"\fP for SCSI devices. -.IP \fBFREEBSD:\fP 9 -Examine all entries \fB"/dev/ad[0-9]+"\fP for IDE/ATA -devices and \fB"/dev/da[0-9]+"\fP for SCSI devices. -.IP \fBNETBSD:\fP 9 -Authoritative list of disk devices is obtained from sysctl -\'hw.disknames\'. -.IP \fBSOLARIS:\fP 9 -Examine all entries \fB"/dev/rdsk/c?t?d?s?"\fP for IDE/ATA and SCSI disk -devices, and entries \fB"/dev/rmt/*"\fP for SCSI tape devices. -.IP \fBWINDOWS:\fP 9 -Examine all entries \fB"/dev/hd[a-j]"\fP ("\\\\.\\PhysicalDisk[0-9]") -for IDE/ATA devices on WinNT4/2000/XP, \fB"/dev/hd[a-d]"\fP -(bitmask from "\\\\.\\SMARTVSD") for IDE/ATA devices on Win95/98/98SE/ME, -and \fB"/dev/scsi[0-3][0-7]"\fP (ASPI adapter 0-3, ID 0-7) for SCSI -devices on all versions of Windows. -.IP \fBCYGWIN\fP: 9 -See "WINDOWS" above. -.PP -\fBsmartd\fP then monitors -for \fIall\fP possible SMART errors (corresponding to the \fB\'\-a\'\fP -Directive in the configuration file; see \fBCONFIGURATION FILE\fP -below). - -.SH -OPTIONS -Long options are not supported on all systems. Use \fB\'smartd -\-h\'\fP to see the available options. -.TP -.B \-c FILE, \-\-configfile=FILE - -Read \fBsmartd\fP configuration Directives from FILE, instead of from -the default location \fB/etc/smartd.conf\fP (Windows: \fB./smartd.conf\fP). -If FILE does \fBnot\fP exist, then \fBsmartd\fP will print an error -message and exit with nonzero status. Thus, \'\-c /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. - -.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 \fBQUIT\fP signal (normally generated from a -terminal with CONTROL\-C) makes \fBsmartd\fP reload its configuration -file. Please use CONTROL-\e to exit -(Cygwin: 2x CONTROL\-C, 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. -.TP -.B \-D, \-\-showdirectives -Prints a list (to STDOUT) of all the possible Directives which may -appear in the configuration file /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 -(Windows: See NOTES below.) - -.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 \fB/var/log/messages\fP 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. - -Cygwin: The current release of Cygwin writes \fBsyslog\fP(3) -messages to Windows event log or to file \fBC:/CYGWIN_SYSLOG.TXT\fP -if the event log is not available. -The FACILITY parameter is always ignored by Cygwin. - -Windows: Some \fBsyslog\fP(3) 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 -(Win9x/ME or 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. - -When using the event log, the enclosed utility \fBsyslogevt.exe\fP -should be registered as an event message file to avoid error -messages from the event viewer. Use \'\fBsyslogevt -r smartd\fP\' -to register, \'\fBsyslogevt -u smartd\fP\' to unregister and -\'\fBsyslogevt\fP\' for more help. - -.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 /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/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. -.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 \-\-service -Windows only: Enables \fBsmartd\fP to run as a Windows service. -It must be specified in the service command line as the first argument. -See NOTES below for details. - -.TP -.B \-V, \-\-version, \-\-license, \-\-copyright -Prints license, copyright, and CVS version information onto -STDOUT and then exits. Please include this information if you are -reporting bugs, or have specific questions about the behavior of -\fBsmartd\fP. - -.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 (by default -.B /var/log/messages.) - -.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/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 /etc/rc.d/init.d/smartd start -.fi -and stop it by using the command: -.nf -.B /etc/rc.d/init.d/smartd stop - -.fi -If you want \fBsmartd\fP to start running whenever your machine is -booted, this can be enabled by using the command: -.nf -.B /sbin/chkconfig --add smartd -.fi -and disabled using the command: -.nf -.B /sbin/chkconfig --del smartd -.fi - -.\" DO NOT MODIFY THIS OR THE FOLLOWING TWO LINES. THIS MATERIAL -.\" IS AUTOMATICALLY INCLUDED IN THE FILE smartd.conf.5 -.\" STARTINCLUDE - -.SH CONFIGURATION FILE /etc/smartd.conf -In the absence of a configuration file, -\fBsmartd\fP -will try to open the 20 ATA devices -.B /dev/hd[a-t] -and the 26 SCSI devices -.B /dev/sd[a-z] -under Linux. Under FreeBSD, -\fBsmartd\fP -will try to open all existing ATA devices (with entries in /dev) -.B /dev/ad[0-9]+ -and all existing SCSI devices -.B /dev/da[0-9]+. -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 -block-major devices that can\'t be found, and SCSI 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 /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/share/doc/smartmontools-5.1/\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 -.B # file /etc/smartd.conf for monitoring three ATA -.B # disks, three SCSI disks, and six ATA disks -.B # behind two 3ware controllers. -.B # -.nf -.B # First ATA disk on each of two interfaces. On -.B # the second disk, do a long self-test every -.B # Sunday at 3am. -.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. Do a scheduled -.B # long self test at 5am Monday/Thursday -.B \ \ /dev/weird -d scsi -s L/../../(1|4)/05 -.B # -.nf -.B # Four ATA disks on a 3ware 6/7/8000 controller. -.B # Do short self-tests daily at midnight, 1, 2, and 3 am -.B # (Note that the syntax /dev/twe0 is also allowed.) -.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 # Do long self-tests Sundays at midnight and 2 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 # 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 the first 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. - -.sp 2 -The following are the Directives that may appear following the device -name or -.B DEVICESCAN -on any line of the -.B /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? -or /dev/twa?) 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). - -.TP -.B \-d TYPE -Specifies the type of the device. This Directive may be used multiple times -for one device, but the arguments \fIata\fP, \fIscsi\fP, and \fI3ware,N\fP are -mutually-exclusive. If more than one is given then -\fBsmartd\fP -will use the last one which appears. - -If none of these three arguments is given, then \fBsmartd\fP will -first attempt to guess the device type by looking at whether the sixth -character in the device name is an \'s\' or an \'h\'. This will work for -device names like /dev/hda or /dev/sdb, and corresponds to choosing -\fIata\fP or \fIscsi\fP respectively. If -\fBsmartd\fP -can\'t guess from this sixth character, then it will simply try to -access the device using first ATA and then SCSI ioctl()s. - -The valid arguments to this Directive are: - -.I ata -\- the device type is ATA. This prevents -\fBsmartd\fP -from issuing SCSI commands to an ATA device. - -.I scsi -\- the device type is SCSI. This prevents -\fBsmartd\fP -from issuing ATA commands to a SCSI device. - -.I 3ware,N -\- 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 15 -inclusive) denotes which disk on the controller is monitored. In log -files and email messages this disk will be identified as 3ware_disk_XX -with XX in the range from 00 to 15 inclusive. - -This Directive may at first appear confusing, because the 3ware -controller is a SCSI device (such as /dev/sda) and should be listed as -such in the the configuration file. -However when the \'\-d 3ware,N\' -Directive is used, then the corresponding disk is addressed using -native ATA commands which are \'passed through\' the SCSI driver. All -ATA Directives listed in this man page may be used. Note that while -you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? 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 man page for further details. - -ATA disks behind 3ware controllers may alternatively be accessed via a -character device interface /dev/twe0-15 (3ware 6000/7000/8000 -controllers) and /dev/twa0-15 (3ware 9000 series controllers). Note -that the 9000 series controllers may \fBonly\fP be accessed using the -character device interface /dev/twa0-15 and not the SCSI device -interface /dev/sd?. Please see the \fBsmartctl\fP man page for -further details. - -Note that 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, if the SCSI interface is used, and produce these types of -harmless syslog error messages instead: \fB\'3w-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. See -\fBhttp://smartmontools.sourceforge.net/\fP for instructions. -Alternatively use the character device interfaces /dev/twe0-15 (3ware -6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series -controllers). - - -.B 3ware controllers are currently ONLY supported under Linux. - -.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 -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. - - -.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. This may also be -needed for some Maxtor disks which fail to comply with the ATA -Specifications and don't properly indicate support for error\- or -self\-test logging. - -[Please see the \fBsmartctl \-T\fP command-line option.] -.TP -.B \-o VALUE -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 -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_CRITICAL\' -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 the two SMART logs. The -valid arguments to this Directive are: - -.I error -\- report if the number of ATA errors reported in the ATA Error Log -has increased since the last check. - -.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.] -.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. -.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 - -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, and so the -self tests may not take place as you wish. - -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. - -Each time a test is run, \fBsmartd\fP will log an entry to SYSLOG. -You can use these 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. - -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. - -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. - -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. - -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. - -The following extension is available on Windows: -By specifying \'\fBmsgbox\fP\' as a mail address, a warning -"email" is displayed as a message box on the screen. -Using both \'\fBmsgbox\fP\' and regular mail addresses is possible, -if \'\fBmsgbox\fP\' is the first word in the comma separated list. -With \'\fBsysmsgbox\fP\', a system modal (always on top) message box -is used. If running as a service, a service notification message box -(always shown on current visible desktop) is used. - -.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 conflicting \-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: - -.I once -\- send only one warning email for each type of disk problem detected. This -is the default. - -.I daily -\- send additional warning reminder emails, once per day, for each type -of disk problem detected. - -.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. - -.I test -\- send a single test email -immediately upon -\fBsmartd\fP -startup. This allows one to verify that email is delivered correctly. - -.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. - -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. Some sample -scripts are included in -/usr/share/doc/smartmontools-5.1/examplescripts/. - -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 (possible values: ata, scsi, 3ware,N). Here -N=0,...,15 denotes the ATA disk behind a 3ware RAID controller. -.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]\'. In this case 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_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 -\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. -.IP \fBSMARTD_MESSAGE\fP 4 -is set to the 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. -.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. -.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 - -Note that on Windows, the syntax of the \'\fBBlat\fP\' mailer is -used: -.nf -- -q -subject "$SMARTD_SUBJECT" -to "$SMARTD_ADDRESS" -.fi - -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. Some sample scripts are also included in -/usr/share/doc/smartmontools-5.1/examplescripts/. - -.TP -.B \-f -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 -Report anytime that a Prefail Attribute has changed -its value since the last check, 30 minutes ago. [Please see the -.B smartctl \-A -command-line option.] -.TP -.B \-u -Report anytime that a Usage Attribute has changed its value -since the last check, 30 minutes ago. [Please see the -.B smartctl \-A -command-line option.] -.TP -.B \-t -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 -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 -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 -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). - -.TP -.B \-R ID -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. - -.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). - -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). - - -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 \-F TYPE -[ATA only] Modifies the behavior of \fBsmartd\fP to compensate for -some known and understood device firmware bug. The arguments to this -Directive are exclusive, so that only the final Directive given is -used. The valid values 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 device -database. - -.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 more recent Samsung disks (firmware revisions ending in "\-23") the -number of ATA errors reported is byte swapped. Enabling this option -tells \fBsmartd\fP to evaluate this quantity in byte-reversed order. - -Note that an explicit \'\-F\' Directive will over-ride any preset -values for \'\-F\' (see the \'\-P\' option below). - - -[Please see the \fBsmartctl \-F\fP command-line option.] - -.TP -.B \-v N,OPTION -Modifies the labeling for Attribute N, for disks which use -non-standard Attribute definitions. This is useful in connection with -the Attribute tracking/reporting Directives. - -This Directive may appear multiple times. Valid arguments to this -Directive are: - -.I 9,minutes -\- Raw Attribute number 9 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 9,seconds -\- Raw Attribute number 9 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 9,halfminutes -\- Raw Attribute number 9 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 9,temp -\- Raw Attribute number 9 is the disk temperature in Celsius. - -.I 192,emergencyretractcyclect -\- Raw Attribute number 192 is the Emergency Retract Cycle Count. - -.I 193,loadunload -\- Raw Attribute number 193 contains two 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 194,10xCelsius -\- Raw Attribute number 194 is ten times the disk temperature in -Celsius. This is used by some Samsung disks (example: model SV1204H -with RK100-13 firmware). - -.I 194,unknown -\- Raw Attribute number 194 is NOT the disk temperature, and its -interpretation is unknown. This is primarily useful for the -P -(presets) Directive. - -.I 198,offlinescanuncsectorct -\- Raw Attribute number 198 is the Offline Scan UNC Sector Count. - -.I 200,writeerrorcount -\- Raw Attribute number 200 is the Write Error Count. - -.I 201,detectedtacount -\- Raw Attribute number 201 is the Detected TA Count. - -.I 220,temp -\- Raw Attribute number 220 is the disk temperature in Celsius. - -Note: a table of hard drive models, listing which Attribute -corresponds to temperature, can be found at: -http://coredump.free.fr/linux/hddtemp.db - -.I N,raw8 -\- Print the Raw value of Attribute N as six 8-bit unsigned base-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw8\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw8\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw16 -\- Print the Raw value of Attribute N as three 16-bit unsigned base-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw16\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw16\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw48 -\- Print the Raw value of Attribute N as a 48-bit unsigned base-10 -integer. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw48\' prints Raw values for ALL Attributes in -this form. The form (for example) \'123,raw48\' only prints the Raw -value for Attribute 123 in this form. - -.TP -.B \-P TYPE -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\ selftest\' -to report increases in the number of Self-Test Log errors, -.B \'\-l\ error\' -to report increases in the number of ATA errors, -.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 the first 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. - -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). - -.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/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/share/doc/smartmontools-5.1/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. - -.\" ENDINCLUDE -.\" DO NOT MODIFY THIS OR PREVIOUS/NEXT LINES. THIS DEFINES THE -.\" END OF THE INCLUDE SECTION FOR smartd.conf.5 - -.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. - -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. - -On Cygwin and 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 - -On WinNT4/2000/XP, \fBsmartd\fP can also be run as a Windows service: - -\'\fBsmartd install [options]\fP\' installs a service -named "smartd" (display name "SmartD Service") using the command line -\'/installpath/smartd.exe --service [options]\'. - -\'\fBsmartd remove\fP\' can later be used to remove the service entry -from 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). - -.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 /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 /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 AUTHOR -\fBBruce Allen\fP smartmontools-support@lists.sourceforge.net -.fi -University of Wisconsin \- Milwaukee Physics Department - -.PP -.SH CONTRIBUTORS -The following have made large contributions to smartmontools: -.nf -\fBCasper Dik\fP (Solaris SCSI interface) -\fBChristian Franke\fP (Windows interface) -\fBDouglas Gilbert\fP (SCSI subsystem) -\fBGuido Guenther\fP (Autoconf/Automake packaging) -\fBGeoffrey Keating\fP (Darwin ATA interface) -\fBEduard Martinescu\fP (FreeBSD interface) -\fBFr\*'ed\*'eric L. W. Meunier\fP (Web site and Mailing list) -\fBKeiji Sawada\fP (Solaris ATA interface) -\fBSergey Svishchev\fP (NetBSD interface) -\fBPhil Williams\fP (User interface and drive database) -.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: -.nf -.B -http://smartmontools.sourceforge.net/ - -.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 http://www.linuxjournal.com/article.php?sid=6983 -online. - -If you would like to understand better how SMART works, and what -it does, a good place to start is Section 8.41 of the \'AT -Attachment with Packet Interface-5\' (ATA/ATAPI-5) specification. This -documents the SMART functionality which the smartmontools -utilities provide access to. You can find Revision 1 of this document -at \fBhttp://www.t13.org/project/d1321r1c.pdf\fP . - -.fi -Future versions of the specifications (ATA/ATAPI-6 and ATA/ATAPI-7), -and later revisions (2, 3) of the ATA/ATAPI-5 specification are -available from \fBhttp://www.t13.org/#FTP_site\fP . - -.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 documents may be found in the References section of the -smartmontools home page at \fBhttp://smartmontools.sourceforge.net/\fP . - -.SH -CVS ID OF THIS PAGE: -$Id: smartd.8.in,v 1.78 2004/08/06 19:48:42 chrfranke Exp $ diff --git a/sm5/smartd.c b/sm5/smartd.c deleted file mode 100644 index 1953213500f87f619f455d630b4a7de1e8433537..0000000000000000000000000000000000000000 --- a/sm5/smartd.c +++ /dev/null @@ -1,3940 +0,0 @@ -/* - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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/ - * - */ - -// unconditionally included files -#define _GNU_SOURCE -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> // umask -#ifndef _WIN32 -#include <sys/wait.h> -#include <unistd.h> -#endif -#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> - -#if SCSITIMEOUT -#include <setjmp.h> -#endif - -// see which system files to conditionally include -#include "config.h" - -// conditionally included files -#ifdef HAVE_GETOPT_LONG -#include <getopt.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 - -// locally included files -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "scsicmds.h" -#include "smartd.h" -#include "utility.h" - -#ifdef _WIN32 -#include "hostname_win32.h" // gethost/domainname() -#define HAVE_GETHOSTNAME 1 -#define HAVE_GETDOMAINNAME 1 -// 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 -#undef EXIT // see utility.h -#define EXIT(x) { exitstatus = daemon_winsvc_exitcode = (x); exit((x)); } -// SIGQUIT does not exits, CONTROL-Break signals SIGBREAK. -#define SIGQUIT SIGBREAK -#define SIGQUIT_KEYNAME "CONTROL-Break" -#else // _WIN32 -#ifdef __CYGWIN__ -// 2x CONTROL-C simulates missing SIGQUIT via keyboard -#define SIGQUIT_KEYNAME "2x CONTROL-C" -#else // __CYGWIN__ -#define SIGQUIT_KEYNAME "CONTROL-\\" -#endif // __CYGWIN__ -#endif // _WIN32 - -#if defined (__SVR4) && defined (__sun) -int getdomainname(char *, int); /* no declaration in header files! */ -#endif - -#define ARGUSED(x) ((void)(x)) - -// These are CVS identification information for *.c and *.h files -extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, - *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; - -static const char *filenameandversion="$Id: smartd.c,v 1.333 2004/08/16 22:44:27 ballen4705 Exp $"; -#ifdef NEED_SOLARIS_ATA_CODE -extern const char *os_solaris_ata_s_cvsid; -#endif -#ifdef _WIN32 -extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid; -#ifdef _MSC_VER -extern const char *int64_vc6_c_cvsid; -#endif -#endif -const char *smartd_c_cvsid="$Id: smartd.c,v 1.333 2004/08/16 22:44:27 ballen4705 Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID -#ifdef DAEMON_WIN32_H_CVSID -DAEMON_WIN32_H_CVSID -#endif -EXTERN_H_CVSID INT64_H_CVSID -#ifdef HOSTNAME_WIN32_H_CVSID -HOSTNAME_WIN32_H_CVSID -#endif -KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID -#ifdef SYSLOG_H_CVSID -SYSLOG_H_CVSID -#endif -UTILITY_H_CVSID; - -extern const char *reportbug; - -// GNU copyleft statement. Needed for GPL purposes. -const char *copyleftstring="smartd comes with ABSOLUTELY NO WARRANTY. This is\n" - "free software, and you are welcome to redistribute it\n" - "under the terms of the GNU General Public License\n" - "Version 2. See http://www.gnu.org for further details.\n\n"; - -extern unsigned char debugmode; - -// command-line: how long to sleep between checks -static int checktime=CHECKTIME; - -// command-line: name of PID file (NULL for no pid file) -static char* pid_file=NULL; - -// configuration file name -#ifndef _WIN32 -static char* configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ; -#else -static char* configfile = "./" CONFIGFILENAME ; -#endif -// configuration file "name" if read from stdin -static /*const*/ char * const configfile_stdin = "<stdin>"; -// allocated memory for alternate configuration file name -static char* configfile_alt = NULL; - -// 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; - -// used for control of printing, passing arguments to atacmds.c -smartmonctrl *con=NULL; - -// pointers to (real or simulated) entries in configuration file, and -// maximum space currently allocated for these entries. -cfgfile **cfgentries=NULL; -int cfgentries_max=0; - -// pointers to ATA and SCSI devices being monitored, maximum and -// actual numbers -cfgfile **atadevlist=NULL, **scsidevlist=NULL; -int atadevlist_max=0, scsidevlist_max=0; -int numdevata=0, numdevscsi=0; - -// track memory usage -extern int64_t bytes; - -// exit status -extern int exitstatus; - -// set to one if we catch a USR1 (check devices now) -volatile int caughtsigUSR1=0; - -#ifdef _WIN32 -// set to one if we catch a USR2 (toggle debug mode) -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). -volatile int caughtsigHUP=0; - -// set to signal value if we catch INT, QUIT, or TERM -volatile int caughtsigEXIT=0; - -#if SCSITIMEOUT -// stack environment if we time out during SCSI access (USB devices) -jmp_buf registerscsienv; -#endif - -// tranlate cfg->pending into the correct Attribute numbers -void TranslatePending(unsigned short pending, unsigned char *current, unsigned char *offline) { - - unsigned char curr = CURR_PEND(pending); - unsigned char off = OFF_PEND(pending); - - // look for special value of CUR_UNC_DEFAULT that means DONT - // monitor. 0 means DO test. - if (curr==CUR_UNC_DEFAULT) - curr=0; - else if (curr==0) - curr=CUR_UNC_DEFAULT; - - // look for special value of OFF_UNC_DEFAULT that means DONT - // monitor. 0 means DO TEST. - if (off==OFF_UNC_DEFAULT) - off=0; - else if (off==0) - off=OFF_UNC_DEFAULT; - - *current=curr; - *offline=off; - - return; -} - - -// free all memory associated with selftest part of configfile entry. Return NULL -testinfo* FreeTestData(testinfo *data){ - - // make sure we have something to do. - if (!data) - return NULL; - - // free space for text pattern - data->regex=FreeNonZero(data->regex, -1, __LINE__, filenameandversion); - - // free compiled expression - regfree(&(data->cregex)); - - // make sure that no sign of the compiled expression is left behind - // (just in case, to help detect bugs if we ever try and refer to - // that again). - memset(&(data->cregex), '0', sizeof(regex_t)); - - // free remaining memory space - data=FreeNonZero(data, sizeof(testinfo), __LINE__, filenameandversion); - - return NULL; -} - -cfgfile **AllocateMoreSpace(cfgfile **oldarray, int *oldsize, char *listname){ - // for now keep BLOCKSIZE small to help detect coding problems. - // Perhaps increase in the future. - const int BLOCKSIZE=8; - int i; - int old = *oldsize; - int new = old + BLOCKSIZE; - cfgfile **newptr=realloc(oldarray, new*sizeof(cfgfile *)); - - // did we get more space? - if (newptr) { - - // clear remaining entries ala calloc() - for (i=old; i<new; i++) - newptr[i]=NULL; - - bytes += BLOCKSIZE*sizeof(cfgfile *); - - *oldsize=new; - -#if 0 - PrintOut(LOG_INFO, "allocating %d slots for %s\n", BLOCKSIZE, listname); -#endif - - return newptr; - } - - PrintOut(LOG_CRIT, "out of memory for allocating %s list\n", listname); - EXIT(EXIT_NOMEM); -} - -void PrintOneCVS(const char *a_cvs_id){ - char out[CVSMAXLEN]; - printone(out,a_cvs_id); - PrintOut(LOG_INFO,"%s",out); - return; -} - -// prints CVS identity information for the executable -void PrintCVS(void){ - char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; - - PrintOut(LOG_INFO,(char *)copyleftstring); - PrintOut(LOG_INFO,"CVS version IDs of files used to build this code are:\n"); - PrintOneCVS(atacmdnames_c_cvsid); - PrintOneCVS(atacmds_c_cvsid); - PrintOneCVS(ataprint_c_cvsid); -#ifdef _WIN32 - PrintOneCVS(daemon_win32_c_cvsid); -#endif -#if defined(_WIN32) && defined(_MSC_VER) - PrintOneCVS(int64_vc6_c_cvsid); -#endif -#ifdef _WIN32 - PrintOneCVS(hostname_win32_c_cvsid); -#endif - PrintOneCVS(knowndrives_c_cvsid); - PrintOneCVS(os_XXXX_c_cvsid); -#ifdef NEED_SOLARIS_ATA_CODE - PrintOneCVS( os_solaris_ata_s_cvsid); -#endif - PrintOneCVS(scsicmds_c_cvsid); - PrintOneCVS(smartd_c_cvsid); -#ifdef _WIN32 - PrintOneCVS(syslog_win32_c_cvsid); -#endif - PrintOneCVS(utility_c_cvsid); - PrintOut(LOG_INFO, "\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); - PrintOut(LOG_INFO, "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); - PrintOut(LOG_INFO, "smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); - PrintOut(LOG_INFO, "smartd compile dated " __DATE__ " at "__TIME__ "\n"); - PrintOut(LOG_INFO, "smartmontools configure arguments: %s\n", configargs); - return; -} - -// Removes config file entry, freeing all memory -void RmConfigEntry(cfgfile **anentry, int whatline){ - - cfgfile *cfg; - - // pointer should never be null! - if (!anentry){ - PrintOut(LOG_CRIT,"Internal error in RmConfigEntry() at line %d of file %s\n%s", - whatline, filenameandversion, reportbug); - EXIT(EXIT_BADCODE); - } - - // only remove entries that exist! - if (!(cfg=*anentry)) - return; - - // entry exists -- free all of its memory - cfg->name = FreeNonZero(cfg->name, -1,__LINE__,filenameandversion); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); - if (cfg->mailwarn){ - cfg->mailwarn->address = FreeNonZero(cfg->mailwarn->address, -1,__LINE__,filenameandversion); - cfg->mailwarn->emailcmdline = FreeNonZero(cfg->mailwarn->emailcmdline, -1,__LINE__,filenameandversion); - cfg->mailwarn = FreeNonZero(cfg->mailwarn, sizeof(maildata),__LINE__,filenameandversion); - } - cfg->testdata = FreeTestData(cfg->testdata); - *anentry = FreeNonZero(cfg, sizeof(cfgfile),__LINE__,filenameandversion); - - return; -} - -// deallocates all memory associated with cfgentries list -void RmAllConfigEntries(){ - int i; - - for (i=0; i<cfgentries_max; i++) - RmConfigEntry(cfgentries+i, __LINE__); - - cfgentries=FreeNonZero(cfgentries, sizeof(cfgfile *)*cfgentries_max, __LINE__, filenameandversion); - cfgentries_max=0; - - return; -} - -// deallocates all memory associated with ATA/SCSI device lists -void RmAllDevEntries(){ - int i; - - for (i=0; i<atadevlist_max; i++) - RmConfigEntry(atadevlist+i, __LINE__); - - atadevlist=FreeNonZero(atadevlist, sizeof(cfgfile *)*atadevlist_max, __LINE__, filenameandversion); - atadevlist_max=0; - - for (i=0; i<scsidevlist_max; i++) - RmConfigEntry(scsidevlist+i, __LINE__); - - scsidevlist=FreeNonZero(scsidevlist, sizeof(cfgfile *)*scsidevlist_max, __LINE__, filenameandversion); - scsidevlist_max=0; - - return; -} - -// remove the PID file -void RemovePidFile(){ - if (pid_file) { - if ( -1==unlink(pid_file) ) - PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n", - pid_file, strerror(errno)); - pid_file=FreeNonZero(pid_file, -1,__LINE__,filenameandversion); - } - return; -} - - -// Note if we catch a SIGUSR1 -void USR1handler(int sig){ - if (SIGUSR1==sig) - caughtsigUSR1=1; - return; -} - -#ifdef _WIN32 -// Note if we catch a SIGUSR2 -void USR2handler(int sig){ - if (SIGUSR2==sig) - caughtsigUSR2=1; - return; -} -#endif - -// Note if we catch a HUP (or INT in debug mode) -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) -void sighandler(int sig){ - if (!caughtsigEXIT) - caughtsigEXIT=sig; - return; -} - - -// signal handler that prints Goodbye message and removes pidfile -void Goodbye(void){ - - // clean up memory -- useful for debugging - RmAllConfigEntries(); - RmAllDevEntries(); - - // delete PID file, if one was created - RemovePidFile(); - - // remove alternate configfile name - configfile_alt=FreeNonZero(configfile_alt, -1,__LINE__,filenameandversion); - - // useful for debugging -- have we managed memory correctly? - if (debugmode || (bytes && exitstatus!=EXIT_NOMEM)) - PrintOut(LOG_INFO, "Memory still allocated for devices at exit is %" PRId64 " bytes.\n", bytes); - - // if we are exiting because of a code bug, tell user - if (exitstatus==EXIT_BADCODE || (bytes && exitstatus!=EXIT_NOMEM)) - PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n"); - - if (exitstatus==0 && bytes) - exitstatus=EXIT_BADCODE; - - // and this should be the final output from smartd before it exits - PrintOut(exitstatus?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", exitstatus); - - return; -} - -#define ENVLENGTH 512 - -// 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 or -// deleted via another call to putenv(). So we keep these on the stack -// as long as the popen() call is underway. -int exportenv(char* stackspace, const char *name, const char *value){ - snprintf(stackspace,ENVLENGTH, "%s=%s", name, value); - return putenv(stackspace); -} - -char* dnsdomain(const char* hostname) { - char *p = NULL; -#ifdef HAVE_GETHOSTBYNAME - struct hostent *hp; - - if ((hp = gethostbyname(hostname))) { - // Does this work if gethostbyname() returns an IPv6 name in - // colon/dot notation? [BA] - if ((p = strchr(hp->h_name, '.'))) - p++; // skip "." - } -#else - ARGUSED(hostname); -#endif - return p; -} - -#define EBUFLEN 1024 - -// If either address or executable path is non-null then send and log -// a warning email, or execute executable -void MailWarning(cfgfile *cfg, int which, char *fmt, ...){ - char command[2048], message[256], hostname[256], domainname[256], additional[256]; - char original[256], further[256], nisdomain[256], subject[256],dates[DATEANDEPOCHLEN]; - char environ_strings[10][ENVLENGTH]; - time_t epoch; - va_list ap; - const int day=24*3600; - int days=0; - char *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 - }; - - char *address, *executable; - mailinfo *mail; - maildata* data=cfg->mailwarn; -#ifndef _WIN32 - FILE *pfp=NULL; -#else - char stdinbuf[1024]; int boxmsgoffs, boxtype; -#endif - char *newadd=NULL, *newwarn=NULL; - const char *unknown="[Unknown]"; - - // See if user wants us to send mail - if (!data) - return; - - address=data->address; - executable=data->emailcmdline; - - if (!address && !executable) - return; - - // which type of mail are we sending? - mail=(data->maillog)+which; - - // checks for sanity - if (data->emailfreq<1 || data->emailfreq>3) { - PrintOut(LOG_CRIT,"internal error in MailWarning(): cfg->mailwarn->emailfreq=%d\n",data->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 ((data->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. - epoch=time(NULL); - - // Return if less than one day has gone by - if (data->emailfreq==2 && mail->logged && epoch<(mail->lastsent+day)) - return; - - // Return if less than 2^(logged-1) days have gone by - if (data->emailfreq==3 && mail->logged){ - days=0x01<<(mail->logged-1); - days*=day; - if (epoch<(mail->lastsent+days)) - return; - } - - // record the time of this mail message, and the first mail message - if (!mail->logged) - mail->firstsent=epoch; - mail->lastsent=epoch; - - // get system host & domain names (not null terminated if length=MAX) -#ifdef HAVE_GETHOSTNAME - if (gethostname(hostname, 256)) - strcpy(hostname, unknown); - else { - char *p=NULL; - hostname[255]='\0'; - p = dnsdomain(hostname); - if (p && *p) { - strncpy(domainname, p, 255); - domainname[255]='\0'; - } else - strcpy(domainname, unknown); - } -#else - strcpy(hostname, unknown); - strcpy(domainname, unknown); -#endif - -#ifdef HAVE_GETDOMAINNAME - if (getdomainname(nisdomain, 256)) - strcpy(nisdomain, unknown); - else - nisdomain[255]='\0'; -#else - strcpy(nisdomain, unknown); -#endif - - // print warning string into message - va_start(ap, fmt); - vsnprintf(message, 256, fmt, ap); - va_end(ap); - - // appropriate message about further information - additional[0]=original[0]=further[0]='\0'; - if (which) { - sprintf(further,"You can also use the smartctl utility for further investigation.\n"); - - switch (data->emailfreq){ - case 1: - sprintf(additional,"No additional email messages about this problem will be sent.\n"); - break; - case 2: - sprintf(additional,"Another email message will be sent in 24 hours if the problem persists.\n"); - break; - case 3: - sprintf(additional,"Another email message will be sent in %d days if the problem persists\n", - (0x01)<<mail->logged); - break; - } - if (data->emailfreq>1 && mail->logged){ - dateandtimezoneepoch(dates, mail->firstsent); - sprintf(original,"The original email about this issue was sent at %s\n", dates); - } - } - - snprintf(subject, 256,"SMART error (%s) detected on host: %s", whichfail[which], hostname); - - // If the user has set cfg->emailcmdline, use that as mailer, else "mail" or "mailx". - if (!executable) -#ifdef DEFAULT_MAILER - executable = DEFAULT_MAILER ; -#else -#ifndef _WIN32 - executable = "mail"; -#else - executable = "blat"; // http://blat.sourceforge.net/ -#endif -#endif - - // make a private copy of address with commas replaced by spaces - // to separate recipients - if (address) { - address=CustomStrDup(data->address, 1, __LINE__, filenameandversion); -#ifndef _WIN32 // blat mailer needs comma - char *comma=address; - while ((comma=strchr(comma, ','))) - *comma=' '; -#endif - } - - // Export information in environment variables that will be useful - // for user scripts - exportenv(environ_strings[0], "SMARTD_MAILER", executable); - exportenv(environ_strings[1], "SMARTD_MESSAGE", message); - exportenv(environ_strings[2], "SMARTD_SUBJECT", subject); - dateandtimezoneepoch(dates, mail->firstsent); - exportenv(environ_strings[3], "SMARTD_TFIRST", dates); - snprintf(dates, DATEANDEPOCHLEN,"%d", (int)mail->firstsent); - exportenv(environ_strings[4], "SMARTD_TFIRSTEPOCH", dates); - exportenv(environ_strings[5], "SMARTD_FAILTYPE", whichfail[which]); - if (address) - exportenv(environ_strings[6], "SMARTD_ADDRESS", address); - exportenv(environ_strings[7], "SMARTD_DEVICESTRING", cfg->name); - - switch (cfg->controller_type) { - case CONTROLLER_3WARE_678K: - case CONTROLLER_3WARE_9000_CHAR: - case CONTROLLER_3WARE_678K_CHAR: - { - char *s,devicetype[16]; - sprintf(devicetype, "3ware,%d", cfg->controller_port-1); - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", devicetype); - if ((s=strchr(cfg->name, ' '))) - *s='\0'; - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - if (s) - *s=' '; - } - break; - case CONTROLLER_ATA: - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "ata"); - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - break; - case CONTROLLER_SCSI: - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "scsi"); - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - } - - // now construct a command to send this as EMAIL -#ifndef _WIN32 - if (address) - snprintf(command, 2048, - "$SMARTD_MAILER -s '%s' %s 2>&1 << \"ENDMAIL\"\n" - "This email was generated by the smartd daemon running on:\n\n" - " host name: %s\n" - " DNS domain: %s\n" - " NIS domain: %s\n\n" - "The following warning/error was logged by the smartd daemon:\n\n" - "%s\n\n" - "For details see host's SYSLOG (default: /var/log/messages).\n\n" - "%s%s%s" - "ENDMAIL\n", - subject, address, hostname, domainname, nisdomain, message, further, original, additional); - else - snprintf(command, 2048, "%s 2>&1", executable); - - // tell SYSLOG what we are about to do... - newadd=address?address:"<nomailer>"; - newwarn=which?"Warning via":"Test of"; - - 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; - 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 - - // No "here-documents" on Windows, so must use separate commandline and stdin - command[0] = stdinbuf[0] = 0; - boxtype = -1; boxmsgoffs = 0; - newadd = "<nomailer>"; - if (address) { - // address "[sys]msgbox ..." => show warning (also) as [system modal ]messagebox - int addroffs = (!strncmp(address, "sys", 3) ? 3 : 0); - if (!strncmp(address+addroffs, "msgbox", 6) && (!address[addroffs+6] || address[addroffs+6] == ',')) { - boxtype = (addroffs > 0 ? 1 : 0); - addroffs += 6; - if (address[addroffs]) - addroffs++; - } - else - addroffs = 0; - - if (address[addroffs]) { - // Use "blat" parameter syntax (TODO: configure via -M for other mailers) - snprintf(command, sizeof(command), - "%s - -q -subject \"%s\" -to \"%s\"", - executable, subject, address+addroffs); - newadd = address+addroffs; - } - // Message for mail [0...] and messagebox [boxmsgoffs...] - snprintf(stdinbuf, sizeof(stdinbuf), - "This email was generated by the smartd daemon running on:\n\n" - " host name: %s\n" - " DNS domain: %s\n" -// " NIS domain: %s\n" - "\n%n" - "The following warning/error was logged by the smartd daemon:\n\n" - "%s\n\n" - "For details see the event log or log file of smartd.\n\n" - "%s%s%s" - "\n", - hostname, /*domainname, */ nisdomain, &boxmsgoffs, message, further, original, additional); - } - else - snprintf(command, sizeof(command), "%s", executable); - - newwarn=which?"Warning via":"Test of"; - if (boxtype >= 0) { - // show message box - daemon_messagebox(boxtype, subject, stdinbuf+boxmsgoffs); - PrintOut(LOG_INFO,"%s message box\n", newwarn); - } - if (command[0]) { - 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, stdinbuf, strlen(stdinbuf), 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, 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++; - - // free copy of address (without commas) - address=FreeNonZero(address, -1, __LINE__, filenameandversion); - - return; -} - -// 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(char *fmt, ...){ - va_list ap; - - // get the correct time in syslog() - FixGlibcTimeZoneBug(); - // initialize variable argument list - va_start(ap,fmt); - // in debug==1 mode we will print the output from the ataprint.o functions! - if (debugmode && debugmode!=2) -#ifdef _WIN32 - if (facility == LOG_LOCAL1) // logging to stdout - vfprintf(stderr,fmt,ap); - else -#endif - vprintf(fmt,ap); - // in debug==2 mode we print output from knowndrives.o functions - else if (debugmode==2 || con->reportataioctl || con->reportscsiioctl || con->controller_port) { - openlog("smartd", LOG_PID, facility); - vsyslog(LOG_INFO, fmt, ap); - closelog(); - } - va_end(ap); - fflush(NULL); - return; -} - -// This function prints either to stdout or to the syslog as needed. -// This function is also used by utility.c to report LOG_CRIT errors. -void PrintOut(int priority,char *fmt, ...){ - va_list ap; - - // get the correct time in syslog() - FixGlibcTimeZoneBug(); - // initialize variable argument list - va_start(ap,fmt); - if (debugmode) -#ifdef _WIN32 - if (facility == LOG_LOCAL1) // logging to stdout - vfprintf(stderr,fmt,ap); - else -#endif - vprintf(fmt,ap); - else { - openlog("smartd", LOG_PID, facility); - vsyslog(priority,fmt,ap); - closelog(); - } - va_end(ap); - return; -} - -// Forks new process, closes ALL file descriptors, redirects stdin, -// stdout, and stderr. Not quite daemon(). See -// http://www.iar.unlp.edu.ar/~fede/revistas/lj/Magazines/LJ47/2335.html -// for a good description of why we do things this way. -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 ((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); - - // 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); - - // redirect any IO attempts to /dev/null for stdin - i=open("/dev/null",O_RDWR); - // stdout - dup(i); - // stderr - dup(i); - umask(0); - chdir("/"); - - 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 -void WritePidFile() { - if (pid_file) { - int error = 0; - pid_t pid = getpid(); - mode_t old_umask; - FILE* fp; - - old_umask = umask(0077); - fp = fopen(pid_file, "w"); - umask(old_umask); - if (fp == NULL) { - error = 1; - } else if (fprintf(fp, "%d\n", (int)pid) <= 0) { - error = 1; - } else if (fclose(fp) != 0) { - error = 1; - } - if (error) { - PrintOut(LOG_CRIT, "unable to write PID file %s - exiting.\n", pid_file); - EXIT(EXIT_PID); - } - PrintOut(LOG_INFO, "file %s written containing PID %d\n", pid_file, (int)pid); - } - return; -} - -// Prints header identifying version of code and home -void PrintHead(){ - PrintOut(LOG_INFO,"smartd version %s [%s] Copyright (C) 2002-4 Bruce Allen\n", PACKAGE_VERSION, SMARTMONTOOLS_BUILD_HOST); - PrintOut(LOG_INFO,"Home page is " PACKAGE_HOMEPAGE "\n\n"); - return; -} - -// prints help info for configuration file Directives -void Directives() { - PrintOut(LOG_INFO, - "Configuration file (%s) Directives (after device name):\n" - " -d TYPE Set the device type: ata, scsi, removable, 3ware,N\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, standby, idle\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. Type is one of: error, selftest\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 Current Pending Sectors in Attribute ID\n" - " -U ID Monitor Offline Uncorrectable Sectors in Attribute ID\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 -C 197 -U 198\n" - " -F TYPE Firmware bug workaround: none, samsung, samsung2\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/hda -a\n", - configfile); - return; -} - -/* Returns a pointer to a static string containing a formatted list of the valid - arguments to the option opt or NULL on failure. */ -const char *GetValidArgList(char opt) { - switch (opt) { - case 'c': - return "<FILE_NAME>, -"; - case 's': - return "valid_regular_expression"; - case 'l': - return "daemon, local0, local1, local2, local3, local4, local5, local6, local7"; - case 'q': - return "nodev, errors, nodevstartup, never, onecheck"; - case 'r': - return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; - case 'p': - return "<FILE_NAME>"; - case 'i': - return "<INTEGER_SECONDS>"; - default: - return NULL; - } -} - -/* prints help information for command syntax */ -void Usage (void){ - PrintOut(LOG_INFO,"Usage: smartd [options]\n\n"); -#ifdef HAVE_GETOPT_LONG - PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n"); - PrintOut(LOG_INFO," Read configuration file NAME or stdin [default is %s]\n\n", configfile); - 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"); -#if !(defined(_WIN32) || defined(__CYGWIN__)) - PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n"); -#else -#ifdef _WIN32 - PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n"); -#else - PrintOut(LOG_INFO," Use syslog facility local0 - local7 (ignored on Cygwin)\n\n"); -#endif -#endif // _WIN32 || __CYGWIN__ - 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')); -#ifdef _WIN32 - PrintOut(LOG_INFO," --service\n"); - PrintOut(LOG_INFO," Running as windows service (must be first arg, do not use from console)\n\n"); -#endif // _WIN32 - PrintOut(LOG_INFO," -V, --version, --license, --copyright\n"); - PrintOut(LOG_INFO," Print License, Copyright, and version information\n"); -#else - PrintOut(LOG_INFO," -c NAME|- Read configuration file NAME or stdin [default is %s]\n", configfile); - PrintOut(LOG_INFO," -d Start smartd in debug mode\n"); - PrintOut(LOG_INFO," -D Print the configuration file Directives and exit\n"); - PrintOut(LOG_INFO," -h Display this help and exit\n"); - PrintOut(LOG_INFO," -i N Set interval between disk checks to N seconds, where N >= 10\n"); - PrintOut(LOG_INFO," -l local? Use syslog facility local0 - local7, or daemon\n"); - PrintOut(LOG_INFO," -p NAME Write PID file NAME\n"); - PrintOut(LOG_INFO," -q WHEN Quit on one of: %s\n", GetValidArgList('q')); - PrintOut(LOG_INFO," -r TYPE Report transactions for one of: %s\n", GetValidArgList('r')); - PrintOut(LOG_INFO," -V Print License, Copyright, and version information\n"); -#endif -} - -// returns negative if problem, else fd>=0 -static int OpenDevice(char *device, char *mode, int scanning) { - int fd; - char *s=device; - - // If there is an ASCII "space" character in the device name, - // terminate string there. This is for 3ware devices only. - if ((s=strchr(device,' '))) - *s='\0'; - - // open the device - fd = deviceopen(device, mode); - - // if we removed a space, put it back in please - if (s) - *s=' '; - - // if we failed to open the device, complain! - if (fd < 0) { - - // 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) { - if (errno==ENOENT || errno==ENOTDIR) - errno=ENODEV; - - PrintOut(LOG_INFO,"Device: %s, %s, open() failed\n", - device, strerror(errno)); - } - return -1; - } - // device opened sucessfully - return fd; -} - -int CloseDevice(int fd, char *name){ - if (deviceclose(fd)){ - PrintOut(LOG_INFO,"Device: %s, %s, close(%d) failed\n", name, strerror(errno), fd); - return 1; - } - // device sucessfully closed - return 0; -} - -// returns <0 on failure -int ATAErrorCount(int fd, char *name){ - struct ata_smart_errorlog log; - - if (-1==ataReadErrorLog(fd,&log)){ - PrintOut(LOG_INFO,"Device: %s, Read SMART Error Log Failed\n",name); - return -1; - } - - // return current number of ATA errors - return log.error_log_pointer?log.ata_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. -int SelfTestErrorCount(int fd, char *name){ - struct ata_smart_selftestlog log; - - if (-1==ataReadSelfTestLog(fd,&log)){ - 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,0); -} - -// scan to see what ata devices there are, and if they support SMART -int ATADeviceScan(cfgfile *cfg, int scanning){ - int fd, supported=0; - struct ata_identify_device drive; - char *name=cfg->name; - int retainsmartdata=0; - int retid; - char *mode; - - // should we try to register this as an ATA device? - switch (cfg->controller_type) { - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - case CONTROLLER_UNKNOWN: - mode="ATA"; - break; - case CONTROLLER_3WARE_678K_CHAR: - mode="ATA_3WARE_678K"; - break; - case CONTROLLER_3WARE_9000_CHAR: - mode="ATA_3WARE_9000"; - break; - default: - // not a recognized ATA or SATA device. We should never enter - // this branch. - return 1; - } - - // open the device - if ((fd=OpenDevice(name, mode, scanning))<0) - // device open failed - return 1; - PrintOut(LOG_INFO,"Device: %s, opened\n", name); - - // pass user settings on to low-level ATA commands - con->controller_port=cfg->controller_port; - con->controller_type=cfg->controller_type; - con->fixfirmwarebug = cfg->fixfirmwarebug; - - // Get drive identity structure - if ((retid=ataReadHDIdentity (fd,&drive))){ - 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(fd, name); - return 2; - } - - // 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 { - // do whatever applypresets decides to do. Will allocate memory if - // cfg->attributedefs is needed. - if (applypresets(&drive, &cfg->attributedefs, con)<0) - PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name); - else - PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name); - - // then save the correct state of the flag (applypresets may have changed it) - cfg->fixfirmwarebug = con->fixfirmwarebug; - } - - // 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; - showpresets(&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(fd, name); - return 2; - } - } - - if (ataEnableSmart(fd)){ - // Enable SMART command has failed - PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); - CloseDevice(fd, name); - return 2; - } - - // disable device attribute autosave... - if (cfg->autosave==1){ - if (ataDisableAutoSave(fd)) - 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(fd)) - 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(fd)==-1){ - PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name); - cfg->smartcheck=0; - } - - // 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 retain SMART data after returning from this routine? - retainsmartdata=cfg->usagefailed || cfg->prefail || cfg->usage; - - // do we need to get SMART data? - if (retainsmartdata || cfg->autoofflinetest || cfg->selftest || cfg->errorlog || cfg->pending!=DONT_MONITOR_UNC) { - - unsigned char currentpending, offlinepending; - - cfg->smartval=(struct ata_smart_values *)Calloc(1,sizeof(struct ata_smart_values)); - cfg->smartthres=(struct ata_smart_thresholds_pvt *)Calloc(1,sizeof(struct ata_smart_thresholds_pvt)); - - if (!cfg->smartval || !cfg->smartthres){ - PrintOut(LOG_CRIT,"Not enough memory to obtain SMART data\n"); - EXIT(EXIT_NOMEM); - } - - if (ataReadSmartValues(fd,cfg->smartval) || - ataReadSmartThresholds (fd,cfg->smartthres)){ - PrintOut(LOG_INFO,"Device: %s, Read SMART Values and/or Thresholds Failed\n",name); - retainsmartdata=cfg->usagefailed=cfg->prefail=cfg->usage=0; - cfg->pending=DONT_MONITOR_UNC; - } - - // see if the necessary Attribute is there to monitor offline or - // current pending sectors - TranslatePending(cfg->pending, ¤tpending, &offlinepending); - - if (currentpending && ATAReturnAttributeRawValue(currentpending, cfg->smartval)<0) { - PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n", - name, (int)currentpending); - cfg->pending &= 0xff00; - cfg->pending |= CUR_UNC_DEFAULT; - } - - if (offlinepending && ATAReturnAttributeRawValue(offlinepending, cfg->smartval)<0) { - PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n", - name, (int)offlinepending); - cfg->pending &= 0x00ff; - cfg->pending |= OFF_UNC_DEFAULT<<8; - } - } - - // enable/disable automatic on-line testing - if (cfg->autoofflinetest){ - // is this an enable or disable request? - char *what=(cfg->autoofflinetest==1)?"disable":"enable"; - if (!cfg->smartval) - 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(cfg->smartval)) - PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name); - // ... but then try anyway - if ((cfg->autoofflinetest==1)?ataDisableAutoOffline(fd):ataEnableAutoOffline(fd)) - 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); - } - } - - // capability check: self-test-log - if (cfg->selftest){ - int retval; - - // start with service disabled, and re-enable it if all works OK - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - - if (!cfg->smartval) - PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log (SMART READ DATA failed); disabling -l selftest\n", name); - else if (!cfg->permissive && !isSmartTestLogCapable(cfg->smartval, &drive)) - PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Self-Test log; disabling -l selftest (override with -T permissive Directive)\n", name); - else if ((retval=SelfTestErrorCount(fd, name))<0) - PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log; remove -l selftest Directive from smartd.conf\n", name); - else { - cfg->selftest=1; - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } - } - - // capability check: ATA error log - if (cfg->errorlog){ - int val; - - // start with service disabled, and re-enable it if all works OK - cfg->errorlog=0; - cfg->ataerrorcount=0; - - if (!cfg->smartval) - PrintOut(LOG_INFO, "Device: %s, no SMART Error log (SMART READ DATA failed); disabling -l error\n", name); - else if (!cfg->permissive && !isSmartErrorLogCapable(cfg->smartval, &drive)) - PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Error log; disabling -l error (override with -T permissive Directive)\n", name); - else if ((val=ATAErrorCount(fd, name))<0) - PrintOut(LOG_INFO, "Device: %s, no SMART Error log; remove -l error Directive from smartd.conf\n", name); - else { - cfg->errorlog=1; - cfg->ataerrorcount=val; - } - } - - // If we don't need to save SMART data, get rid of it now - if (!retainsmartdata) { - if (cfg->smartval) { - cfg->smartval=CheckFree(cfg->smartval, __LINE__,filenameandversion); - bytes-=sizeof(struct ata_smart_values); - } - if (cfg->smartthres) { - cfg->smartthres=CheckFree(cfg->smartthres, __LINE__,filenameandversion); - bytes-=sizeof(struct ata_smart_thresholds_pvt); - } - } - - // capabilities check -- does it support powermode? - if (cfg->powermode) { - int powermode=ataCheckPowerMode(fd); - - 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; - } - } - - // If no tests available or selected, return - if (!(cfg->errorlog || cfg->selftest || cfg->smartcheck || - cfg->usagefailed || cfg->prefail || cfg->usage)) { - CloseDevice(fd, name); - return 3; - } - - // Do we still have entries available? - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); - - // register device - PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name); - - // record number of device, type of device, increment device count - if (cfg->controller_type == CONTROLLER_UNKNOWN) - cfg->controller_type=CONTROLLER_ATA;; - - // close file descriptor - CloseDevice(fd, name); - return 0; -} - -// on success, return 0. On failure, return >0. Never return <0, -// please. -static int SCSIDeviceScan(cfgfile *cfg, int scanning) { - int k, fd, err; - char *device = cfg->name; - struct scsi_iec_mode_page iec; - UINT8 tBuf[64]; - - // should we try to register this as a SCSI device? - switch (con->controller_type) { - case CONTROLLER_SCSI: - case CONTROLLER_UNKNOWN: - break; - default: - return 1; - } - - // open the device - if ((fd = OpenDevice(device, "SCSI", scanning)) < 0) - return 1; - PrintOut(LOG_INFO,"Device: %s, opened\n", device); - - // check that device is ready for commands. IE stores its stuff on - // the media. - if ((err = scsiTestUnitReady(fd))) { - if (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(fd, 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(fd, &iec, cfg->modese_len))) - cfg->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(fd, 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(fd, device); - return 3; - } - - // Device exists, and does SMART. Add to list (allocating more space if needed) - while (numdevscsi >= scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); - - // Flag that certain log pages are supported (information may be - // available from other sources). - if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { - for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { - switch (tBuf[k]) { - case TEMPERATURE_LPAGE: - cfg->TempPageSupported = 1; - break; - case IE_LPAGE: - cfg->SmartPageSupported = 1; - break; - default: - break; - } - } - } - - // record type of device - cfg->controller_type = CONTROLLER_SCSI; - - // get rid of allocated memory only needed for ATA devices. These - // might have been allocated if the user specified Ignore options or - // other ATA-only Attribute-specific options on the DEVICESCAN line. - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); - - // Check if scsiCheckIE() is going to work - { - UINT8 asc = 0; - UINT8 ascq = 0; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); - cfg->SuppressReport = 1; - } - } - - // capability check: self-test-log - if (cfg->selftest){ - int retval=scsiCountFailedSelfTests(fd, 0); - if (retval<0) { - // no self-test log, turn off monitoring - PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device); - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - } - else { - // register starting values to watch for changes - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } - } - - // disable autosave (set GLTSD bit) - if (cfg->autosave==1){ - if (scsiSetControlGLTSD(fd, 1, cfg->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(fd, 0, cfg->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); - - // close file descriptor - CloseDevice(fd, device); - return 0; -} - -// We compare old and new values of the n'th attribute. Note that n -// is NOT the attribute ID number.. If (Normalized & Raw) equal, -// then return 0, else nonzero. -int ATACompareValues(changedattribute_t *delta, - struct ata_smart_values *new, - struct ata_smart_values *old, - struct ata_smart_thresholds_pvt *thresholds, - int n, char *name){ - struct ata_smart_attribute *now,*was; - struct ata_smart_threshold_entry *thre; - unsigned char oldval,newval; - int sameraw; - - // check that attribute number in range, and no null pointers - if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !new || !old || !thresholds) - return 0; - - // pointers to disk's values and vendor's thresholds - now=new->vendor_attributes+n; - was=old->vendor_attributes+n; - thre=thresholds->thres_entries+n; - - // consider only valid attributes - if (!now->id || !was->id || !thre->id) - return 0; - - - // issue warning if they don't have the same ID in all structures: - if ( (now->id != was->id) || (now->id != thre->id) ){ - PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n", - name, (int)now->id, (int)was->id, (int)thre->id); - return 0; - } - - // new and old values of Normalized Attributes - newval=now->current; - oldval=was->current; - - // See if the RAW values are unchanged (ie, the same) - if (memcmp(now->raw, was->raw, 6)) - sameraw=0; - else - sameraw=1; - - // if any values out of the allowed range, or if the values haven't - // changed, return 0 - if (!newval || !oldval || newval>0xfe || oldval>0xfe || (oldval==newval && sameraw)) - return 0; - - // values have changed. Construct output and return - delta->newval=newval; - delta->oldval=oldval; - delta->id=now->id; - delta->prefail=ATTRIBUTE_FLAGS_PREFAILURE(now->flags); - delta->sameraw=sameraw; - - return 1; -} - -// This looks to see if the corresponding bit of the 32 bytes is set. -// This wastes a few bytes of storage but eliminates all searching and -// sorting functions! Entry is ZERO <==> the attribute ON. Calling -// with set=0 tells you if the attribute is being tracked or not. -// Calling with set=1 turns the attribute OFF. -int IsAttributeOff(unsigned char attr, unsigned char **datap, int set, int which, int whatline){ - unsigned char *data; - int loc=attr>>3; - int bit=attr & 0x07; - unsigned char mask=0x01<<bit; - - if (which>=NMONITOR || which < 0){ - PrintOut(LOG_CRIT, "Internal error in IsAttributeOff() at line %d of file %s (which=%d)\n%s", - whatline, filenameandversion, which, reportbug); - EXIT(EXIT_BADCODE); - } - - if (*datap == NULL){ - // NULL data implies Attributes are ON... - if (!set) - return 0; - - // we are writing - if (!(*datap=(unsigned char *)Calloc(NMONITOR*32, 1))){ - PrintOut(LOG_CRIT,"No memory to create monattflags\n"); - EXIT(EXIT_NOMEM); - } - } - - // pointer to the 256 bits that we need - data=*datap+which*32; - - // attribute zero is always OFF - if (!attr) - return 1; - - if (!set) - return (data[loc] & mask); - - data[loc]|=mask; - - // return value when setting has no sense - return 0; -} - -// If the self-test log has got more self-test errors (or more recent -// self-test errors) recorded, then notify user. -void CheckSelfTestLogs(cfgfile *cfg, int new){ - char *name=cfg->name; - - if (new<0) - // command failed - MailWarning(cfg, 8, "Device: %s, Read SMART Self-Test Log Failed", name); - else { - // old and new error counts - int oldc=cfg->selflogcount; - int newc=SELFTEST_ERRORCOUNT(new); - - // old and new error timestamps in hours - int oldh=cfg->selfloghour; - int newh=SELFTEST_ERRORHOURS(new); - - 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, 3, "Device: %s, Self-Test Log error count increased from %d to %d", - name, oldc, newc); - } else if (oldh<newh) { - // more recent error - PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n", - name, newh); - MailWarning(cfg, 3, "Device: %s, new Self-Test Log error at hour timestamp %d\n", - name, newh); - } - - // Needed since self-test error count may DECREASE. Hour should - // never decrease but this does no harm. - cfg->selflogcount= newc; - cfg->selfloghour = newh; - } - return; -} - -// returns 1 if time to do test of type testtype, 0 if not time to do -// test, < 0 if error -int DoTestNow(cfgfile *cfg, char testtype) { - // start by finding out the time: - struct tm *timenow; - time_t epochnow; - char matchpattern[16]; - regmatch_t substring; - int weekday, length; - unsigned short hours; - testinfo *dat=cfg->testdata; - - // check that self-testing has been requested - if (!dat) - return 0; - - // since we are about to call localtime(), be sure glibc is informed - // of any timezone changes we make. - FixGlibcTimeZoneBug(); - - // construct pattern containing the month, day of month, day of - // week, and hour - time(&epochnow); - timenow=localtime(&epochnow); - - // tm_wday is 0 (Sunday) to 6 (Saturday). We use 1 (Monday) to 7 - // (Sunday). - weekday=timenow->tm_wday?timenow->tm_wday:7; - sprintf(matchpattern, "%c/%02d/%02d/%1d/%02d", testtype, timenow->tm_mon+1, - timenow->tm_mday, weekday, timenow->tm_hour); - - // if no match, we are done - if (regexec(&(dat->cregex), matchpattern, 1, &substring, 0)) - return 0; - - // must match the ENTIRE type/date/time string - length=strlen(matchpattern); - if (substring.rm_so!=0 || substring.rm_eo!=length) - return 0; - - // never do a second test in the same hour as another test (the % 7 ensures - // that the RHS will never be greater than 65535 and so will always fit into - // an unsigned short) - hours=1+timenow->tm_hour+24*(timenow->tm_yday+366*(timenow->tm_year % 7)); - if (hours==dat->hour) { - if (testtype!=dat->testtype) - PrintOut(LOG_INFO, "Device: %s, did test of type %c in current hour, skipping test of type %c\n", - cfg->name, dat->testtype, testtype); - return 0; - } - - // save time and type of the current test; we are ready to do a test - dat->hour=hours; - dat->testtype=testtype; - return 1; -} - -// Return zero on success, nonzero on failure. Perform offline (background) -// short or long (extended) self test on given scsi device. -int DoSCSISelfTest(int fd, cfgfile *cfg, char testtype) { - int retval = 0; - char *testname = NULL; - char *name = cfg->name; - int inProgress; - - if (scsiSelfTestInProgress(fd, &inProgress)) { - PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name); - cfg->testdata->not_cap_short=cfg->testdata->not_cap_long=1; - 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(fd); - break; - case 'L': - testname = "Long Self"; - retval = scsiSmartExtendSelfTest(fd); - 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) - cfg->testdata->not_cap_long=1; - else - cfg->testdata->not_cap_short=1; - - 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. -int DoATASelfTest(int fd, cfgfile *cfg, char testtype) { - - struct ata_smart_values data; - char *testname=NULL; - int retval, dotest=-1; - char *name=cfg->name; - - // Read current smart data and check status/capability - if (ataReadSmartValues(fd, &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 - switch (testtype) { - case 'O': - testname="Offline Immediate "; - if (isSupportExecuteOfflineImmediate(&data)) - dotest=OFFLINE_FULL_SCAN; - else - cfg->testdata->not_cap_offline=1; - break; - case 'C': - testname="Conveyance Self-"; - if (isSupportConveyanceSelfTest(&data)) - dotest=CONVEYANCE_SELF_TEST; - else - cfg->testdata->not_cap_conveyance=1; - break; - case 'S': - testname="Short Self-"; - if (isSupportSelfTest(&data)) - dotest=SHORT_SELF_TEST; - else - cfg->testdata->not_cap_short=1; - break; - case 'L': - testname="Long Self-"; - if (isSupportSelfTest(&data)) - dotest=EXTEND_SELF_TEST; - else - cfg->testdata->not_cap_long=1; - 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)) { - 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; - } - - // else execute the test, and return status - if ((retval=smartcommandhandler(fd, IMMEDIATE_OFFLINE, dotest, NULL))) - PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname); - else - PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname); - - return retval; -} - - -int ATACheckDevice(cfgfile *cfg){ - int fd,i; - char *name=cfg->name; - char *mode="ATA"; - - // fix firmware bug if requested - con->fixfirmwarebug=cfg->fixfirmwarebug; - con->controller_port=cfg->controller_port; - con->controller_type=cfg->controller_type; - - // If user has asked, test the email warning system - if (cfg->mailwarn && cfg->mailwarn->emailtest) - MailWarning(cfg, 0, "TEST EMAIL from smartd for device: %s", name); - - if (cfg->controller_type == CONTROLLER_3WARE_9000_CHAR) - mode="ATA_3WARE_9000"; - - if (cfg->controller_type == CONTROLLER_3WARE_678K_CHAR) - mode="ATA_3WARE_678K"; - - // 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 ((fd=OpenDevice(name, mode, 0))<0){ - MailWarning(cfg, 9, "Device: %s, unable to open device", name); - return 1; - } - - // 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){ - int dontcheck=0, powermode=ataCheckPowerMode(fd); - char *mode=NULL; - - 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 - break; - default: - // UNKNOWN - PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", - name, powermode); - cfg->powermode=0; - break; - } - - // if we are going to skip a check, return now - if (dontcheck){ - CloseDevice(fd, name); - PrintOut(LOG_INFO, "Device: %s, is in %s mode, skipping checks\n", name, mode); - return 0; - } - } - - // check smart status - if (cfg->smartcheck){ - int status=ataSmartStatus2(fd); - if (status==-1){ - PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name); - MailWarning(cfg, 5, "Device: %s, not capable of SMART self-check", name); - } - else if (status==1){ - PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name); - MailWarning(cfg, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name); - } - } - - // Check everything that depends upon SMART Data (eg, Attribute values) - if (cfg->usagefailed || cfg->prefail || cfg->usage || cfg->pending!=DONT_MONITOR_UNC){ - struct ata_smart_values curval; - struct ata_smart_thresholds_pvt *thresh=cfg->smartthres; - - // Read current attribute values. *drive contains old values and thresholds - if (ataReadSmartValues(fd,&curval)){ - PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name); - MailWarning(cfg, 6, "Device: %s, failed to read SMART Attribute Data", name); - } - else { - // look for current or offline pending sectors - if (cfg->pending != DONT_MONITOR_UNC) { - int64_t rawval; - unsigned char currentpending, offlinepending; - - TranslatePending(cfg->pending, ¤tpending, &offlinepending); - - if (currentpending && (rawval=ATAReturnAttributeRawValue(currentpending, &curval))>0) { - // Unreadable pending sectors!! - PrintOut(LOG_CRIT, "Device: %s, %"PRId64" Currently unreadable (pending) sectors\n", name, rawval); - MailWarning(cfg, 10, "Device: %s, %"PRId64" Currently unreadable (pending) sectors", name, rawval); - } - - if (offlinepending && (rawval=ATAReturnAttributeRawValue(offlinepending, &curval))>0) { - // Unreadable offline sectors!! - PrintOut(LOG_CRIT, "Device: %s, %"PRId64" Offline uncorrectable sectors\n", name, rawval); - MailWarning(cfg, 11, "Device: %s, %"PRId64" Offline uncorrectable sectors", name, rawval); - } - } - - if (cfg->usagefailed || cfg->prefail || cfg->usage) { - - // look for failed usage attributes, or track usage or prefail attributes - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ - int att; - changedattribute_t delta; - - // This block looks for usage attributes that have failed. - // Prefail attributes that have failed are returned with a - // positive sign. No failure returns 0. Usage attributes<0. - if (cfg->usagefailed && ((att=ataCheckAttribute(&curval, thresh, i))<0)){ - - // are we ignoring failures of this attribute? - att *= -1; - if (!IsAttributeOff(att, &cfg->monitorattflags, 0, MONITOR_FAILUSE, __LINE__)){ - char attname[64], *loc=attname; - - // get attribute name & skip white space - ataPrintSmartAttribName(loc, att, cfg->attributedefs); - while (*loc && *loc==' ') loc++; - - // warning message - PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc); - MailWarning(cfg, 2, "Device: %s, Failed SMART usage Attribute: %s.", name, loc); - } - } - - // This block tracks usage or prefailure attributes to see if - // they are changing. It also looks for changes in RAW values - // if this has been requested by user. - if ((cfg->usage || cfg->prefail) && ATACompareValues(&delta, &curval, cfg->smartval, thresh, i, name)){ - unsigned char id=delta.id; - - // if the only change is the raw value, and we're not - // tracking raw value, then continue loop over attributes - if (!delta.sameraw && delta.newval==delta.oldval && !IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_RAW, __LINE__)) - continue; - - // are we tracking this attribute? - if (!IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_IGNORE, __LINE__)){ - char newrawstring[64], oldrawstring[64], attname[64], *loc=attname; - - // get attribute name, skip spaces - ataPrintSmartAttribName(loc, id, cfg->attributedefs); - while (*loc && *loc==' ') loc++; - - // has the user asked for us to print raw values? - if (IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_RAWPRINT, __LINE__)) { - // get raw values (as a string) and add to printout - char rawstring[64]; - ataPrintSmartAttribRawValue(rawstring, curval.vendor_attributes+i, cfg->attributedefs); - sprintf(newrawstring, " [Raw %s]", rawstring); - ataPrintSmartAttribRawValue(rawstring, cfg->smartval->vendor_attributes+i, cfg->attributedefs); - sprintf(oldrawstring, " [Raw %s]", rawstring); - } - else - newrawstring[0]=oldrawstring[0]='\0'; - - // prefailure attribute - if (cfg->prefail && delta.prefail) - PrintOut(LOG_INFO, "Device: %s, SMART Prefailure Attribute: %s changed from %d%s to %d%s\n", - name, loc, delta.oldval, oldrawstring, delta.newval, newrawstring); - - // usage attribute - if (cfg->usage && !delta.prefail) - PrintOut(LOG_INFO, "Device: %s, SMART Usage Attribute: %s changed from %d%s to %d%s\n", - name, loc, delta.oldval, oldrawstring, delta.newval, newrawstring); - } - } // endof block tracking usage or prefailure - } // end of loop over attributes - - // Save the new values into *drive for the next time around - *(cfg->smartval)=curval; - } - } - } - - // check if number of selftest errors has increased (note: may also DECREASE) - if (cfg->selftest) - CheckSelfTestLogs(cfg, SelfTestErrorCount(fd, name)); - - // check if number of ATA errors has increased - if (cfg->errorlog){ - - int new,old=cfg->ataerrorcount; - - // new number of errors - new=ATAErrorCount(fd, name); - - // did command fail? - if (new<0) - // lack of PrintOut here is INTENTIONAL - MailWarning(cfg, 7, "Device: %s, Read SMART Error Log Failed", name); - - // has error count increased? - if (new>old){ - PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", - name, old, new); - MailWarning(cfg, 4, "Device: %s, ATA error count increased from %d to %d", - name, old, new); - } - - // this last line is probably not needed, count always increases - if (new>=0) - cfg->ataerrorcount=new; - } - - // if the user has asked, and device is capable (or we're not yet - // sure) carry out scheduled self-tests. - if (cfg->testdata) { - // long test - if (!cfg->testdata->not_cap_long && DoTestNow(cfg, 'L')>0) - DoATASelfTest(fd, cfg, 'L'); - // short test - else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S')>0) - DoATASelfTest(fd, cfg, 'S'); - // conveyance test - else if (!cfg->testdata->not_cap_conveyance && DoTestNow(cfg, 'C')>0) - DoATASelfTest(fd, cfg, 'C'); - // offline immediate - else if (!cfg->testdata->not_cap_offline && DoTestNow(cfg, 'O')>0) - DoATASelfTest(fd, cfg, 'O'); - } - - // Don't leave device open -- the OS/user may want to access it - // before the next smartd cycle! - CloseDevice(fd, name); - return 0; -} - -#define DEF_SCSI_REPORT_TEMPERATURE_DELTA 2 -static int scsi_report_temperature_delta = DEF_SCSI_REPORT_TEMPERATURE_DELTA; - -int SCSICheckDevice(cfgfile *cfg) -{ - UINT8 asc, ascq; - UINT8 currenttemp; - UINT8 triptemp; - int fd; - char *name=cfg->name; - const char *cp; - - // If the user has asked for it, test the email warning system - if (cfg->mailwarn && cfg->mailwarn->emailtest) - MailWarning(cfg, 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 ((fd=OpenDevice(name, "SCSI", 0))<0) { - // Lack of PrintOut() here is intentional! - MailWarning(cfg, 9, "Device: %s, unable to open device", name); - return 1; - } - currenttemp = 0; - asc = 0; - ascq = 0; - if (! cfg->SuppressReport) { - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n", - name); - MailWarning(cfg, 6, "Device: %s, failed to read SMART values", name); - cfg->SuppressReport = 1; - } - } - if (asc > 0) { - cp = scsiGetIEString(asc, ascq); - if (cp) { - PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp); - MailWarning(cfg, 1,"Device: %s, SMART Failure: %s", name, cp); - } - } else if (debugmode) - PrintOut(LOG_INFO,"Device: %s, Acceptable asc,ascq: %d,%d\n", - name, (int)asc, (int)ascq); - - if (currenttemp && currenttemp!=255) { - if (cfg->Temperature) { - if (abs(((int)currenttemp - (int)cfg->Temperature)) >= - scsi_report_temperature_delta) { - PrintOut(LOG_INFO, "Device: %s, Temperature changed %d Celsius " - "to %d Celsius since last report\n", name, - (int)(currenttemp - cfg->Temperature), - (int)currenttemp); - cfg->Temperature = currenttemp; - } - } - else { - PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d " - "Celsius\n", name, (int)currenttemp); - if (triptemp) - PrintOut(LOG_INFO, " [trip Temperature is %d Celsius]\n", - (int)triptemp); - cfg->Temperature = currenttemp; - cfg->Temperature = currenttemp; - } - } - - // check if number of selftest errors has increased (note: may also DECREASE) - if (cfg->selftest) - CheckSelfTestLogs(cfg, scsiCountFailedSelfTests(fd, 0)); - - if (cfg->testdata) { - // long (extended) background test - if (!cfg->testdata->not_cap_long && DoTestNow(cfg, 'L')>0) - DoSCSISelfTest(fd, cfg, 'L'); - // short background test - else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S')>0) - DoSCSISelfTest(fd, cfg, 'S'); - } - CloseDevice(fd, name); - return 0; -} - -// Checks the SMART status of all ATA and SCSI devices -void CheckDevicesOnce(cfgfile **atadevices, cfgfile **scsidevices){ - int i; - - for (i=0; i<numdevata; i++) - ATACheckDevice(atadevices[i]); - - for (i=0; i<numdevscsi; i++) - SCSICheckDevice(scsidevices[i]); - - return; -} - -#if SCSITIMEOUT -// This alarm means that a SCSI USB device was hanging -void AlarmHandler(int signal) { - longjmp(registerscsienv, 1); -} -#endif - -// Does initialization right after fork to daemon mode -void Initialize(time_t *wakeuptime){ - - // install goobye message and remove pidfile handler - atexit(Goodbye); - - // write PID file only after installing exit handler - 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 - -time_t dosleep(time_t wakeuptime){ - time_t timenow=0; - - // If past wake-up-time, compute next wake-up-time - timenow=time(NULL); - while (wakeuptime<=timenow){ - int intervals=1+(timenow-wakeuptime)/checktime; - wakeuptime+=intervals*checktime; - } - - // sleep until we catch SIGUSR1 or have completed sleeping - while (timenow<wakeuptime && !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-timenow); - -#ifdef _WIN32 - // toggle debug mode? - if (caughtsigUSR2) { - ToggleDebugMode(); - caughtsigUSR2 = 0; - } -#endif - - timenow=time(NULL); - } - - // 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; - } - - // return adjusted wakeuptime - return wakeuptime; -} - -// Print out a list of valid arguments for the Directive d -void printoutvaliddirectiveargs(int priority, char d) { - char *s=NULL; - - switch (d) { - case 'n': - PrintOut(priority, "never, sleep, standby, idle"); - break; - case 's': - PrintOut(priority, "valid_regular_expression"); - break; - case 'd': - PrintOut(priority, "ata, scsi, removable, 3ware,N"); - 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': - if (!(s = create_vendor_attribute_arg_list())) { - PrintOut(LOG_CRIT,"Insufficient memory to construct argument list\n"); - EXIT(EXIT_NOMEM); - } - PrintOut(priority, "\n%s\n", s); - s=CheckFree(s, __LINE__,filenameandversion); - break; - case 'P': - PrintOut(priority, "use, ignore, show, showall"); - break; - case 'F': - PrintOut(priority, "none, samsung, samsung2"); - break; - } -} - -// exits with an error message, or returns integer value of token -int GetInteger(char *arg, char *name, char *token, int lineno, char *configfile, int min, int max){ - char *endptr; - int val; - - // check input range - if (min<0){ - PrintOut(LOG_CRIT, "min =%d passed to GetInteger() must be >=0\n", min); - return -1; - } - - // 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", - configfile, lineno, name, token, min, max); - return -1; - } - - // get argument value (base 10), check that it's integer, and in-range - val=strtol(arg,&endptr,10); - if (*endptr!='\0' || val<min || val>max ) { - PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n", - configfile, lineno, name, token, arg, min, max); - return -1; - } - - // all is well; return value - return val; -} - -// 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. -int ParseToken(char *token,cfgfile *cfg){ - char sym; - char *name=cfg->name; - int lineno=cfg->lineno; - char *delim = " \n\t"; - int badarg = 0; - int missingarg = 0; - char *arg = NULL; - int makemail=0; - maildata *mdat=NULL, tempmail; - - // 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]; - - // create temporary maildata structure. This means we can postpone - // allocating space in the data segment until we are sure there are - // no errors. - if ('m'==sym || 'M'==sym){ - if (!cfg->mailwarn){ - memset(&tempmail, 0, sizeof(maildata)); - mdat=&tempmail; - makemail=1; - } - else - mdat=cfg->mailwarn; - } - - // parse the token and swallow its argument - switch (sym) { - int val; - - case 'C': - // monitor current pending sector count (default 197) - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255))<0) - return -1; - if (val==CUR_UNC_DEFAULT) - val=0; - else if (val==0) - val=CUR_UNC_DEFAULT; - // set bottom 8 bits to correct value - cfg->pending &= 0xff00; - cfg->pending |= val; - break; - case 'U': - // monitor offline uncorrectable sectors (default 198) - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255))<0) - return -1; - if (val==OFF_UNC_DEFAULT) - val=0; - else if (val==0) - val=OFF_UNC_DEFAULT; - // turn off top 8 bits, then set to correct value - cfg->pending &= 0xff; - cfg->pending |= (val<<8); - 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=0; - } else if (!strcmp(arg, "permissive")) { - // Permissive mode; ignore errors from Mandatory SMART commands - cfg->permissive=1; - } else { - badarg = 1; - } - break; - case 'd': - // specify the device type - if ((arg = strtok(NULL, delim)) == NULL) { - missingarg = 1; - } else if (!strcmp(arg, "ata")) { - cfg->controller_port = 0; - cfg->controller_type = CONTROLLER_ATA; - } else if (!strcmp(arg, "scsi")) { - cfg->controller_port =0; - cfg->controller_type = CONTROLLER_SCSI; - } else if (!strcmp(arg, "removable")) { - cfg->removable = 1; - } else { - // look 3ware,N RAID device - int i; - char *s; - - // make a copy of the string to mess with - if (!(s = strdup(arg))) { - PrintOut(LOG_CRIT, - "No memory to copy argument to -d option - exiting\n"); - EXIT(EXIT_NOMEM); - } else if (strncmp(s,"3ware,",6)) { - badarg=1; - } else if (split_report_arg2(s, &i)){ - PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N requires N integer\n", - configfile, lineno, name); - badarg=1; - } else if ( i<0 || i>15) { - PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N (N=%d) must have 0 <= N <= 15\n", - configfile, lineno, name, i); - badarg=1; - } else { - // determine type of escalade device from name of device - cfg->controller_type = guess_device_type(name); - if (cfg->controller_type!=CONTROLLER_3WARE_9000_CHAR && cfg->controller_type!=CONTROLLER_3WARE_678K_CHAR) - cfg->controller_type=CONTROLLER_3WARE_678K; - - // NOTE: controller_port == disk number + 1 - cfg->controller_port = i+1; - } - s=CheckFree(s, __LINE__,filenameandversion); - } - break; - case 'F': - // fix firmware bug - if ((arg = strtok(NULL, delim)) == NULL) { - missingarg = 1; - } else if (!strcmp(arg, "none")) { - cfg->fixfirmwarebug = FIX_NONE; - } else if (!strcmp(arg, "samsung")) { - cfg->fixfirmwarebug = FIX_SAMSUNG; - } else if (!strcmp(arg, "samsung2")) { - cfg->fixfirmwarebug = FIX_SAMSUNG2; - } else { - badarg = 1; - } - break; - case 'H': - // check SMART status - cfg->smartcheck=1; - break; - case 'f': - // check for failure of usage attributes - cfg->usagefailed=1; - break; - case 't': - // track changes in all vendor attributes - cfg->prefail=1; - cfg->usage=1; - break; - case 'p': - // track changes in prefail vendor attributes - cfg->prefail=1; - break; - case 'u': - // track changes in usage vendor attributes - cfg->usage=1; - 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=1; - } else if (!strcmp(arg, "error")) { - // track changes in ATA error log - cfg->errorlog=1; - } else { - badarg = 1; - } - break; - case 'a': - // monitor everything - cfg->smartcheck=1; - cfg->prefail=1; - cfg->usagefailed=1; - cfg->usage=1; - cfg->selftest=1; - cfg->errorlog=1; - 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 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; - 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->testdata){ - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n", - configfile, lineno, name, cfg->testdata->regex); - cfg->testdata=FreeTestData(cfg->testdata); - } - // check for missing argument - if (!(arg = strtok(NULL, delim))) { - missingarg = 1; - } - // allocate space for structure and string - else if (!(cfg->testdata=(testinfo *)Calloc(1, sizeof(testinfo))) || !(cfg->testdata->regex=CustomStrDup(arg, 1, __LINE__,filenameandversion))) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): no memory to create Test Directive -s %s!\n", - configfile, lineno, name, arg); - EXIT(EXIT_NOMEM); - } - else if ((val=regcomp(&(cfg->testdata->cregex), arg, REG_EXTENDED))) { - char errormsg[512]; - // not a valid regular expression! - regerror(val, &(cfg->testdata->cregex), errormsg, 512); - PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n", - configfile, lineno, name, arg, errormsg); - cfg->testdata=FreeTestData(cfg->testdata); - 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 ((int)strlen(arg) != (val=strspn(arg,"0123456789/.+*|()?^$[]SLCO"))) - 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 (mdat->address) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n", - configfile, lineno, name, mdat->address); - mdat->address=FreeNonZero(mdat->address, -1,__LINE__,filenameandversion); - } - mdat->address=CustomStrDup(arg, 1, __LINE__,filenameandversion); - } - break; - case 'M': - // email warning options - if (!(arg = strtok(NULL, delim))) - missingarg = 1; - else if (!strcmp(arg, "once")) - mdat->emailfreq = 1; - else if (!strcmp(arg, "daily")) - mdat->emailfreq = 2; - else if (!strcmp(arg, "diminishing")) - mdat->emailfreq = 3; - else if (!strcmp(arg, "test")) - mdat->emailtest = 1; - else if (!strcmp(arg, "exec")) { - // Get the next argument (the command line) - if (!(arg = strtok(NULL, delim))) { - 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 (mdat->emailcmdline) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n", - configfile, lineno, name, mdat->emailcmdline); - mdat->emailcmdline=FreeNonZero(mdat->emailcmdline, -1,__LINE__,filenameandversion); - } - mdat->emailcmdline=CustomStrDup(arg, 1, __LINE__,filenameandversion); - } - 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; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_FAILUSE, __LINE__); - break; - case 'I': - // ignore attribute for tracking purposes - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_IGNORE, __LINE__); - break; - case 'r': - // print raw value when tracking - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAWPRINT, __LINE__); - 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))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAWPRINT, __LINE__); - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAW, __LINE__); - break; - case 'v': - // non-default vendor-specific attribute meaning - if (!(arg=strtok(NULL,delim))) { - missingarg = 1; - } else if (parse_attribute_def(arg, &cfg->attributedefs)){ - 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; - 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; - } - - // If this did something to fill the mail structure, and that didn't - // already exist, create it and copy. - if (makemail) { - if (!(cfg->mailwarn=(maildata *)Calloc(1, sizeof(maildata)))) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): no memory to create mail warning entry!\n", - configfile, lineno, name); - EXIT(EXIT_NOMEM); - } - memcpy(cfg->mailwarn, mdat, sizeof(maildata)); - } - - return 1; -} - -// Allocate storage for a new cfgfile entry. If original!=NULL, it's -// a copy of the original, but with private data storage. Else all is -// zeroed. Returns address, and fails if non memory available. - -cfgfile *CreateConfigEntry(cfgfile *original){ - cfgfile *add; - - // allocate memory for new structure - if (!(add=(cfgfile *)Calloc(1,sizeof(cfgfile)))) - goto badexit; - - // if old structure was pointed to, copy it - if (original) - memcpy(add, original, sizeof(cfgfile)); - - // make private copies of data items ONLY if they are in use (non - // NULL) - add->name = CustomStrDup(add->name, 0, __LINE__,filenameandversion); - - if (add->testdata) { - int val; - if (!(add->testdata=(testinfo *)Calloc(1,sizeof(testinfo)))) - goto badexit; - memcpy(add->testdata, original->testdata, sizeof(testinfo)); - add->testdata->regex = CustomStrDup(add->testdata->regex, 1, __LINE__,filenameandversion); - // only POSIX-portable way to make fresh copy of compiled regex is - // to recompile it completely. There is no POSIX - // compiled-regex-copy command. - if ((val=regcomp(&(add->testdata->cregex), add->testdata->regex, REG_EXTENDED))) { - char errormsg[512]; - regerror(val, &(add->testdata->cregex), errormsg, 512); - PrintOut(LOG_CRIT, "unable to recompile regular expression %s. %s\n", add->testdata->regex, errormsg); - goto badexit; - } - } - - if (add->mailwarn) { - if (!(add->mailwarn=(maildata *)Calloc(1,sizeof(maildata)))) - goto badexit; - memcpy(add->mailwarn, original->mailwarn, sizeof(maildata)); - add->mailwarn->address = CustomStrDup(add->mailwarn->address, 0, __LINE__,filenameandversion); - add->mailwarn->emailcmdline = CustomStrDup(add->mailwarn->emailcmdline, 0, __LINE__,filenameandversion); - } - - if (add->attributedefs) { - if (!(add->attributedefs=(unsigned char *)Calloc(MAX_ATTRIBUTE_NUM,1))) - goto badexit; - memcpy(add->attributedefs, original->attributedefs, MAX_ATTRIBUTE_NUM); - } - - if (add->monitorattflags) { - if (!(add->monitorattflags=(unsigned char *)Calloc(NMONITOR*32, 1))) - goto badexit; - memcpy(add->monitorattflags, original->monitorattflags, NMONITOR*32); - } - - if (add->smartval) { - if (!(add->smartval=(struct ata_smart_values *)Calloc(1,sizeof(struct ata_smart_values)))) - goto badexit; - } - - if (add->smartthres) { - if (!(add->smartthres=(struct ata_smart_thresholds_pvt *)Calloc(1,sizeof(struct ata_smart_thresholds_pvt)))) - goto badexit; - } - - return add; - - badexit: - PrintOut(LOG_CRIT, "No memory to create entry from configuration file\n"); - EXIT(EXIT_NOMEM); -} - - - -// This is the routine that adds things to the cfgentries list. To -// prevent memory leaks when re-reading the configuration file many -// times, this routine MUST deallocate any memory other than that -// pointed to within cfg-> before it returns. -// -// Return values are: -// 1: parsed a normal line -// 0: found comment or blank line -// -1: found SCANDIRECTIVE line -// -2: found an error -// -// Note: this routine modifies *line from the caller! -int ParseConfigLine(int entry, int lineno,char *line){ - char *token=NULL; - char *name=NULL; - char *delim = " \n\t"; - cfgfile *cfg=NULL; - int devscan=0; - - // get first token: device name. If a comment, skip line - if (!(name=strtok(line,delim)) || *name=='#') { - return 0; - } - - // Have we detected the SCANDIRECTIVE directive? - if (!strcmp(SCANDIRECTIVE,name)){ - devscan=1; - if (entry) { - PrintOut(LOG_INFO,"Scan Directive %s (line %d) must be the first entry in %s\n",name, lineno, configfile); - return -2; - } - } - - // Is there space for another entry? If not, allocate more - while (entry>=cfgentries_max) - cfgentries=AllocateMoreSpace(cfgentries, &cfgentries_max, "configuration file device"); - - // We've got a legit entry, make space to store it - cfg=cfgentries[entry]=CreateConfigEntry(NULL); - cfg->name = CustomStrDup(name, 1, __LINE__,filenameandversion); - - // Store line number, and by default check for both device types. - cfg->lineno=lineno; - - // Try and recognize if a IDE or SCSI device. These can be - // overwritten by configuration file directives. - if (cfg->controller_type==CONTROLLER_UNKNOWN) - cfg->controller_type = guess_device_type(cfg->name); - - // parse tokens one at a time from the file. - while ((token=strtok(NULL,delim))){ - int retval=ParseToken(token,cfg); - - if (retval==0) - // No tokens left: - break; - - if (retval>0) { - // Parsed token -#if (0) - PrintOut(LOG_INFO,"Parsed token %s\n",token); -#endif - continue; - } - - if (retval<0) { - // error found on the line - return -2; - } - } - - // If we found 3ware controller, then modify device name by adding a SPACE - if (cfg->controller_port){ - int len=17+strlen(cfg->name); - char *newname; - - if (devscan){ - PrintOut(LOG_CRIT, "smartd: can not scan for 3ware devices (line %d of file %s)\n", - lineno, configfile); - return -2; - } - - if (!(newname=(char *)calloc(len,1))) { - PrintOut(LOG_INFO,"No memory to parse file: %s line %d, %s\n", configfile, lineno, strerror(errno)); - EXIT(EXIT_NOMEM); - } - - // Make new device name by adding a space then RAID disk number - snprintf(newname, len, "%s [3ware_disk_%02d]", cfg->name, cfg->controller_port-1); - cfg->name=CheckFree(cfg->name, __LINE__,filenameandversion); - cfg->name=newname; - bytes+=16; - } - - // If NO monitoring directives are set, then set all of them. - if (!(cfg->smartcheck || cfg->usagefailed || cfg->prefail || - cfg->usage || cfg->selftest || cfg->errorlog )){ - - PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n", - cfg->name, cfg->lineno, configfile); - - cfg->smartcheck=1; - cfg->usagefailed=1; - cfg->prefail=1; - cfg->usage=1; - cfg->selftest=1; - cfg->errorlog=1; - } - - // additional sanity check. Has user set -M options without -m? - if (cfg->mailwarn && !cfg->mailwarn->address && (cfg->mailwarn->emailcmdline || cfg->mailwarn->emailfreq || cfg->mailwarn->emailtest)){ - PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n", - cfg->name, cfg->lineno, configfile); - return -2; - } - - // has the user has set <nomailer>? - if (cfg->mailwarn && cfg->mailwarn->address && !strcmp(cfg->mailwarn->address,"<nomailer>")){ - // check that -M exec is also set - if (!cfg->mailwarn->emailcmdline){ - PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n", - cfg->name, cfg->lineno, configfile); - return -2; - } - // now free memory. From here on the sign of <nomailer> is - // address==NULL and cfg->emailcmdline!=NULL - cfg->mailwarn->address=FreeNonZero(cfg->mailwarn->address, -1,__LINE__,filenameandversion); - } - - // set cfg->emailfreq to 1 (once) if user hasn't set it - if (cfg->mailwarn && !cfg->mailwarn->emailfreq) - cfg->mailwarn->emailfreq = 1; - - entry++; - - if (devscan) - return -1; - else - return 1; -} - -// clean up utility for ParseConfigFile() -void cleanup(FILE **fpp, int is_stdin){ - if (*fpp){ - // (*fpp != stdin) does not work here if stdin has been closed & reopened - if (!is_stdin) - fclose(*fpp); - *fpp=NULL; - } - - return; -} - - -// 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 ==> cfgentries==NULL -// No configuration file ==> cfgentries[0]->lineno == 0 -// SCANDIRECTIVE found ==> cfgentries[0]->lineno != 0 -int ParseConfigFile(){ - FILE *fp=NULL; - int entry=0,lineno=1,cont=0,contlineno=0; - char line[MAXLINELEN+2]; - char fullline[MAXCONTLINE+1]; - - int is_stdin = (configfile == configfile_stdin); // pointer comparison ok here - - // Open config file, if it exists and is not <stdin> - if (!is_stdin) { - fp=fopen(configfile,"r"); - if (fp==NULL && (errno!=ENOENT || configfile_alt)) { - // 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) - fp = stdin; - - // No configuration file found -- use fake one - if (fp==NULL) { - int len=strlen(SCANDIRECTIVE)+4; - char *fakeconfig=(char *)calloc(len,1); - - if (!fakeconfig || - (len-1) != snprintf(fakeconfig, len, "%s -a", SCANDIRECTIVE) || - -1 != ParseConfigLine(entry, 0, fakeconfig) - ) { - PrintOut(LOG_CRIT,"Internal error in ParseConfigFile() at line %d of file %s\n%s", - __LINE__, filenameandversion, reportbug); - EXIT(EXIT_BADCODE); - } - fakeconfig=CheckFree(fakeconfig, __LINE__,filenameandversion); - return 0; - } - - // configuration file exists - PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile); - - // parse config file line by line - while (1) { - 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,fp); - - // are we at the end of the file? - if (!code){ - if (cont) { - scandevice=ParseConfigLine(entry,contlineno,fullline); - // See if we found a SCANDIRECTIVE directive - if (scandevice==-1) { - cleanup(&fp, is_stdin); - return 0; - } - // did we find a syntax error - if (scandevice==-2) { - cleanup(&fp, is_stdin); - 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){ - 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); - cleanup(&fp, is_stdin); - 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); - cleanup(&fp, is_stdin); - return -1; - } - - // copy string so far into fullline, and increment length - strcpy(fullline+cont,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(entry,contlineno,fullline); - - // did we find a scandevice directive? - if (scandevice==-1) { - cleanup(&fp, is_stdin); - return 0; - } - // did we find a syntax error - if (scandevice==-2) { - cleanup(&fp, is_stdin); - return -1; - } - - entry+=scandevice; - lineno++; - cont=0; - } - cleanup(&fp, is_stdin); - - // note -- may be zero if syntax of file OK, but no valid entries! - return entry; -} - - -// Prints copyright, license and version information -void PrintCopyleft(void){ - debugmode=1; - PrintHead(); - PrintCVS(); - return; -} - -/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> <=======\n", where - <LIST> is the list of valid arguments for option opt. */ -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, (char *)s); - PrintOut(LOG_CRIT, " <=======\n"); -} - -// Parses input line, prints usage message and -// version/license/copyright messages -void ParseOpts(int argc, char **argv){ - extern char *optarg; - extern int optopt, optind, opterr; - int optchar; - int badarg; - char *tailptr; - long lchecktime; - // Please update GetValidArgList() if you edit shortopts - const char *shortopts = "c:l:q:dDi:p:r:Vh?"; -#ifdef HAVE_GETOPT_LONG - char *arg; - // 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' }, - { "pidfile", required_argument, 0, 'p' }, - { "report", required_argument, 0, 'r' }, -#ifdef _WIN32 - { "service", no_argument, 0, 'S' }, -#endif - { "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' }, - { 0, 0, 0, 0 } - }; -#endif - - opterr=optopt=0; - badarg=FALSE; - - // Parse input options. This horrible construction is so that emacs - // indents properly. Sorry. - while (-1 != (optchar = -#ifdef HAVE_GETOPT_LONG - getopt_long(argc, argv, shortopts, longopts, NULL) -#else - getopt(argc, argv, shortopts) -#endif - )) { - - 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,"errors"))) { - quit=4; - } 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 = TRUE; - break; - case 'D': - // print summary of all valid directives - debugmode = TRUE; - 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")) { - con->reportataioctl = con->reportscsiioctl = i; - } else if (!strcmp(s,"ataioctl")) { - con->reportataioctl = i; - } else if (!strcmp(s,"scsiioctl")) { - con->reportscsiioctl = i; - } else { - badarg = TRUE; - } - s=CheckFree(s, __LINE__,filenameandversion); - } - break; - case 'c': - // alternate configuration file - if (strcmp(optarg,"-")) - configfile=configfile_alt=CustomStrDup(optarg, 1, __LINE__,filenameandversion); - else // read from stdin - configfile=configfile_stdin; - break; - case 'p': - // output file with PID number - pid_file=CustomStrDup(optarg, 1, __LINE__,filenameandversion); - break; -#ifdef _WIN32 - case 'S': - // running as service, option already handled by deamon_main(), so ignore it - break; -#endif - case 'V': - // print version and CVS info - PrintCopyleft(); - EXIT(0); - break; - case 'h': - // help: print summary of command-line options - debugmode=1; - PrintHead(); - Usage(); - EXIT(0); - break; - case '?': - default: - // unrecognized option - debugmode=1; - PrintHead(); -#ifdef HAVE_GETOPT_LONG - // 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); - } -#endif - 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) { - 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); - pid_file=FreeNonZero(pid_file, -1,__LINE__,filenameandversion); - EXIT(EXIT_BADCMD); - } - - // print header - PrintHead(); - - return; -} - -// Function we call if no configuration file was found or if the -// SCANDIRECTIVE Directive was found. It makes entries for device -// names returned by make_device_names() in os_OSNAME.c -int MakeConfigEntries(const char *type, int start){ - int i; - int num; - char** devlist = NULL; - cfgfile *first=cfgentries[0],*cfg=first; - - // make list of devices - if ((num=make_device_names(&devlist,type))<0) - PrintOut(LOG_CRIT,"Problem creating device name scan list\n"); - - // if no devices, or error constructing list, return - if (num<=0) - return 0; - - // loop over entries to create - for (i=0; i<num; i++){ - - // make storage and copy for all but first entry - if (start+i) { - // allocate more storage if needed - while (cfgentries_max<=start+i) - cfgentries=AllocateMoreSpace(cfgentries, &cfgentries_max, "simulated configuration file device"); - cfg=cfgentries[start+i]=CreateConfigEntry(first); - } - - // ATA or SCSI? - if (!strcmp(type,"ATA") ) - cfg->controller_type = CONTROLLER_ATA; - if (!strcmp(type,"SCSI") ) - cfg->controller_type = CONTROLLER_SCSI; - - // remove device name, if it's there, and put in correct one - cfg->name=FreeNonZero(cfg->name, -1,__LINE__,filenameandversion); - // save pointer to the device name created within - // make_device_names - cfg->name=devlist[i]; - } - - // If needed, free memory used for devlist: pointers now in - // cfgentries[]->names. If num==0 we never get to this point, but - // that's OK. If we realloc()d the array length in - // make_device_names() that was ALREADY equivalent to calling - // free(). - devlist = FreeNonZero(devlist,(sizeof (char*) * num),__LINE__, filenameandversion); - - return num; -} - -void CanNotRegister(char *name, char *type, int line, int scandirective){ - if( !debugmode && scandirective == 1 ) { 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. -// If we found no configuration file, or it contained SCANDIRECTIVE, -// then *scanning is set to 1, else 0. -int ReadOrMakeConfigEntries(int *scanning){ - int entries; - - // deallocate any cfgfile data structures in memory - RmAllConfigEntries(); - - // parse configuration file configfile (normally /etc/smartd.conf) - if ((entries=ParseConfigFile())<0) { - - // There was an error reading the configuration file. - RmAllConfigEntries(); - if (entries == -1) - PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile); - return entries; - } - - // did we find entries or scan? - *scanning=0; - - // 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 (cfgentries && cfgentries[0]) { - // we found a SCANDIRECTIVE or there was no configuration file so - // scan. Configuration file's first entry contains all options - // that were set - cfgfile *first=cfgentries[0]; - int doata = !(first->controller_type==CONTROLLER_SCSI); - int doscsi = !(first->controller_type==CONTROLLER_ATA); - - *scanning=1; - - 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 ATA devices to search for - if (doata) - entries+=MakeConfigEntries("ATA", entries); - // make config list of SCSI devices to search for - if (doscsi) - entries+=MakeConfigEntries("SCSI", entries); - - // warn user if scan table found no devices - if (!entries) { - PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n"); - // get rid of fake entry with SCANDIRECTIVE as name - RmConfigEntry(cfgentries, __LINE__); - } - } - else - PrintOut(LOG_CRIT,"Configuration file %s parsed but has no entries (like /dev/hda)\n",configfile); - - return entries; -} - - -// This function tries devices from cfgentries. Each one that can be -// registered is moved onto the [ata|scsi]devices lists and removed -// from the cfgentries list, else it's memory is deallocated. -void RegisterDevices(int scanning){ - int i; - - // start by clearing lists/memory of ALL existing devices - RmAllDevEntries(); - numdevata=numdevscsi=0; - - // Register entries - for (i=0; i<cfgentries_max ; i++){ - - cfgfile *ent=cfgentries[i]; - - // skip any NULL entries (holes) - if (!ent) - continue; - - // register ATA devices - if (ent->controller_type!=CONTROLLER_SCSI){ - if (ATADeviceScan(ent, scanning)) - CanNotRegister(ent->name, "ATA", ent->lineno, scanning); - else { - // move onto the list of ata devices - cfgentries[i]=NULL; - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); - atadevlist[numdevata++]=ent; - } - } - - // then register SCSI devices - if (ent->controller_type==CONTROLLER_SCSI || ent->controller_type==CONTROLLER_UNKNOWN){ - int retscsi=0; - -#if SCSITIMEOUT - struct sigaction alarmAction, defaultaction; - - // Set up an alarm handler to catch USB devices that hang on - // SCSI scanning... - alarmAction.sa_handler= AlarmHandler; - alarmAction.sa_flags = SA_RESTART; - if (sigaction(SIGALRM, &alarmAction, &defaultaction)) { - // if we can't set timeout, just scan device - PrintOut(LOG_CRIT, "Unable to initialize SCSI timeout mechanism.\n"); - retscsi=SCSIDeviceScan(ent, scanning); - } - else { - // prepare return point in case of bad SCSI device - if (setjmp(registerscsienv)) - // SCSI device timed out! - retscsi=-1; - else { - // Set alarm, make SCSI call, reset alarm - alarm(SCSITIMEOUT); - retscsi=SCSIDeviceScan(ent, scanning); - alarm(0); - } - if (sigaction(SIGALRM, &defaultaction, NULL)){ - PrintOut(LOG_CRIT, "Unable to clear SCSI timeout mechanism.\n"); - } - } -#else - retscsi=SCSIDeviceScan(ent, scanning); -#endif - - // Now scan SCSI device... - if (retscsi){ - if (retscsi<0) - PrintOut(LOG_CRIT, "Device %s timed out (poorly-implemented USB device?)\n", ent->name); - CanNotRegister(ent->name, "SCSI", ent->lineno, scanning); - } - else { - // move onto the list of scsi devices - cfgentries[i]=NULL; - while (numdevscsi>=scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); - scsidevlist[numdevscsi++]=ent; - } - } - - // if device is explictly listed and we can't register it, then - // exit unless the user has specified that the device is removable - if (cfgentries[i] && !scanning){ - if (ent->removable || quit==2) - PrintOut(LOG_INFO, "Device %s not available\n", ent->name); - else { - PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n", ent->name); - EXIT(EXIT_BADDEV); - } - } - - // free up memory if device could not be registered - RmConfigEntry(cfgentries+i, __LINE__); - } - - return; -} - - -#ifndef _WIN32 -// Main function -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 -{ - // external control variables for ATA disks - smartmonctrl control; - - // is it our first pass through? - int firstpass=1; - - // next time to wake up - time_t wakeuptime; - - // for simplicity, null all global communications variables/lists - con=&control; - memset(con, 0,sizeof(control)); - - // parse input and print header and usage info if needed - ParseOpts(argc,argv); - - // do we mute printing from ataprint commands? - con->printing_switchable=0; - con->dont_print=debugmode?0:1; - - // don't exit on bad checksums - con->checksumfail=0; - - // the main loop of the code - while (1){ - - // 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)); - - EXIT(isok?0:EXIT_SIGNAL); - } - - // Should we (re)read the config file? - if (firstpass || caughtsigHUP){ - int entries, scanning=0; - - if (!firstpass) { -#ifdef __CYGWIN__ - // Workaround for missing SIGQUIT via keyboard on Cygwin - if (caughtsigHUP==2) { - // Simulate SIGQUIT if another SIGINT arrives soon - caughtsigHUP=0; - sleep(1); - if (caughtsigHUP==2) { - caughtsigEXIT=SIGQUIT; - continue; - } - caughtsigHUP=2; - } -#endif - 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); - } - - // clears cfgentries, (re)reads config file, makes >=0 entries - entries=ReadOrMakeConfigEntries(&scanning); - - if (entries>=0) { - // checks devices, then moves onto ata/scsi list or deallocates. - RegisterDevices(scanning); - } - 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 - int status = (entries==-3 ? EXIT_READCONF : entries==-2 ? EXIT_NOCONF : EXIT_BADCONF); - EXIT(status); - } - - // Log number of devices we are monitoring... - if (numdevata+numdevscsi || quit==2 || (quit==1 && !firstpass)) - PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n", - numdevata, numdevscsi); - else { - PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n"); - EXIT(EXIT_NODEV); - } - - // reset signal - caughtsigHUP=0; - } - - // check all devices once - CheckDevicesOnce(atadevlist, scsidevlist); - - // 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"); - EXIT(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=0; - } - - // sleep until next check time, or a signal arrives - wakeuptime=dosleep(wakeuptime); - } -} - - -#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 diff --git a/sm5/smartd.conf b/sm5/smartd.conf deleted file mode 100644 index 6e450eeba816bfb5ebcded53f170a0eaf799540e..0000000000000000000000000000000000000000 --- a/sm5/smartd.conf +++ /dev/null @@ -1,92 +0,0 @@ -# Sample configuration file for smartd. See man smartd.conf. - -# Home page is: http://smartmontools.sourceforge.net - -# $Id: smartd.conf,v 1.37 2004/08/04 05:32:44 ballen4705 Exp $ - -# 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 - -# First (primary) ATA/IDE hard disk. Monitor all attributes, enable -# automatic online data collection, automatic Attribute autosave, and -# do a short self-test every day at 2am, and a long self test -# Saturdays at 3am. -#/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 - -# A very silent check. Only report SMART health status if it fails -# But send an email in this case -#/dev/hdc -H -m admin@example.com - -# First two SCSI disks. This will monitor everything that smartd can -# monitor. Do extended self-tests Wednesdays at 6pm and Sundays at 1 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. Do a long self-tests Sundays at 1, 2, 3, and 4 am -# Note: one can also use the /dev/twe0 character device interface. -#/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. Do a long self-tests Tuesdays at 1 and 3 am -#/dev/twa0 -d 3ware,0 -a -s L/../../2/01 -#/dev/twa0 -d 3ware,1 -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, removable, 3ware,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 Do 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 -# -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. diff --git a/sm5/smartd.conf.5.in b/sm5/smartd.conf.5.in deleted file mode 100644 index a7c59397c185bb43cdd3584765aa9a858913f97e..0000000000000000000000000000000000000000 --- a/sm5/smartd.conf.5.in +++ /dev/null @@ -1,1209 +0,0 @@ -.ig -Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> - -$Id: smartd.conf.5.in,v 1.58 2004/08/08 14:32:07 ballen4705 Exp $ - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the Free -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., 675 -Mass Ave, Cambridge, MA 02139, 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/ -.. -.TH SMARTD.CONF 5 CURRENT_CVS_DATE CURRENT_CVS_VERSION CURRENT_CVS_DATE -.SH NAME -\fBsmartd.conf\fP \- SMART Disk Monitoring Daemon Configuration File\fP - -.SH FULL PATH -.B /etc/smartd.conf - -.SH PACKAGE VERSION -CURRENT_CVS_VERSION released CURRENT_CVS_DATE at CURRENT_CVS_TIME - -.SH DESCRIPTION -\fB/etc/smartd.conf\fP is the configuration file for the \fBsmartd\fP -daemon, which monitors the Self-Monitoring, Analysis and Reporting -Technology (SMART) system built into many ATA-3 and later ATA, IDE and -SCSI-3 hard drives. - -If the configuration file \fB/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. - -.\" DO NOT MODIFY THIS OR THE FOLLOWING TWO LINES. WHAT FOLLOWS -.\" IS AUTOMATICALLY INCLUDED FROM THE FILE smartd.8.in -.\" STARTINCLUDE - -.SH CONFIGURATION FILE /etc/smartd.conf -In the absence of a configuration file, -\fBsmartd\fP -will try to open the 20 ATA devices -.B /dev/hd[a-t] -and the 26 SCSI devices -.B /dev/sd[a-z] -under Linux. Under FreeBSD, -\fBsmartd\fP -will try to open all existing ATA devices (with entries in /dev) -.B /dev/ad[0-9]+ -and all existing SCSI devices -.B /dev/da[0-9]+. -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 -block-major devices that can\'t be found, and SCSI 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 /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/share/doc/smartmontools-5.1/\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 -.B # file /etc/smartd.conf for monitoring three ATA -.B # disks, three SCSI disks, and six ATA disks -.B # behind two 3ware controllers. -.B # -.nf -.B # First ATA disk on each of two interfaces. On -.B # the second disk, do a long self-test every -.B # Sunday at 3am. -.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. Do a scheduled -.B # long self test at 5am Monday/Thursday -.B \ \ /dev/weird -d scsi -s L/../../(1|4)/05 -.B # -.nf -.B # Four ATA disks on a 3ware 6/7/8000 controller. -.B # Do short self-tests daily at midnight, 1, 2, and 3 am -.B # (Note that the syntax /dev/twe0 is also allowed.) -.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 # Do long self-tests Sundays at midnight and 2 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 # 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 the first 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. - -.sp 2 -The following are the Directives that may appear following the device -name or -.B DEVICESCAN -on any line of the -.B /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? -or /dev/twa?) 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). - -.TP -.B \-d TYPE -Specifies the type of the device. This Directive may be used multiple times -for one device, but the arguments \fIata\fP, \fIscsi\fP, and \fI3ware,N\fP are -mutually-exclusive. If more than one is given then -\fBsmartd\fP -will use the last one which appears. - -If none of these three arguments is given, then \fBsmartd\fP will -first attempt to guess the device type by looking at whether the sixth -character in the device name is an \'s\' or an \'h\'. This will work for -device names like /dev/hda or /dev/sdb, and corresponds to choosing -\fIata\fP or \fIscsi\fP respectively. If -\fBsmartd\fP -can\'t guess from this sixth character, then it will simply try to -access the device using first ATA and then SCSI ioctl()s. - -The valid arguments to this Directive are: - -.I ata -\- the device type is ATA. This prevents -\fBsmartd\fP -from issuing SCSI commands to an ATA device. - -.I scsi -\- the device type is SCSI. This prevents -\fBsmartd\fP -from issuing ATA commands to a SCSI device. - -.I 3ware,N -\- 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 15 -inclusive) denotes which disk on the controller is monitored. In log -files and email messages this disk will be identified as 3ware_disk_XX -with XX in the range from 00 to 15 inclusive. - -This Directive may at first appear confusing, because the 3ware -controller is a SCSI device (such as /dev/sda) and should be listed as -such in the the configuration file. -However when the \'\-d 3ware,N\' -Directive is used, then the corresponding disk is addressed using -native ATA commands which are \'passed through\' the SCSI driver. All -ATA Directives listed in this man page may be used. Note that while -you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? 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 man page for further details. - -ATA disks behind 3ware controllers may alternatively be accessed via a -character device interface /dev/twe0-15 (3ware 6000/7000/8000 -controllers) and /dev/twa0-15 (3ware 9000 series controllers). Note -that the 9000 series controllers may \fBonly\fP be accessed using the -character device interface /dev/twa0-15 and not the SCSI device -interface /dev/sd?. Please see the \fBsmartctl\fP man page for -further details. - -Note that 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, if the SCSI interface is used, and produce these types of -harmless syslog error messages instead: \fB\'3w-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. See -\fBhttp://smartmontools.sourceforge.net/\fP for instructions. -Alternatively use the character device interfaces /dev/twe0-15 (3ware -6/7/8000 series controllers) or /dev/twa0-15 (3ware 9000 series -controllers). - - -.B 3ware controllers are currently ONLY supported under Linux. - -.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 -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. - - -.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. This may also be -needed for some Maxtor disks which fail to comply with the ATA -Specifications and don't properly indicate support for error\- or -self\-test logging. - -[Please see the \fBsmartctl \-T\fP command-line option.] -.TP -.B \-o VALUE -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 -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_CRITICAL\' -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 the two SMART logs. The -valid arguments to this Directive are: - -.I error -\- report if the number of ATA errors reported in the ATA Error Log -has increased since the last check. - -.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.] -.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. -.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 - -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, and so the -self tests may not take place as you wish. - -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. - -Each time a test is run, \fBsmartd\fP will log an entry to SYSLOG. -You can use these 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. - -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. - -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. - -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. - -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. - -The following extension is available on Windows: -By specifying \'\fBmsgbox\fP\' as a mail address, a warning -"email" is displayed as a message box on the screen. -Using both \'\fBmsgbox\fP\' and regular mail addresses is possible, -if \'\fBmsgbox\fP\' is the first word in the comma separated list. -With \'\fBsysmsgbox\fP\', a system modal (always on top) message box -is used. If running as a service, a service notification message box -(always shown on current visible desktop) is used. - -.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 conflicting \-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: - -.I once -\- send only one warning email for each type of disk problem detected. This -is the default. - -.I daily -\- send additional warning reminder emails, once per day, for each type -of disk problem detected. - -.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. - -.I test -\- send a single test email -immediately upon -\fBsmartd\fP -startup. This allows one to verify that email is delivered correctly. - -.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. - -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. Some sample -scripts are included in -/usr/share/doc/smartmontools-5.1/examplescripts/. - -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 (possible values: ata, scsi, 3ware,N). Here -N=0,...,15 denotes the ATA disk behind a 3ware RAID controller. -.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]\'. In this case 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_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 -\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. -.IP \fBSMARTD_MESSAGE\fP 4 -is set to the 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. -.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. -.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 - -Note that on Windows, the syntax of the \'\fBBlat\fP\' mailer is -used: -.nf -- -q -subject "$SMARTD_SUBJECT" -to "$SMARTD_ADDRESS" -.fi - -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. Some sample scripts are also included in -/usr/share/doc/smartmontools-5.1/examplescripts/. - -.TP -.B \-f -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 -Report anytime that a Prefail Attribute has changed -its value since the last check, 30 minutes ago. [Please see the -.B smartctl \-A -command-line option.] -.TP -.B \-u -Report anytime that a Usage Attribute has changed its value -since the last check, 30 minutes ago. [Please see the -.B smartctl \-A -command-line option.] -.TP -.B \-t -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 -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 -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 -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). - -.TP -.B \-R ID -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. - -.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). - -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). - - -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 \-F TYPE -[ATA only] Modifies the behavior of \fBsmartd\fP to compensate for -some known and understood device firmware bug. The arguments to this -Directive are exclusive, so that only the final Directive given is -used. The valid values 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 device -database. - -.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 more recent Samsung disks (firmware revisions ending in "\-23") the -number of ATA errors reported is byte swapped. Enabling this option -tells \fBsmartd\fP to evaluate this quantity in byte-reversed order. - -Note that an explicit \'\-F\' Directive will over-ride any preset -values for \'\-F\' (see the \'\-P\' option below). - - -[Please see the \fBsmartctl \-F\fP command-line option.] - -.TP -.B \-v N,OPTION -Modifies the labeling for Attribute N, for disks which use -non-standard Attribute definitions. This is useful in connection with -the Attribute tracking/reporting Directives. - -This Directive may appear multiple times. Valid arguments to this -Directive are: - -.I 9,minutes -\- Raw Attribute number 9 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 9,seconds -\- Raw Attribute number 9 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 9,halfminutes -\- Raw Attribute number 9 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 9,temp -\- Raw Attribute number 9 is the disk temperature in Celsius. - -.I 192,emergencyretractcyclect -\- Raw Attribute number 192 is the Emergency Retract Cycle Count. - -.I 193,loadunload -\- Raw Attribute number 193 contains two 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 194,10xCelsius -\- Raw Attribute number 194 is ten times the disk temperature in -Celsius. This is used by some Samsung disks (example: model SV1204H -with RK100-13 firmware). - -.I 194,unknown -\- Raw Attribute number 194 is NOT the disk temperature, and its -interpretation is unknown. This is primarily useful for the -P -(presets) Directive. - -.I 198,offlinescanuncsectorct -\- Raw Attribute number 198 is the Offline Scan UNC Sector Count. - -.I 200,writeerrorcount -\- Raw Attribute number 200 is the Write Error Count. - -.I 201,detectedtacount -\- Raw Attribute number 201 is the Detected TA Count. - -.I 220,temp -\- Raw Attribute number 220 is the disk temperature in Celsius. - -Note: a table of hard drive models, listing which Attribute -corresponds to temperature, can be found at: -http://coredump.free.fr/linux/hddtemp.db - -.I N,raw8 -\- Print the Raw value of Attribute N as six 8-bit unsigned base-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw8\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw8\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw16 -\- Print the Raw value of Attribute N as three 16-bit unsigned base-10 -integers. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw16\' prints Raw values for ALL Attributes in this -form. The form (for example) \'123,raw16\' only prints the Raw value for -Attribute 123 in this form. - -.I N,raw48 -\- Print the Raw value of Attribute N as a 48-bit unsigned base-10 -integer. This may be useful for decoding the meaning of the Raw -value. The form \'N,raw48\' prints Raw values for ALL Attributes in -this form. The form (for example) \'123,raw48\' only prints the Raw -value for Attribute 123 in this form. - -.TP -.B \-P TYPE -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\ selftest\' -to report increases in the number of Self-Test Log errors, -.B \'\-l\ error\' -to report increases in the number of ATA errors, -.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 the first 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. - -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). - -.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/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/share/doc/smartmontools-5.1/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. - -.\" ENDINCLUDE -.\" DO NOT MODIFY THIS OR PREVIOUS/NEXT LINES. THIS DEFINES THE -.\" END OF THE INCLUDED SECTION FROM smartd.8.in - -.PP -.SH AUTHOR -\fBBruce Allen\fP smartmontools-support@lists.sourceforge.net -.fi -University of Wisconsin \- Milwaukee Physics Department - -.PP -.SH CONTRIBUTORS -The following have made large contributions to smartmontools: -.nf -\fBCasper Dik\fP (Solaris SCSI interface) -\fBChristian Franke\fP (Windows interface) -\fBDouglas Gilbert\fP (SCSI subsystem) -\fBGuido Guenther\fP (Autoconf/Automake packaging) -\fBEduard Martinescu\fP (FreeBSD interface) -\fBFr\*'ed\*'eric L. W. Meunier\fP (Web site and Mailing list) -\fBKeiji Sawada\fP (Solaris ATA interface) -\fBSergey Svishchev\fP (NetBSD interface) -\fBPhil Williams\fP (User interface and drive database) -.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: -.nf -.B -http://smartmontools.sourceforge.net/ - -.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 -CVS ID OF THIS PAGE: -$Id: smartd.conf.5.in,v 1.58 2004/08/08 14:32:07 ballen4705 Exp $ diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp deleted file mode 100644 index c2b77c91594e3eba287d6b51885bc06812d8070c..0000000000000000000000000000000000000000 --- a/sm5/smartd.cpp +++ /dev/null @@ -1,3940 +0,0 @@ -/* - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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/ - * - */ - -// unconditionally included files -#define _GNU_SOURCE -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> // umask -#ifndef _WIN32 -#include <sys/wait.h> -#include <unistd.h> -#endif -#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> - -#if SCSITIMEOUT -#include <setjmp.h> -#endif - -// see which system files to conditionally include -#include "config.h" - -// conditionally included files -#ifdef HAVE_GETOPT_LONG -#include <getopt.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 - -// locally included files -#include "atacmds.h" -#include "ataprint.h" -#include "extern.h" -#include "int64.h" -#include "knowndrives.h" -#include "scsicmds.h" -#include "smartd.h" -#include "utility.h" - -#ifdef _WIN32 -#include "hostname_win32.h" // gethost/domainname() -#define HAVE_GETHOSTNAME 1 -#define HAVE_GETDOMAINNAME 1 -// 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 -#undef EXIT // see utility.h -#define EXIT(x) { exitstatus = daemon_winsvc_exitcode = (x); exit((x)); } -// SIGQUIT does not exits, CONTROL-Break signals SIGBREAK. -#define SIGQUIT SIGBREAK -#define SIGQUIT_KEYNAME "CONTROL-Break" -#else // _WIN32 -#ifdef __CYGWIN__ -// 2x CONTROL-C simulates missing SIGQUIT via keyboard -#define SIGQUIT_KEYNAME "2x CONTROL-C" -#else // __CYGWIN__ -#define SIGQUIT_KEYNAME "CONTROL-\\" -#endif // __CYGWIN__ -#endif // _WIN32 - -#if defined (__SVR4) && defined (__sun) -int getdomainname(char *, int); /* no declaration in header files! */ -#endif - -#define ARGUSED(x) ((void)(x)) - -// These are CVS identification information for *.c and *.h files -extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, - *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; - -static const char *filenameandversion="$Id: smartd.cpp,v 1.333 2004/08/16 22:44:27 ballen4705 Exp $"; -#ifdef NEED_SOLARIS_ATA_CODE -extern const char *os_solaris_ata_s_cvsid; -#endif -#ifdef _WIN32 -extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid; -#ifdef _MSC_VER -extern const char *int64_vc6_c_cvsid; -#endif -#endif -const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.333 2004/08/16 22:44:27 ballen4705 Exp $" -ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID -#ifdef DAEMON_WIN32_H_CVSID -DAEMON_WIN32_H_CVSID -#endif -EXTERN_H_CVSID INT64_H_CVSID -#ifdef HOSTNAME_WIN32_H_CVSID -HOSTNAME_WIN32_H_CVSID -#endif -KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID -#ifdef SYSLOG_H_CVSID -SYSLOG_H_CVSID -#endif -UTILITY_H_CVSID; - -extern const char *reportbug; - -// GNU copyleft statement. Needed for GPL purposes. -const char *copyleftstring="smartd comes with ABSOLUTELY NO WARRANTY. This is\n" - "free software, and you are welcome to redistribute it\n" - "under the terms of the GNU General Public License\n" - "Version 2. See http://www.gnu.org for further details.\n\n"; - -extern unsigned char debugmode; - -// command-line: how long to sleep between checks -static int checktime=CHECKTIME; - -// command-line: name of PID file (NULL for no pid file) -static char* pid_file=NULL; - -// configuration file name -#ifndef _WIN32 -static char* configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ; -#else -static char* configfile = "./" CONFIGFILENAME ; -#endif -// configuration file "name" if read from stdin -static /*const*/ char * const configfile_stdin = "<stdin>"; -// allocated memory for alternate configuration file name -static char* configfile_alt = NULL; - -// 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; - -// used for control of printing, passing arguments to atacmds.c -smartmonctrl *con=NULL; - -// pointers to (real or simulated) entries in configuration file, and -// maximum space currently allocated for these entries. -cfgfile **cfgentries=NULL; -int cfgentries_max=0; - -// pointers to ATA and SCSI devices being monitored, maximum and -// actual numbers -cfgfile **atadevlist=NULL, **scsidevlist=NULL; -int atadevlist_max=0, scsidevlist_max=0; -int numdevata=0, numdevscsi=0; - -// track memory usage -extern int64_t bytes; - -// exit status -extern int exitstatus; - -// set to one if we catch a USR1 (check devices now) -volatile int caughtsigUSR1=0; - -#ifdef _WIN32 -// set to one if we catch a USR2 (toggle debug mode) -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). -volatile int caughtsigHUP=0; - -// set to signal value if we catch INT, QUIT, or TERM -volatile int caughtsigEXIT=0; - -#if SCSITIMEOUT -// stack environment if we time out during SCSI access (USB devices) -jmp_buf registerscsienv; -#endif - -// tranlate cfg->pending into the correct Attribute numbers -void TranslatePending(unsigned short pending, unsigned char *current, unsigned char *offline) { - - unsigned char curr = CURR_PEND(pending); - unsigned char off = OFF_PEND(pending); - - // look for special value of CUR_UNC_DEFAULT that means DONT - // monitor. 0 means DO test. - if (curr==CUR_UNC_DEFAULT) - curr=0; - else if (curr==0) - curr=CUR_UNC_DEFAULT; - - // look for special value of OFF_UNC_DEFAULT that means DONT - // monitor. 0 means DO TEST. - if (off==OFF_UNC_DEFAULT) - off=0; - else if (off==0) - off=OFF_UNC_DEFAULT; - - *current=curr; - *offline=off; - - return; -} - - -// free all memory associated with selftest part of configfile entry. Return NULL -testinfo* FreeTestData(testinfo *data){ - - // make sure we have something to do. - if (!data) - return NULL; - - // free space for text pattern - data->regex=FreeNonZero(data->regex, -1, __LINE__, filenameandversion); - - // free compiled expression - regfree(&(data->cregex)); - - // make sure that no sign of the compiled expression is left behind - // (just in case, to help detect bugs if we ever try and refer to - // that again). - memset(&(data->cregex), '0', sizeof(regex_t)); - - // free remaining memory space - data=FreeNonZero(data, sizeof(testinfo), __LINE__, filenameandversion); - - return NULL; -} - -cfgfile **AllocateMoreSpace(cfgfile **oldarray, int *oldsize, char *listname){ - // for now keep BLOCKSIZE small to help detect coding problems. - // Perhaps increase in the future. - const int BLOCKSIZE=8; - int i; - int old = *oldsize; - int new = old + BLOCKSIZE; - cfgfile **newptr=realloc(oldarray, new*sizeof(cfgfile *)); - - // did we get more space? - if (newptr) { - - // clear remaining entries ala calloc() - for (i=old; i<new; i++) - newptr[i]=NULL; - - bytes += BLOCKSIZE*sizeof(cfgfile *); - - *oldsize=new; - -#if 0 - PrintOut(LOG_INFO, "allocating %d slots for %s\n", BLOCKSIZE, listname); -#endif - - return newptr; - } - - PrintOut(LOG_CRIT, "out of memory for allocating %s list\n", listname); - EXIT(EXIT_NOMEM); -} - -void PrintOneCVS(const char *a_cvs_id){ - char out[CVSMAXLEN]; - printone(out,a_cvs_id); - PrintOut(LOG_INFO,"%s",out); - return; -} - -// prints CVS identity information for the executable -void PrintCVS(void){ - char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; - - PrintOut(LOG_INFO,(char *)copyleftstring); - PrintOut(LOG_INFO,"CVS version IDs of files used to build this code are:\n"); - PrintOneCVS(atacmdnames_c_cvsid); - PrintOneCVS(atacmds_c_cvsid); - PrintOneCVS(ataprint_c_cvsid); -#ifdef _WIN32 - PrintOneCVS(daemon_win32_c_cvsid); -#endif -#if defined(_WIN32) && defined(_MSC_VER) - PrintOneCVS(int64_vc6_c_cvsid); -#endif -#ifdef _WIN32 - PrintOneCVS(hostname_win32_c_cvsid); -#endif - PrintOneCVS(knowndrives_c_cvsid); - PrintOneCVS(os_XXXX_c_cvsid); -#ifdef NEED_SOLARIS_ATA_CODE - PrintOneCVS( os_solaris_ata_s_cvsid); -#endif - PrintOneCVS(scsicmds_c_cvsid); - PrintOneCVS(smartd_c_cvsid); -#ifdef _WIN32 - PrintOneCVS(syslog_win32_c_cvsid); -#endif - PrintOneCVS(utility_c_cvsid); - PrintOut(LOG_INFO, "\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); - PrintOut(LOG_INFO, "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); - PrintOut(LOG_INFO, "smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); - PrintOut(LOG_INFO, "smartd compile dated " __DATE__ " at "__TIME__ "\n"); - PrintOut(LOG_INFO, "smartmontools configure arguments: %s\n", configargs); - return; -} - -// Removes config file entry, freeing all memory -void RmConfigEntry(cfgfile **anentry, int whatline){ - - cfgfile *cfg; - - // pointer should never be null! - if (!anentry){ - PrintOut(LOG_CRIT,"Internal error in RmConfigEntry() at line %d of file %s\n%s", - whatline, filenameandversion, reportbug); - EXIT(EXIT_BADCODE); - } - - // only remove entries that exist! - if (!(cfg=*anentry)) - return; - - // entry exists -- free all of its memory - cfg->name = FreeNonZero(cfg->name, -1,__LINE__,filenameandversion); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); - if (cfg->mailwarn){ - cfg->mailwarn->address = FreeNonZero(cfg->mailwarn->address, -1,__LINE__,filenameandversion); - cfg->mailwarn->emailcmdline = FreeNonZero(cfg->mailwarn->emailcmdline, -1,__LINE__,filenameandversion); - cfg->mailwarn = FreeNonZero(cfg->mailwarn, sizeof(maildata),__LINE__,filenameandversion); - } - cfg->testdata = FreeTestData(cfg->testdata); - *anentry = FreeNonZero(cfg, sizeof(cfgfile),__LINE__,filenameandversion); - - return; -} - -// deallocates all memory associated with cfgentries list -void RmAllConfigEntries(){ - int i; - - for (i=0; i<cfgentries_max; i++) - RmConfigEntry(cfgentries+i, __LINE__); - - cfgentries=FreeNonZero(cfgentries, sizeof(cfgfile *)*cfgentries_max, __LINE__, filenameandversion); - cfgentries_max=0; - - return; -} - -// deallocates all memory associated with ATA/SCSI device lists -void RmAllDevEntries(){ - int i; - - for (i=0; i<atadevlist_max; i++) - RmConfigEntry(atadevlist+i, __LINE__); - - atadevlist=FreeNonZero(atadevlist, sizeof(cfgfile *)*atadevlist_max, __LINE__, filenameandversion); - atadevlist_max=0; - - for (i=0; i<scsidevlist_max; i++) - RmConfigEntry(scsidevlist+i, __LINE__); - - scsidevlist=FreeNonZero(scsidevlist, sizeof(cfgfile *)*scsidevlist_max, __LINE__, filenameandversion); - scsidevlist_max=0; - - return; -} - -// remove the PID file -void RemovePidFile(){ - if (pid_file) { - if ( -1==unlink(pid_file) ) - PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n", - pid_file, strerror(errno)); - pid_file=FreeNonZero(pid_file, -1,__LINE__,filenameandversion); - } - return; -} - - -// Note if we catch a SIGUSR1 -void USR1handler(int sig){ - if (SIGUSR1==sig) - caughtsigUSR1=1; - return; -} - -#ifdef _WIN32 -// Note if we catch a SIGUSR2 -void USR2handler(int sig){ - if (SIGUSR2==sig) - caughtsigUSR2=1; - return; -} -#endif - -// Note if we catch a HUP (or INT in debug mode) -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) -void sighandler(int sig){ - if (!caughtsigEXIT) - caughtsigEXIT=sig; - return; -} - - -// signal handler that prints Goodbye message and removes pidfile -void Goodbye(void){ - - // clean up memory -- useful for debugging - RmAllConfigEntries(); - RmAllDevEntries(); - - // delete PID file, if one was created - RemovePidFile(); - - // remove alternate configfile name - configfile_alt=FreeNonZero(configfile_alt, -1,__LINE__,filenameandversion); - - // useful for debugging -- have we managed memory correctly? - if (debugmode || (bytes && exitstatus!=EXIT_NOMEM)) - PrintOut(LOG_INFO, "Memory still allocated for devices at exit is %" PRId64 " bytes.\n", bytes); - - // if we are exiting because of a code bug, tell user - if (exitstatus==EXIT_BADCODE || (bytes && exitstatus!=EXIT_NOMEM)) - PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n"); - - if (exitstatus==0 && bytes) - exitstatus=EXIT_BADCODE; - - // and this should be the final output from smartd before it exits - PrintOut(exitstatus?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", exitstatus); - - return; -} - -#define ENVLENGTH 512 - -// 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 or -// deleted via another call to putenv(). So we keep these on the stack -// as long as the popen() call is underway. -int exportenv(char* stackspace, const char *name, const char *value){ - snprintf(stackspace,ENVLENGTH, "%s=%s", name, value); - return putenv(stackspace); -} - -char* dnsdomain(const char* hostname) { - char *p = NULL; -#ifdef HAVE_GETHOSTBYNAME - struct hostent *hp; - - if ((hp = gethostbyname(hostname))) { - // Does this work if gethostbyname() returns an IPv6 name in - // colon/dot notation? [BA] - if ((p = strchr(hp->h_name, '.'))) - p++; // skip "." - } -#else - ARGUSED(hostname); -#endif - return p; -} - -#define EBUFLEN 1024 - -// If either address or executable path is non-null then send and log -// a warning email, or execute executable -void MailWarning(cfgfile *cfg, int which, char *fmt, ...){ - char command[2048], message[256], hostname[256], domainname[256], additional[256]; - char original[256], further[256], nisdomain[256], subject[256],dates[DATEANDEPOCHLEN]; - char environ_strings[10][ENVLENGTH]; - time_t epoch; - va_list ap; - const int day=24*3600; - int days=0; - char *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 - }; - - char *address, *executable; - mailinfo *mail; - maildata* data=cfg->mailwarn; -#ifndef _WIN32 - FILE *pfp=NULL; -#else - char stdinbuf[1024]; int boxmsgoffs, boxtype; -#endif - char *newadd=NULL, *newwarn=NULL; - const char *unknown="[Unknown]"; - - // See if user wants us to send mail - if (!data) - return; - - address=data->address; - executable=data->emailcmdline; - - if (!address && !executable) - return; - - // which type of mail are we sending? - mail=(data->maillog)+which; - - // checks for sanity - if (data->emailfreq<1 || data->emailfreq>3) { - PrintOut(LOG_CRIT,"internal error in MailWarning(): cfg->mailwarn->emailfreq=%d\n",data->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 ((data->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. - epoch=time(NULL); - - // Return if less than one day has gone by - if (data->emailfreq==2 && mail->logged && epoch<(mail->lastsent+day)) - return; - - // Return if less than 2^(logged-1) days have gone by - if (data->emailfreq==3 && mail->logged){ - days=0x01<<(mail->logged-1); - days*=day; - if (epoch<(mail->lastsent+days)) - return; - } - - // record the time of this mail message, and the first mail message - if (!mail->logged) - mail->firstsent=epoch; - mail->lastsent=epoch; - - // get system host & domain names (not null terminated if length=MAX) -#ifdef HAVE_GETHOSTNAME - if (gethostname(hostname, 256)) - strcpy(hostname, unknown); - else { - char *p=NULL; - hostname[255]='\0'; - p = dnsdomain(hostname); - if (p && *p) { - strncpy(domainname, p, 255); - domainname[255]='\0'; - } else - strcpy(domainname, unknown); - } -#else - strcpy(hostname, unknown); - strcpy(domainname, unknown); -#endif - -#ifdef HAVE_GETDOMAINNAME - if (getdomainname(nisdomain, 256)) - strcpy(nisdomain, unknown); - else - nisdomain[255]='\0'; -#else - strcpy(nisdomain, unknown); -#endif - - // print warning string into message - va_start(ap, fmt); - vsnprintf(message, 256, fmt, ap); - va_end(ap); - - // appropriate message about further information - additional[0]=original[0]=further[0]='\0'; - if (which) { - sprintf(further,"You can also use the smartctl utility for further investigation.\n"); - - switch (data->emailfreq){ - case 1: - sprintf(additional,"No additional email messages about this problem will be sent.\n"); - break; - case 2: - sprintf(additional,"Another email message will be sent in 24 hours if the problem persists.\n"); - break; - case 3: - sprintf(additional,"Another email message will be sent in %d days if the problem persists\n", - (0x01)<<mail->logged); - break; - } - if (data->emailfreq>1 && mail->logged){ - dateandtimezoneepoch(dates, mail->firstsent); - sprintf(original,"The original email about this issue was sent at %s\n", dates); - } - } - - snprintf(subject, 256,"SMART error (%s) detected on host: %s", whichfail[which], hostname); - - // If the user has set cfg->emailcmdline, use that as mailer, else "mail" or "mailx". - if (!executable) -#ifdef DEFAULT_MAILER - executable = DEFAULT_MAILER ; -#else -#ifndef _WIN32 - executable = "mail"; -#else - executable = "blat"; // http://blat.sourceforge.net/ -#endif -#endif - - // make a private copy of address with commas replaced by spaces - // to separate recipients - if (address) { - address=CustomStrDup(data->address, 1, __LINE__, filenameandversion); -#ifndef _WIN32 // blat mailer needs comma - char *comma=address; - while ((comma=strchr(comma, ','))) - *comma=' '; -#endif - } - - // Export information in environment variables that will be useful - // for user scripts - exportenv(environ_strings[0], "SMARTD_MAILER", executable); - exportenv(environ_strings[1], "SMARTD_MESSAGE", message); - exportenv(environ_strings[2], "SMARTD_SUBJECT", subject); - dateandtimezoneepoch(dates, mail->firstsent); - exportenv(environ_strings[3], "SMARTD_TFIRST", dates); - snprintf(dates, DATEANDEPOCHLEN,"%d", (int)mail->firstsent); - exportenv(environ_strings[4], "SMARTD_TFIRSTEPOCH", dates); - exportenv(environ_strings[5], "SMARTD_FAILTYPE", whichfail[which]); - if (address) - exportenv(environ_strings[6], "SMARTD_ADDRESS", address); - exportenv(environ_strings[7], "SMARTD_DEVICESTRING", cfg->name); - - switch (cfg->controller_type) { - case CONTROLLER_3WARE_678K: - case CONTROLLER_3WARE_9000_CHAR: - case CONTROLLER_3WARE_678K_CHAR: - { - char *s,devicetype[16]; - sprintf(devicetype, "3ware,%d", cfg->controller_port-1); - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", devicetype); - if ((s=strchr(cfg->name, ' '))) - *s='\0'; - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - if (s) - *s=' '; - } - break; - case CONTROLLER_ATA: - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "ata"); - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - break; - case CONTROLLER_SCSI: - exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "scsi"); - exportenv(environ_strings[9], "SMARTD_DEVICE", cfg->name); - } - - // now construct a command to send this as EMAIL -#ifndef _WIN32 - if (address) - snprintf(command, 2048, - "$SMARTD_MAILER -s '%s' %s 2>&1 << \"ENDMAIL\"\n" - "This email was generated by the smartd daemon running on:\n\n" - " host name: %s\n" - " DNS domain: %s\n" - " NIS domain: %s\n\n" - "The following warning/error was logged by the smartd daemon:\n\n" - "%s\n\n" - "For details see host's SYSLOG (default: /var/log/messages).\n\n" - "%s%s%s" - "ENDMAIL\n", - subject, address, hostname, domainname, nisdomain, message, further, original, additional); - else - snprintf(command, 2048, "%s 2>&1", executable); - - // tell SYSLOG what we are about to do... - newadd=address?address:"<nomailer>"; - newwarn=which?"Warning via":"Test of"; - - 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; - 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 - - // No "here-documents" on Windows, so must use separate commandline and stdin - command[0] = stdinbuf[0] = 0; - boxtype = -1; boxmsgoffs = 0; - newadd = "<nomailer>"; - if (address) { - // address "[sys]msgbox ..." => show warning (also) as [system modal ]messagebox - int addroffs = (!strncmp(address, "sys", 3) ? 3 : 0); - if (!strncmp(address+addroffs, "msgbox", 6) && (!address[addroffs+6] || address[addroffs+6] == ',')) { - boxtype = (addroffs > 0 ? 1 : 0); - addroffs += 6; - if (address[addroffs]) - addroffs++; - } - else - addroffs = 0; - - if (address[addroffs]) { - // Use "blat" parameter syntax (TODO: configure via -M for other mailers) - snprintf(command, sizeof(command), - "%s - -q -subject \"%s\" -to \"%s\"", - executable, subject, address+addroffs); - newadd = address+addroffs; - } - // Message for mail [0...] and messagebox [boxmsgoffs...] - snprintf(stdinbuf, sizeof(stdinbuf), - "This email was generated by the smartd daemon running on:\n\n" - " host name: %s\n" - " DNS domain: %s\n" -// " NIS domain: %s\n" - "\n%n" - "The following warning/error was logged by the smartd daemon:\n\n" - "%s\n\n" - "For details see the event log or log file of smartd.\n\n" - "%s%s%s" - "\n", - hostname, /*domainname, */ nisdomain, &boxmsgoffs, message, further, original, additional); - } - else - snprintf(command, sizeof(command), "%s", executable); - - newwarn=which?"Warning via":"Test of"; - if (boxtype >= 0) { - // show message box - daemon_messagebox(boxtype, subject, stdinbuf+boxmsgoffs); - PrintOut(LOG_INFO,"%s message box\n", newwarn); - } - if (command[0]) { - 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, stdinbuf, strlen(stdinbuf), 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, 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++; - - // free copy of address (without commas) - address=FreeNonZero(address, -1, __LINE__, filenameandversion); - - return; -} - -// 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(char *fmt, ...){ - va_list ap; - - // get the correct time in syslog() - FixGlibcTimeZoneBug(); - // initialize variable argument list - va_start(ap,fmt); - // in debug==1 mode we will print the output from the ataprint.o functions! - if (debugmode && debugmode!=2) -#ifdef _WIN32 - if (facility == LOG_LOCAL1) // logging to stdout - vfprintf(stderr,fmt,ap); - else -#endif - vprintf(fmt,ap); - // in debug==2 mode we print output from knowndrives.o functions - else if (debugmode==2 || con->reportataioctl || con->reportscsiioctl || con->controller_port) { - openlog("smartd", LOG_PID, facility); - vsyslog(LOG_INFO, fmt, ap); - closelog(); - } - va_end(ap); - fflush(NULL); - return; -} - -// This function prints either to stdout or to the syslog as needed. -// This function is also used by utility.c to report LOG_CRIT errors. -void PrintOut(int priority,char *fmt, ...){ - va_list ap; - - // get the correct time in syslog() - FixGlibcTimeZoneBug(); - // initialize variable argument list - va_start(ap,fmt); - if (debugmode) -#ifdef _WIN32 - if (facility == LOG_LOCAL1) // logging to stdout - vfprintf(stderr,fmt,ap); - else -#endif - vprintf(fmt,ap); - else { - openlog("smartd", LOG_PID, facility); - vsyslog(priority,fmt,ap); - closelog(); - } - va_end(ap); - return; -} - -// Forks new process, closes ALL file descriptors, redirects stdin, -// stdout, and stderr. Not quite daemon(). See -// http://www.iar.unlp.edu.ar/~fede/revistas/lj/Magazines/LJ47/2335.html -// for a good description of why we do things this way. -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 ((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); - - // 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); - - // redirect any IO attempts to /dev/null for stdin - i=open("/dev/null",O_RDWR); - // stdout - dup(i); - // stderr - dup(i); - umask(0); - chdir("/"); - - 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 -void WritePidFile() { - if (pid_file) { - int error = 0; - pid_t pid = getpid(); - mode_t old_umask; - FILE* fp; - - old_umask = umask(0077); - fp = fopen(pid_file, "w"); - umask(old_umask); - if (fp == NULL) { - error = 1; - } else if (fprintf(fp, "%d\n", (int)pid) <= 0) { - error = 1; - } else if (fclose(fp) != 0) { - error = 1; - } - if (error) { - PrintOut(LOG_CRIT, "unable to write PID file %s - exiting.\n", pid_file); - EXIT(EXIT_PID); - } - PrintOut(LOG_INFO, "file %s written containing PID %d\n", pid_file, (int)pid); - } - return; -} - -// Prints header identifying version of code and home -void PrintHead(){ - PrintOut(LOG_INFO,"smartd version %s [%s] Copyright (C) 2002-4 Bruce Allen\n", PACKAGE_VERSION, SMARTMONTOOLS_BUILD_HOST); - PrintOut(LOG_INFO,"Home page is " PACKAGE_HOMEPAGE "\n\n"); - return; -} - -// prints help info for configuration file Directives -void Directives() { - PrintOut(LOG_INFO, - "Configuration file (%s) Directives (after device name):\n" - " -d TYPE Set the device type: ata, scsi, removable, 3ware,N\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, standby, idle\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. Type is one of: error, selftest\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 Current Pending Sectors in Attribute ID\n" - " -U ID Monitor Offline Uncorrectable Sectors in Attribute ID\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 -C 197 -U 198\n" - " -F TYPE Firmware bug workaround: none, samsung, samsung2\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/hda -a\n", - configfile); - return; -} - -/* Returns a pointer to a static string containing a formatted list of the valid - arguments to the option opt or NULL on failure. */ -const char *GetValidArgList(char opt) { - switch (opt) { - case 'c': - return "<FILE_NAME>, -"; - case 's': - return "valid_regular_expression"; - case 'l': - return "daemon, local0, local1, local2, local3, local4, local5, local6, local7"; - case 'q': - return "nodev, errors, nodevstartup, never, onecheck"; - case 'r': - return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; - case 'p': - return "<FILE_NAME>"; - case 'i': - return "<INTEGER_SECONDS>"; - default: - return NULL; - } -} - -/* prints help information for command syntax */ -void Usage (void){ - PrintOut(LOG_INFO,"Usage: smartd [options]\n\n"); -#ifdef HAVE_GETOPT_LONG - PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n"); - PrintOut(LOG_INFO," Read configuration file NAME or stdin [default is %s]\n\n", configfile); - 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"); -#if !(defined(_WIN32) || defined(__CYGWIN__)) - PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n"); -#else -#ifdef _WIN32 - PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n"); -#else - PrintOut(LOG_INFO," Use syslog facility local0 - local7 (ignored on Cygwin)\n\n"); -#endif -#endif // _WIN32 || __CYGWIN__ - 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')); -#ifdef _WIN32 - PrintOut(LOG_INFO," --service\n"); - PrintOut(LOG_INFO," Running as windows service (must be first arg, do not use from console)\n\n"); -#endif // _WIN32 - PrintOut(LOG_INFO," -V, --version, --license, --copyright\n"); - PrintOut(LOG_INFO," Print License, Copyright, and version information\n"); -#else - PrintOut(LOG_INFO," -c NAME|- Read configuration file NAME or stdin [default is %s]\n", configfile); - PrintOut(LOG_INFO," -d Start smartd in debug mode\n"); - PrintOut(LOG_INFO," -D Print the configuration file Directives and exit\n"); - PrintOut(LOG_INFO," -h Display this help and exit\n"); - PrintOut(LOG_INFO," -i N Set interval between disk checks to N seconds, where N >= 10\n"); - PrintOut(LOG_INFO," -l local? Use syslog facility local0 - local7, or daemon\n"); - PrintOut(LOG_INFO," -p NAME Write PID file NAME\n"); - PrintOut(LOG_INFO," -q WHEN Quit on one of: %s\n", GetValidArgList('q')); - PrintOut(LOG_INFO," -r TYPE Report transactions for one of: %s\n", GetValidArgList('r')); - PrintOut(LOG_INFO," -V Print License, Copyright, and version information\n"); -#endif -} - -// returns negative if problem, else fd>=0 -static int OpenDevice(char *device, char *mode, int scanning) { - int fd; - char *s=device; - - // If there is an ASCII "space" character in the device name, - // terminate string there. This is for 3ware devices only. - if ((s=strchr(device,' '))) - *s='\0'; - - // open the device - fd = deviceopen(device, mode); - - // if we removed a space, put it back in please - if (s) - *s=' '; - - // if we failed to open the device, complain! - if (fd < 0) { - - // 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) { - if (errno==ENOENT || errno==ENOTDIR) - errno=ENODEV; - - PrintOut(LOG_INFO,"Device: %s, %s, open() failed\n", - device, strerror(errno)); - } - return -1; - } - // device opened sucessfully - return fd; -} - -int CloseDevice(int fd, char *name){ - if (deviceclose(fd)){ - PrintOut(LOG_INFO,"Device: %s, %s, close(%d) failed\n", name, strerror(errno), fd); - return 1; - } - // device sucessfully closed - return 0; -} - -// returns <0 on failure -int ATAErrorCount(int fd, char *name){ - struct ata_smart_errorlog log; - - if (-1==ataReadErrorLog(fd,&log)){ - PrintOut(LOG_INFO,"Device: %s, Read SMART Error Log Failed\n",name); - return -1; - } - - // return current number of ATA errors - return log.error_log_pointer?log.ata_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. -int SelfTestErrorCount(int fd, char *name){ - struct ata_smart_selftestlog log; - - if (-1==ataReadSelfTestLog(fd,&log)){ - 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,0); -} - -// scan to see what ata devices there are, and if they support SMART -int ATADeviceScan(cfgfile *cfg, int scanning){ - int fd, supported=0; - struct ata_identify_device drive; - char *name=cfg->name; - int retainsmartdata=0; - int retid; - char *mode; - - // should we try to register this as an ATA device? - switch (cfg->controller_type) { - case CONTROLLER_ATA: - case CONTROLLER_3WARE_678K: - case CONTROLLER_UNKNOWN: - mode="ATA"; - break; - case CONTROLLER_3WARE_678K_CHAR: - mode="ATA_3WARE_678K"; - break; - case CONTROLLER_3WARE_9000_CHAR: - mode="ATA_3WARE_9000"; - break; - default: - // not a recognized ATA or SATA device. We should never enter - // this branch. - return 1; - } - - // open the device - if ((fd=OpenDevice(name, mode, scanning))<0) - // device open failed - return 1; - PrintOut(LOG_INFO,"Device: %s, opened\n", name); - - // pass user settings on to low-level ATA commands - con->controller_port=cfg->controller_port; - con->controller_type=cfg->controller_type; - con->fixfirmwarebug = cfg->fixfirmwarebug; - - // Get drive identity structure - if ((retid=ataReadHDIdentity (fd,&drive))){ - 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(fd, name); - return 2; - } - - // 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 { - // do whatever applypresets decides to do. Will allocate memory if - // cfg->attributedefs is needed. - if (applypresets(&drive, &cfg->attributedefs, con)<0) - PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name); - else - PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name); - - // then save the correct state of the flag (applypresets may have changed it) - cfg->fixfirmwarebug = con->fixfirmwarebug; - } - - // 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; - showpresets(&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(fd, name); - return 2; - } - } - - if (ataEnableSmart(fd)){ - // Enable SMART command has failed - PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); - CloseDevice(fd, name); - return 2; - } - - // disable device attribute autosave... - if (cfg->autosave==1){ - if (ataDisableAutoSave(fd)) - 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(fd)) - 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(fd)==-1){ - PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name); - cfg->smartcheck=0; - } - - // 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 retain SMART data after returning from this routine? - retainsmartdata=cfg->usagefailed || cfg->prefail || cfg->usage; - - // do we need to get SMART data? - if (retainsmartdata || cfg->autoofflinetest || cfg->selftest || cfg->errorlog || cfg->pending!=DONT_MONITOR_UNC) { - - unsigned char currentpending, offlinepending; - - cfg->smartval=(struct ata_smart_values *)Calloc(1,sizeof(struct ata_smart_values)); - cfg->smartthres=(struct ata_smart_thresholds_pvt *)Calloc(1,sizeof(struct ata_smart_thresholds_pvt)); - - if (!cfg->smartval || !cfg->smartthres){ - PrintOut(LOG_CRIT,"Not enough memory to obtain SMART data\n"); - EXIT(EXIT_NOMEM); - } - - if (ataReadSmartValues(fd,cfg->smartval) || - ataReadSmartThresholds (fd,cfg->smartthres)){ - PrintOut(LOG_INFO,"Device: %s, Read SMART Values and/or Thresholds Failed\n",name); - retainsmartdata=cfg->usagefailed=cfg->prefail=cfg->usage=0; - cfg->pending=DONT_MONITOR_UNC; - } - - // see if the necessary Attribute is there to monitor offline or - // current pending sectors - TranslatePending(cfg->pending, ¤tpending, &offlinepending); - - if (currentpending && ATAReturnAttributeRawValue(currentpending, cfg->smartval)<0) { - PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n", - name, (int)currentpending); - cfg->pending &= 0xff00; - cfg->pending |= CUR_UNC_DEFAULT; - } - - if (offlinepending && ATAReturnAttributeRawValue(offlinepending, cfg->smartval)<0) { - PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n", - name, (int)offlinepending); - cfg->pending &= 0x00ff; - cfg->pending |= OFF_UNC_DEFAULT<<8; - } - } - - // enable/disable automatic on-line testing - if (cfg->autoofflinetest){ - // is this an enable or disable request? - char *what=(cfg->autoofflinetest==1)?"disable":"enable"; - if (!cfg->smartval) - 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(cfg->smartval)) - PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name); - // ... but then try anyway - if ((cfg->autoofflinetest==1)?ataDisableAutoOffline(fd):ataEnableAutoOffline(fd)) - 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); - } - } - - // capability check: self-test-log - if (cfg->selftest){ - int retval; - - // start with service disabled, and re-enable it if all works OK - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - - if (!cfg->smartval) - PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log (SMART READ DATA failed); disabling -l selftest\n", name); - else if (!cfg->permissive && !isSmartTestLogCapable(cfg->smartval, &drive)) - PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Self-Test log; disabling -l selftest (override with -T permissive Directive)\n", name); - else if ((retval=SelfTestErrorCount(fd, name))<0) - PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log; remove -l selftest Directive from smartd.conf\n", name); - else { - cfg->selftest=1; - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } - } - - // capability check: ATA error log - if (cfg->errorlog){ - int val; - - // start with service disabled, and re-enable it if all works OK - cfg->errorlog=0; - cfg->ataerrorcount=0; - - if (!cfg->smartval) - PrintOut(LOG_INFO, "Device: %s, no SMART Error log (SMART READ DATA failed); disabling -l error\n", name); - else if (!cfg->permissive && !isSmartErrorLogCapable(cfg->smartval, &drive)) - PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Error log; disabling -l error (override with -T permissive Directive)\n", name); - else if ((val=ATAErrorCount(fd, name))<0) - PrintOut(LOG_INFO, "Device: %s, no SMART Error log; remove -l error Directive from smartd.conf\n", name); - else { - cfg->errorlog=1; - cfg->ataerrorcount=val; - } - } - - // If we don't need to save SMART data, get rid of it now - if (!retainsmartdata) { - if (cfg->smartval) { - cfg->smartval=CheckFree(cfg->smartval, __LINE__,filenameandversion); - bytes-=sizeof(struct ata_smart_values); - } - if (cfg->smartthres) { - cfg->smartthres=CheckFree(cfg->smartthres, __LINE__,filenameandversion); - bytes-=sizeof(struct ata_smart_thresholds_pvt); - } - } - - // capabilities check -- does it support powermode? - if (cfg->powermode) { - int powermode=ataCheckPowerMode(fd); - - 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; - } - } - - // If no tests available or selected, return - if (!(cfg->errorlog || cfg->selftest || cfg->smartcheck || - cfg->usagefailed || cfg->prefail || cfg->usage)) { - CloseDevice(fd, name); - return 3; - } - - // Do we still have entries available? - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); - - // register device - PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name); - - // record number of device, type of device, increment device count - if (cfg->controller_type == CONTROLLER_UNKNOWN) - cfg->controller_type=CONTROLLER_ATA;; - - // close file descriptor - CloseDevice(fd, name); - return 0; -} - -// on success, return 0. On failure, return >0. Never return <0, -// please. -static int SCSIDeviceScan(cfgfile *cfg, int scanning) { - int k, fd, err; - char *device = cfg->name; - struct scsi_iec_mode_page iec; - UINT8 tBuf[64]; - - // should we try to register this as a SCSI device? - switch (con->controller_type) { - case CONTROLLER_SCSI: - case CONTROLLER_UNKNOWN: - break; - default: - return 1; - } - - // open the device - if ((fd = OpenDevice(device, "SCSI", scanning)) < 0) - return 1; - PrintOut(LOG_INFO,"Device: %s, opened\n", device); - - // check that device is ready for commands. IE stores its stuff on - // the media. - if ((err = scsiTestUnitReady(fd))) { - if (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(fd, 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(fd, &iec, cfg->modese_len))) - cfg->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(fd, 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(fd, device); - return 3; - } - - // Device exists, and does SMART. Add to list (allocating more space if needed) - while (numdevscsi >= scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); - - // Flag that certain log pages are supported (information may be - // available from other sources). - if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { - for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { - switch (tBuf[k]) { - case TEMPERATURE_LPAGE: - cfg->TempPageSupported = 1; - break; - case IE_LPAGE: - cfg->SmartPageSupported = 1; - break; - default: - break; - } - } - } - - // record type of device - cfg->controller_type = CONTROLLER_SCSI; - - // get rid of allocated memory only needed for ATA devices. These - // might have been allocated if the user specified Ignore options or - // other ATA-only Attribute-specific options on the DEVICESCAN line. - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); - - // Check if scsiCheckIE() is going to work - { - UINT8 asc = 0; - UINT8 ascq = 0; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); - cfg->SuppressReport = 1; - } - } - - // capability check: self-test-log - if (cfg->selftest){ - int retval=scsiCountFailedSelfTests(fd, 0); - if (retval<0) { - // no self-test log, turn off monitoring - PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device); - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - } - else { - // register starting values to watch for changes - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } - } - - // disable autosave (set GLTSD bit) - if (cfg->autosave==1){ - if (scsiSetControlGLTSD(fd, 1, cfg->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(fd, 0, cfg->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); - - // close file descriptor - CloseDevice(fd, device); - return 0; -} - -// We compare old and new values of the n'th attribute. Note that n -// is NOT the attribute ID number.. If (Normalized & Raw) equal, -// then return 0, else nonzero. -int ATACompareValues(changedattribute_t *delta, - struct ata_smart_values *new, - struct ata_smart_values *old, - struct ata_smart_thresholds_pvt *thresholds, - int n, char *name){ - struct ata_smart_attribute *now,*was; - struct ata_smart_threshold_entry *thre; - unsigned char oldval,newval; - int sameraw; - - // check that attribute number in range, and no null pointers - if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !new || !old || !thresholds) - return 0; - - // pointers to disk's values and vendor's thresholds - now=new->vendor_attributes+n; - was=old->vendor_attributes+n; - thre=thresholds->thres_entries+n; - - // consider only valid attributes - if (!now->id || !was->id || !thre->id) - return 0; - - - // issue warning if they don't have the same ID in all structures: - if ( (now->id != was->id) || (now->id != thre->id) ){ - PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n", - name, (int)now->id, (int)was->id, (int)thre->id); - return 0; - } - - // new and old values of Normalized Attributes - newval=now->current; - oldval=was->current; - - // See if the RAW values are unchanged (ie, the same) - if (memcmp(now->raw, was->raw, 6)) - sameraw=0; - else - sameraw=1; - - // if any values out of the allowed range, or if the values haven't - // changed, return 0 - if (!newval || !oldval || newval>0xfe || oldval>0xfe || (oldval==newval && sameraw)) - return 0; - - // values have changed. Construct output and return - delta->newval=newval; - delta->oldval=oldval; - delta->id=now->id; - delta->prefail=ATTRIBUTE_FLAGS_PREFAILURE(now->flags); - delta->sameraw=sameraw; - - return 1; -} - -// This looks to see if the corresponding bit of the 32 bytes is set. -// This wastes a few bytes of storage but eliminates all searching and -// sorting functions! Entry is ZERO <==> the attribute ON. Calling -// with set=0 tells you if the attribute is being tracked or not. -// Calling with set=1 turns the attribute OFF. -int IsAttributeOff(unsigned char attr, unsigned char **datap, int set, int which, int whatline){ - unsigned char *data; - int loc=attr>>3; - int bit=attr & 0x07; - unsigned char mask=0x01<<bit; - - if (which>=NMONITOR || which < 0){ - PrintOut(LOG_CRIT, "Internal error in IsAttributeOff() at line %d of file %s (which=%d)\n%s", - whatline, filenameandversion, which, reportbug); - EXIT(EXIT_BADCODE); - } - - if (*datap == NULL){ - // NULL data implies Attributes are ON... - if (!set) - return 0; - - // we are writing - if (!(*datap=(unsigned char *)Calloc(NMONITOR*32, 1))){ - PrintOut(LOG_CRIT,"No memory to create monattflags\n"); - EXIT(EXIT_NOMEM); - } - } - - // pointer to the 256 bits that we need - data=*datap+which*32; - - // attribute zero is always OFF - if (!attr) - return 1; - - if (!set) - return (data[loc] & mask); - - data[loc]|=mask; - - // return value when setting has no sense - return 0; -} - -// If the self-test log has got more self-test errors (or more recent -// self-test errors) recorded, then notify user. -void CheckSelfTestLogs(cfgfile *cfg, int new){ - char *name=cfg->name; - - if (new<0) - // command failed - MailWarning(cfg, 8, "Device: %s, Read SMART Self-Test Log Failed", name); - else { - // old and new error counts - int oldc=cfg->selflogcount; - int newc=SELFTEST_ERRORCOUNT(new); - - // old and new error timestamps in hours - int oldh=cfg->selfloghour; - int newh=SELFTEST_ERRORHOURS(new); - - 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, 3, "Device: %s, Self-Test Log error count increased from %d to %d", - name, oldc, newc); - } else if (oldh<newh) { - // more recent error - PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n", - name, newh); - MailWarning(cfg, 3, "Device: %s, new Self-Test Log error at hour timestamp %d\n", - name, newh); - } - - // Needed since self-test error count may DECREASE. Hour should - // never decrease but this does no harm. - cfg->selflogcount= newc; - cfg->selfloghour = newh; - } - return; -} - -// returns 1 if time to do test of type testtype, 0 if not time to do -// test, < 0 if error -int DoTestNow(cfgfile *cfg, char testtype) { - // start by finding out the time: - struct tm *timenow; - time_t epochnow; - char matchpattern[16]; - regmatch_t substring; - int weekday, length; - unsigned short hours; - testinfo *dat=cfg->testdata; - - // check that self-testing has been requested - if (!dat) - return 0; - - // since we are about to call localtime(), be sure glibc is informed - // of any timezone changes we make. - FixGlibcTimeZoneBug(); - - // construct pattern containing the month, day of month, day of - // week, and hour - time(&epochnow); - timenow=localtime(&epochnow); - - // tm_wday is 0 (Sunday) to 6 (Saturday). We use 1 (Monday) to 7 - // (Sunday). - weekday=timenow->tm_wday?timenow->tm_wday:7; - sprintf(matchpattern, "%c/%02d/%02d/%1d/%02d", testtype, timenow->tm_mon+1, - timenow->tm_mday, weekday, timenow->tm_hour); - - // if no match, we are done - if (regexec(&(dat->cregex), matchpattern, 1, &substring, 0)) - return 0; - - // must match the ENTIRE type/date/time string - length=strlen(matchpattern); - if (substring.rm_so!=0 || substring.rm_eo!=length) - return 0; - - // never do a second test in the same hour as another test (the % 7 ensures - // that the RHS will never be greater than 65535 and so will always fit into - // an unsigned short) - hours=1+timenow->tm_hour+24*(timenow->tm_yday+366*(timenow->tm_year % 7)); - if (hours==dat->hour) { - if (testtype!=dat->testtype) - PrintOut(LOG_INFO, "Device: %s, did test of type %c in current hour, skipping test of type %c\n", - cfg->name, dat->testtype, testtype); - return 0; - } - - // save time and type of the current test; we are ready to do a test - dat->hour=hours; - dat->testtype=testtype; - return 1; -} - -// Return zero on success, nonzero on failure. Perform offline (background) -// short or long (extended) self test on given scsi device. -int DoSCSISelfTest(int fd, cfgfile *cfg, char testtype) { - int retval = 0; - char *testname = NULL; - char *name = cfg->name; - int inProgress; - - if (scsiSelfTestInProgress(fd, &inProgress)) { - PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name); - cfg->testdata->not_cap_short=cfg->testdata->not_cap_long=1; - 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(fd); - break; - case 'L': - testname = "Long Self"; - retval = scsiSmartExtendSelfTest(fd); - 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) - cfg->testdata->not_cap_long=1; - else - cfg->testdata->not_cap_short=1; - - 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. -int DoATASelfTest(int fd, cfgfile *cfg, char testtype) { - - struct ata_smart_values data; - char *testname=NULL; - int retval, dotest=-1; - char *name=cfg->name; - - // Read current smart data and check status/capability - if (ataReadSmartValues(fd, &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 - switch (testtype) { - case 'O': - testname="Offline Immediate "; - if (isSupportExecuteOfflineImmediate(&data)) - dotest=OFFLINE_FULL_SCAN; - else - cfg->testdata->not_cap_offline=1; - break; - case 'C': - testname="Conveyance Self-"; - if (isSupportConveyanceSelfTest(&data)) - dotest=CONVEYANCE_SELF_TEST; - else - cfg->testdata->not_cap_conveyance=1; - break; - case 'S': - testname="Short Self-"; - if (isSupportSelfTest(&data)) - dotest=SHORT_SELF_TEST; - else - cfg->testdata->not_cap_short=1; - break; - case 'L': - testname="Long Self-"; - if (isSupportSelfTest(&data)) - dotest=EXTEND_SELF_TEST; - else - cfg->testdata->not_cap_long=1; - 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)) { - 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; - } - - // else execute the test, and return status - if ((retval=smartcommandhandler(fd, IMMEDIATE_OFFLINE, dotest, NULL))) - PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname); - else - PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname); - - return retval; -} - - -int ATACheckDevice(cfgfile *cfg){ - int fd,i; - char *name=cfg->name; - char *mode="ATA"; - - // fix firmware bug if requested - con->fixfirmwarebug=cfg->fixfirmwarebug; - con->controller_port=cfg->controller_port; - con->controller_type=cfg->controller_type; - - // If user has asked, test the email warning system - if (cfg->mailwarn && cfg->mailwarn->emailtest) - MailWarning(cfg, 0, "TEST EMAIL from smartd for device: %s", name); - - if (cfg->controller_type == CONTROLLER_3WARE_9000_CHAR) - mode="ATA_3WARE_9000"; - - if (cfg->controller_type == CONTROLLER_3WARE_678K_CHAR) - mode="ATA_3WARE_678K"; - - // 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 ((fd=OpenDevice(name, mode, 0))<0){ - MailWarning(cfg, 9, "Device: %s, unable to open device", name); - return 1; - } - - // 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){ - int dontcheck=0, powermode=ataCheckPowerMode(fd); - char *mode=NULL; - - 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 - break; - default: - // UNKNOWN - PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", - name, powermode); - cfg->powermode=0; - break; - } - - // if we are going to skip a check, return now - if (dontcheck){ - CloseDevice(fd, name); - PrintOut(LOG_INFO, "Device: %s, is in %s mode, skipping checks\n", name, mode); - return 0; - } - } - - // check smart status - if (cfg->smartcheck){ - int status=ataSmartStatus2(fd); - if (status==-1){ - PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name); - MailWarning(cfg, 5, "Device: %s, not capable of SMART self-check", name); - } - else if (status==1){ - PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name); - MailWarning(cfg, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name); - } - } - - // Check everything that depends upon SMART Data (eg, Attribute values) - if (cfg->usagefailed || cfg->prefail || cfg->usage || cfg->pending!=DONT_MONITOR_UNC){ - struct ata_smart_values curval; - struct ata_smart_thresholds_pvt *thresh=cfg->smartthres; - - // Read current attribute values. *drive contains old values and thresholds - if (ataReadSmartValues(fd,&curval)){ - PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name); - MailWarning(cfg, 6, "Device: %s, failed to read SMART Attribute Data", name); - } - else { - // look for current or offline pending sectors - if (cfg->pending != DONT_MONITOR_UNC) { - int64_t rawval; - unsigned char currentpending, offlinepending; - - TranslatePending(cfg->pending, ¤tpending, &offlinepending); - - if (currentpending && (rawval=ATAReturnAttributeRawValue(currentpending, &curval))>0) { - // Unreadable pending sectors!! - PrintOut(LOG_CRIT, "Device: %s, %"PRId64" Currently unreadable (pending) sectors\n", name, rawval); - MailWarning(cfg, 10, "Device: %s, %"PRId64" Currently unreadable (pending) sectors", name, rawval); - } - - if (offlinepending && (rawval=ATAReturnAttributeRawValue(offlinepending, &curval))>0) { - // Unreadable offline sectors!! - PrintOut(LOG_CRIT, "Device: %s, %"PRId64" Offline uncorrectable sectors\n", name, rawval); - MailWarning(cfg, 11, "Device: %s, %"PRId64" Offline uncorrectable sectors", name, rawval); - } - } - - if (cfg->usagefailed || cfg->prefail || cfg->usage) { - - // look for failed usage attributes, or track usage or prefail attributes - for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ - int att; - changedattribute_t delta; - - // This block looks for usage attributes that have failed. - // Prefail attributes that have failed are returned with a - // positive sign. No failure returns 0. Usage attributes<0. - if (cfg->usagefailed && ((att=ataCheckAttribute(&curval, thresh, i))<0)){ - - // are we ignoring failures of this attribute? - att *= -1; - if (!IsAttributeOff(att, &cfg->monitorattflags, 0, MONITOR_FAILUSE, __LINE__)){ - char attname[64], *loc=attname; - - // get attribute name & skip white space - ataPrintSmartAttribName(loc, att, cfg->attributedefs); - while (*loc && *loc==' ') loc++; - - // warning message - PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc); - MailWarning(cfg, 2, "Device: %s, Failed SMART usage Attribute: %s.", name, loc); - } - } - - // This block tracks usage or prefailure attributes to see if - // they are changing. It also looks for changes in RAW values - // if this has been requested by user. - if ((cfg->usage || cfg->prefail) && ATACompareValues(&delta, &curval, cfg->smartval, thresh, i, name)){ - unsigned char id=delta.id; - - // if the only change is the raw value, and we're not - // tracking raw value, then continue loop over attributes - if (!delta.sameraw && delta.newval==delta.oldval && !IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_RAW, __LINE__)) - continue; - - // are we tracking this attribute? - if (!IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_IGNORE, __LINE__)){ - char newrawstring[64], oldrawstring[64], attname[64], *loc=attname; - - // get attribute name, skip spaces - ataPrintSmartAttribName(loc, id, cfg->attributedefs); - while (*loc && *loc==' ') loc++; - - // has the user asked for us to print raw values? - if (IsAttributeOff(id, &cfg->monitorattflags, 0, MONITOR_RAWPRINT, __LINE__)) { - // get raw values (as a string) and add to printout - char rawstring[64]; - ataPrintSmartAttribRawValue(rawstring, curval.vendor_attributes+i, cfg->attributedefs); - sprintf(newrawstring, " [Raw %s]", rawstring); - ataPrintSmartAttribRawValue(rawstring, cfg->smartval->vendor_attributes+i, cfg->attributedefs); - sprintf(oldrawstring, " [Raw %s]", rawstring); - } - else - newrawstring[0]=oldrawstring[0]='\0'; - - // prefailure attribute - if (cfg->prefail && delta.prefail) - PrintOut(LOG_INFO, "Device: %s, SMART Prefailure Attribute: %s changed from %d%s to %d%s\n", - name, loc, delta.oldval, oldrawstring, delta.newval, newrawstring); - - // usage attribute - if (cfg->usage && !delta.prefail) - PrintOut(LOG_INFO, "Device: %s, SMART Usage Attribute: %s changed from %d%s to %d%s\n", - name, loc, delta.oldval, oldrawstring, delta.newval, newrawstring); - } - } // endof block tracking usage or prefailure - } // end of loop over attributes - - // Save the new values into *drive for the next time around - *(cfg->smartval)=curval; - } - } - } - - // check if number of selftest errors has increased (note: may also DECREASE) - if (cfg->selftest) - CheckSelfTestLogs(cfg, SelfTestErrorCount(fd, name)); - - // check if number of ATA errors has increased - if (cfg->errorlog){ - - int new,old=cfg->ataerrorcount; - - // new number of errors - new=ATAErrorCount(fd, name); - - // did command fail? - if (new<0) - // lack of PrintOut here is INTENTIONAL - MailWarning(cfg, 7, "Device: %s, Read SMART Error Log Failed", name); - - // has error count increased? - if (new>old){ - PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", - name, old, new); - MailWarning(cfg, 4, "Device: %s, ATA error count increased from %d to %d", - name, old, new); - } - - // this last line is probably not needed, count always increases - if (new>=0) - cfg->ataerrorcount=new; - } - - // if the user has asked, and device is capable (or we're not yet - // sure) carry out scheduled self-tests. - if (cfg->testdata) { - // long test - if (!cfg->testdata->not_cap_long && DoTestNow(cfg, 'L')>0) - DoATASelfTest(fd, cfg, 'L'); - // short test - else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S')>0) - DoATASelfTest(fd, cfg, 'S'); - // conveyance test - else if (!cfg->testdata->not_cap_conveyance && DoTestNow(cfg, 'C')>0) - DoATASelfTest(fd, cfg, 'C'); - // offline immediate - else if (!cfg->testdata->not_cap_offline && DoTestNow(cfg, 'O')>0) - DoATASelfTest(fd, cfg, 'O'); - } - - // Don't leave device open -- the OS/user may want to access it - // before the next smartd cycle! - CloseDevice(fd, name); - return 0; -} - -#define DEF_SCSI_REPORT_TEMPERATURE_DELTA 2 -static int scsi_report_temperature_delta = DEF_SCSI_REPORT_TEMPERATURE_DELTA; - -int SCSICheckDevice(cfgfile *cfg) -{ - UINT8 asc, ascq; - UINT8 currenttemp; - UINT8 triptemp; - int fd; - char *name=cfg->name; - const char *cp; - - // If the user has asked for it, test the email warning system - if (cfg->mailwarn && cfg->mailwarn->emailtest) - MailWarning(cfg, 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 ((fd=OpenDevice(name, "SCSI", 0))<0) { - // Lack of PrintOut() here is intentional! - MailWarning(cfg, 9, "Device: %s, unable to open device", name); - return 1; - } - currenttemp = 0; - asc = 0; - ascq = 0; - if (! cfg->SuppressReport) { - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n", - name); - MailWarning(cfg, 6, "Device: %s, failed to read SMART values", name); - cfg->SuppressReport = 1; - } - } - if (asc > 0) { - cp = scsiGetIEString(asc, ascq); - if (cp) { - PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp); - MailWarning(cfg, 1,"Device: %s, SMART Failure: %s", name, cp); - } - } else if (debugmode) - PrintOut(LOG_INFO,"Device: %s, Acceptable asc,ascq: %d,%d\n", - name, (int)asc, (int)ascq); - - if (currenttemp && currenttemp!=255) { - if (cfg->Temperature) { - if (abs(((int)currenttemp - (int)cfg->Temperature)) >= - scsi_report_temperature_delta) { - PrintOut(LOG_INFO, "Device: %s, Temperature changed %d Celsius " - "to %d Celsius since last report\n", name, - (int)(currenttemp - cfg->Temperature), - (int)currenttemp); - cfg->Temperature = currenttemp; - } - } - else { - PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d " - "Celsius\n", name, (int)currenttemp); - if (triptemp) - PrintOut(LOG_INFO, " [trip Temperature is %d Celsius]\n", - (int)triptemp); - cfg->Temperature = currenttemp; - cfg->Temperature = currenttemp; - } - } - - // check if number of selftest errors has increased (note: may also DECREASE) - if (cfg->selftest) - CheckSelfTestLogs(cfg, scsiCountFailedSelfTests(fd, 0)); - - if (cfg->testdata) { - // long (extended) background test - if (!cfg->testdata->not_cap_long && DoTestNow(cfg, 'L')>0) - DoSCSISelfTest(fd, cfg, 'L'); - // short background test - else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S')>0) - DoSCSISelfTest(fd, cfg, 'S'); - } - CloseDevice(fd, name); - return 0; -} - -// Checks the SMART status of all ATA and SCSI devices -void CheckDevicesOnce(cfgfile **atadevices, cfgfile **scsidevices){ - int i; - - for (i=0; i<numdevata; i++) - ATACheckDevice(atadevices[i]); - - for (i=0; i<numdevscsi; i++) - SCSICheckDevice(scsidevices[i]); - - return; -} - -#if SCSITIMEOUT -// This alarm means that a SCSI USB device was hanging -void AlarmHandler(int signal) { - longjmp(registerscsienv, 1); -} -#endif - -// Does initialization right after fork to daemon mode -void Initialize(time_t *wakeuptime){ - - // install goobye message and remove pidfile handler - atexit(Goodbye); - - // write PID file only after installing exit handler - 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 - -time_t dosleep(time_t wakeuptime){ - time_t timenow=0; - - // If past wake-up-time, compute next wake-up-time - timenow=time(NULL); - while (wakeuptime<=timenow){ - int intervals=1+(timenow-wakeuptime)/checktime; - wakeuptime+=intervals*checktime; - } - - // sleep until we catch SIGUSR1 or have completed sleeping - while (timenow<wakeuptime && !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-timenow); - -#ifdef _WIN32 - // toggle debug mode? - if (caughtsigUSR2) { - ToggleDebugMode(); - caughtsigUSR2 = 0; - } -#endif - - timenow=time(NULL); - } - - // 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; - } - - // return adjusted wakeuptime - return wakeuptime; -} - -// Print out a list of valid arguments for the Directive d -void printoutvaliddirectiveargs(int priority, char d) { - char *s=NULL; - - switch (d) { - case 'n': - PrintOut(priority, "never, sleep, standby, idle"); - break; - case 's': - PrintOut(priority, "valid_regular_expression"); - break; - case 'd': - PrintOut(priority, "ata, scsi, removable, 3ware,N"); - 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': - if (!(s = create_vendor_attribute_arg_list())) { - PrintOut(LOG_CRIT,"Insufficient memory to construct argument list\n"); - EXIT(EXIT_NOMEM); - } - PrintOut(priority, "\n%s\n", s); - s=CheckFree(s, __LINE__,filenameandversion); - break; - case 'P': - PrintOut(priority, "use, ignore, show, showall"); - break; - case 'F': - PrintOut(priority, "none, samsung, samsung2"); - break; - } -} - -// exits with an error message, or returns integer value of token -int GetInteger(char *arg, char *name, char *token, int lineno, char *configfile, int min, int max){ - char *endptr; - int val; - - // check input range - if (min<0){ - PrintOut(LOG_CRIT, "min =%d passed to GetInteger() must be >=0\n", min); - return -1; - } - - // 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", - configfile, lineno, name, token, min, max); - return -1; - } - - // get argument value (base 10), check that it's integer, and in-range - val=strtol(arg,&endptr,10); - if (*endptr!='\0' || val<min || val>max ) { - PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n", - configfile, lineno, name, token, arg, min, max); - return -1; - } - - // all is well; return value - return val; -} - -// 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. -int ParseToken(char *token,cfgfile *cfg){ - char sym; - char *name=cfg->name; - int lineno=cfg->lineno; - char *delim = " \n\t"; - int badarg = 0; - int missingarg = 0; - char *arg = NULL; - int makemail=0; - maildata *mdat=NULL, tempmail; - - // 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]; - - // create temporary maildata structure. This means we can postpone - // allocating space in the data segment until we are sure there are - // no errors. - if ('m'==sym || 'M'==sym){ - if (!cfg->mailwarn){ - memset(&tempmail, 0, sizeof(maildata)); - mdat=&tempmail; - makemail=1; - } - else - mdat=cfg->mailwarn; - } - - // parse the token and swallow its argument - switch (sym) { - int val; - - case 'C': - // monitor current pending sector count (default 197) - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255))<0) - return -1; - if (val==CUR_UNC_DEFAULT) - val=0; - else if (val==0) - val=CUR_UNC_DEFAULT; - // set bottom 8 bits to correct value - cfg->pending &= 0xff00; - cfg->pending |= val; - break; - case 'U': - // monitor offline uncorrectable sectors (default 198) - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255))<0) - return -1; - if (val==OFF_UNC_DEFAULT) - val=0; - else if (val==0) - val=OFF_UNC_DEFAULT; - // turn off top 8 bits, then set to correct value - cfg->pending &= 0xff; - cfg->pending |= (val<<8); - 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=0; - } else if (!strcmp(arg, "permissive")) { - // Permissive mode; ignore errors from Mandatory SMART commands - cfg->permissive=1; - } else { - badarg = 1; - } - break; - case 'd': - // specify the device type - if ((arg = strtok(NULL, delim)) == NULL) { - missingarg = 1; - } else if (!strcmp(arg, "ata")) { - cfg->controller_port = 0; - cfg->controller_type = CONTROLLER_ATA; - } else if (!strcmp(arg, "scsi")) { - cfg->controller_port =0; - cfg->controller_type = CONTROLLER_SCSI; - } else if (!strcmp(arg, "removable")) { - cfg->removable = 1; - } else { - // look 3ware,N RAID device - int i; - char *s; - - // make a copy of the string to mess with - if (!(s = strdup(arg))) { - PrintOut(LOG_CRIT, - "No memory to copy argument to -d option - exiting\n"); - EXIT(EXIT_NOMEM); - } else if (strncmp(s,"3ware,",6)) { - badarg=1; - } else if (split_report_arg2(s, &i)){ - PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N requires N integer\n", - configfile, lineno, name); - badarg=1; - } else if ( i<0 || i>15) { - PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive -d 3ware,N (N=%d) must have 0 <= N <= 15\n", - configfile, lineno, name, i); - badarg=1; - } else { - // determine type of escalade device from name of device - cfg->controller_type = guess_device_type(name); - if (cfg->controller_type!=CONTROLLER_3WARE_9000_CHAR && cfg->controller_type!=CONTROLLER_3WARE_678K_CHAR) - cfg->controller_type=CONTROLLER_3WARE_678K; - - // NOTE: controller_port == disk number + 1 - cfg->controller_port = i+1; - } - s=CheckFree(s, __LINE__,filenameandversion); - } - break; - case 'F': - // fix firmware bug - if ((arg = strtok(NULL, delim)) == NULL) { - missingarg = 1; - } else if (!strcmp(arg, "none")) { - cfg->fixfirmwarebug = FIX_NONE; - } else if (!strcmp(arg, "samsung")) { - cfg->fixfirmwarebug = FIX_SAMSUNG; - } else if (!strcmp(arg, "samsung2")) { - cfg->fixfirmwarebug = FIX_SAMSUNG2; - } else { - badarg = 1; - } - break; - case 'H': - // check SMART status - cfg->smartcheck=1; - break; - case 'f': - // check for failure of usage attributes - cfg->usagefailed=1; - break; - case 't': - // track changes in all vendor attributes - cfg->prefail=1; - cfg->usage=1; - break; - case 'p': - // track changes in prefail vendor attributes - cfg->prefail=1; - break; - case 'u': - // track changes in usage vendor attributes - cfg->usage=1; - 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=1; - } else if (!strcmp(arg, "error")) { - // track changes in ATA error log - cfg->errorlog=1; - } else { - badarg = 1; - } - break; - case 'a': - // monitor everything - cfg->smartcheck=1; - cfg->prefail=1; - cfg->usagefailed=1; - cfg->usage=1; - cfg->selftest=1; - cfg->errorlog=1; - 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 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; - 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->testdata){ - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n", - configfile, lineno, name, cfg->testdata->regex); - cfg->testdata=FreeTestData(cfg->testdata); - } - // check for missing argument - if (!(arg = strtok(NULL, delim))) { - missingarg = 1; - } - // allocate space for structure and string - else if (!(cfg->testdata=(testinfo *)Calloc(1, sizeof(testinfo))) || !(cfg->testdata->regex=CustomStrDup(arg, 1, __LINE__,filenameandversion))) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): no memory to create Test Directive -s %s!\n", - configfile, lineno, name, arg); - EXIT(EXIT_NOMEM); - } - else if ((val=regcomp(&(cfg->testdata->cregex), arg, REG_EXTENDED))) { - char errormsg[512]; - // not a valid regular expression! - regerror(val, &(cfg->testdata->cregex), errormsg, 512); - PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n", - configfile, lineno, name, arg, errormsg); - cfg->testdata=FreeTestData(cfg->testdata); - 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 ((int)strlen(arg) != (val=strspn(arg,"0123456789/.+*|()?^$[]SLCO"))) - 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 (mdat->address) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n", - configfile, lineno, name, mdat->address); - mdat->address=FreeNonZero(mdat->address, -1,__LINE__,filenameandversion); - } - mdat->address=CustomStrDup(arg, 1, __LINE__,filenameandversion); - } - break; - case 'M': - // email warning options - if (!(arg = strtok(NULL, delim))) - missingarg = 1; - else if (!strcmp(arg, "once")) - mdat->emailfreq = 1; - else if (!strcmp(arg, "daily")) - mdat->emailfreq = 2; - else if (!strcmp(arg, "diminishing")) - mdat->emailfreq = 3; - else if (!strcmp(arg, "test")) - mdat->emailtest = 1; - else if (!strcmp(arg, "exec")) { - // Get the next argument (the command line) - if (!(arg = strtok(NULL, delim))) { - 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 (mdat->emailcmdline) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n", - configfile, lineno, name, mdat->emailcmdline); - mdat->emailcmdline=FreeNonZero(mdat->emailcmdline, -1,__LINE__,filenameandversion); - } - mdat->emailcmdline=CustomStrDup(arg, 1, __LINE__,filenameandversion); - } - 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; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_FAILUSE, __LINE__); - break; - case 'I': - // ignore attribute for tracking purposes - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_IGNORE, __LINE__); - break; - case 'r': - // print raw value when tracking - if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAWPRINT, __LINE__); - 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))<0) - return -1; - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAWPRINT, __LINE__); - IsAttributeOff(val, &cfg->monitorattflags, 1, MONITOR_RAW, __LINE__); - break; - case 'v': - // non-default vendor-specific attribute meaning - if (!(arg=strtok(NULL,delim))) { - missingarg = 1; - } else if (parse_attribute_def(arg, &cfg->attributedefs)){ - 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; - 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; - } - - // If this did something to fill the mail structure, and that didn't - // already exist, create it and copy. - if (makemail) { - if (!(cfg->mailwarn=(maildata *)Calloc(1, sizeof(maildata)))) { - PrintOut(LOG_INFO, "File %s line %d (drive %s): no memory to create mail warning entry!\n", - configfile, lineno, name); - EXIT(EXIT_NOMEM); - } - memcpy(cfg->mailwarn, mdat, sizeof(maildata)); - } - - return 1; -} - -// Allocate storage for a new cfgfile entry. If original!=NULL, it's -// a copy of the original, but with private data storage. Else all is -// zeroed. Returns address, and fails if non memory available. - -cfgfile *CreateConfigEntry(cfgfile *original){ - cfgfile *add; - - // allocate memory for new structure - if (!(add=(cfgfile *)Calloc(1,sizeof(cfgfile)))) - goto badexit; - - // if old structure was pointed to, copy it - if (original) - memcpy(add, original, sizeof(cfgfile)); - - // make private copies of data items ONLY if they are in use (non - // NULL) - add->name = CustomStrDup(add->name, 0, __LINE__,filenameandversion); - - if (add->testdata) { - int val; - if (!(add->testdata=(testinfo *)Calloc(1,sizeof(testinfo)))) - goto badexit; - memcpy(add->testdata, original->testdata, sizeof(testinfo)); - add->testdata->regex = CustomStrDup(add->testdata->regex, 1, __LINE__,filenameandversion); - // only POSIX-portable way to make fresh copy of compiled regex is - // to recompile it completely. There is no POSIX - // compiled-regex-copy command. - if ((val=regcomp(&(add->testdata->cregex), add->testdata->regex, REG_EXTENDED))) { - char errormsg[512]; - regerror(val, &(add->testdata->cregex), errormsg, 512); - PrintOut(LOG_CRIT, "unable to recompile regular expression %s. %s\n", add->testdata->regex, errormsg); - goto badexit; - } - } - - if (add->mailwarn) { - if (!(add->mailwarn=(maildata *)Calloc(1,sizeof(maildata)))) - goto badexit; - memcpy(add->mailwarn, original->mailwarn, sizeof(maildata)); - add->mailwarn->address = CustomStrDup(add->mailwarn->address, 0, __LINE__,filenameandversion); - add->mailwarn->emailcmdline = CustomStrDup(add->mailwarn->emailcmdline, 0, __LINE__,filenameandversion); - } - - if (add->attributedefs) { - if (!(add->attributedefs=(unsigned char *)Calloc(MAX_ATTRIBUTE_NUM,1))) - goto badexit; - memcpy(add->attributedefs, original->attributedefs, MAX_ATTRIBUTE_NUM); - } - - if (add->monitorattflags) { - if (!(add->monitorattflags=(unsigned char *)Calloc(NMONITOR*32, 1))) - goto badexit; - memcpy(add->monitorattflags, original->monitorattflags, NMONITOR*32); - } - - if (add->smartval) { - if (!(add->smartval=(struct ata_smart_values *)Calloc(1,sizeof(struct ata_smart_values)))) - goto badexit; - } - - if (add->smartthres) { - if (!(add->smartthres=(struct ata_smart_thresholds_pvt *)Calloc(1,sizeof(struct ata_smart_thresholds_pvt)))) - goto badexit; - } - - return add; - - badexit: - PrintOut(LOG_CRIT, "No memory to create entry from configuration file\n"); - EXIT(EXIT_NOMEM); -} - - - -// This is the routine that adds things to the cfgentries list. To -// prevent memory leaks when re-reading the configuration file many -// times, this routine MUST deallocate any memory other than that -// pointed to within cfg-> before it returns. -// -// Return values are: -// 1: parsed a normal line -// 0: found comment or blank line -// -1: found SCANDIRECTIVE line -// -2: found an error -// -// Note: this routine modifies *line from the caller! -int ParseConfigLine(int entry, int lineno,char *line){ - char *token=NULL; - char *name=NULL; - char *delim = " \n\t"; - cfgfile *cfg=NULL; - int devscan=0; - - // get first token: device name. If a comment, skip line - if (!(name=strtok(line,delim)) || *name=='#') { - return 0; - } - - // Have we detected the SCANDIRECTIVE directive? - if (!strcmp(SCANDIRECTIVE,name)){ - devscan=1; - if (entry) { - PrintOut(LOG_INFO,"Scan Directive %s (line %d) must be the first entry in %s\n",name, lineno, configfile); - return -2; - } - } - - // Is there space for another entry? If not, allocate more - while (entry>=cfgentries_max) - cfgentries=AllocateMoreSpace(cfgentries, &cfgentries_max, "configuration file device"); - - // We've got a legit entry, make space to store it - cfg=cfgentries[entry]=CreateConfigEntry(NULL); - cfg->name = CustomStrDup(name, 1, __LINE__,filenameandversion); - - // Store line number, and by default check for both device types. - cfg->lineno=lineno; - - // Try and recognize if a IDE or SCSI device. These can be - // overwritten by configuration file directives. - if (cfg->controller_type==CONTROLLER_UNKNOWN) - cfg->controller_type = guess_device_type(cfg->name); - - // parse tokens one at a time from the file. - while ((token=strtok(NULL,delim))){ - int retval=ParseToken(token,cfg); - - if (retval==0) - // No tokens left: - break; - - if (retval>0) { - // Parsed token -#if (0) - PrintOut(LOG_INFO,"Parsed token %s\n",token); -#endif - continue; - } - - if (retval<0) { - // error found on the line - return -2; - } - } - - // If we found 3ware controller, then modify device name by adding a SPACE - if (cfg->controller_port){ - int len=17+strlen(cfg->name); - char *newname; - - if (devscan){ - PrintOut(LOG_CRIT, "smartd: can not scan for 3ware devices (line %d of file %s)\n", - lineno, configfile); - return -2; - } - - if (!(newname=(char *)calloc(len,1))) { - PrintOut(LOG_INFO,"No memory to parse file: %s line %d, %s\n", configfile, lineno, strerror(errno)); - EXIT(EXIT_NOMEM); - } - - // Make new device name by adding a space then RAID disk number - snprintf(newname, len, "%s [3ware_disk_%02d]", cfg->name, cfg->controller_port-1); - cfg->name=CheckFree(cfg->name, __LINE__,filenameandversion); - cfg->name=newname; - bytes+=16; - } - - // If NO monitoring directives are set, then set all of them. - if (!(cfg->smartcheck || cfg->usagefailed || cfg->prefail || - cfg->usage || cfg->selftest || cfg->errorlog )){ - - PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n", - cfg->name, cfg->lineno, configfile); - - cfg->smartcheck=1; - cfg->usagefailed=1; - cfg->prefail=1; - cfg->usage=1; - cfg->selftest=1; - cfg->errorlog=1; - } - - // additional sanity check. Has user set -M options without -m? - if (cfg->mailwarn && !cfg->mailwarn->address && (cfg->mailwarn->emailcmdline || cfg->mailwarn->emailfreq || cfg->mailwarn->emailtest)){ - PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n", - cfg->name, cfg->lineno, configfile); - return -2; - } - - // has the user has set <nomailer>? - if (cfg->mailwarn && cfg->mailwarn->address && !strcmp(cfg->mailwarn->address,"<nomailer>")){ - // check that -M exec is also set - if (!cfg->mailwarn->emailcmdline){ - PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n", - cfg->name, cfg->lineno, configfile); - return -2; - } - // now free memory. From here on the sign of <nomailer> is - // address==NULL and cfg->emailcmdline!=NULL - cfg->mailwarn->address=FreeNonZero(cfg->mailwarn->address, -1,__LINE__,filenameandversion); - } - - // set cfg->emailfreq to 1 (once) if user hasn't set it - if (cfg->mailwarn && !cfg->mailwarn->emailfreq) - cfg->mailwarn->emailfreq = 1; - - entry++; - - if (devscan) - return -1; - else - return 1; -} - -// clean up utility for ParseConfigFile() -void cleanup(FILE **fpp, int is_stdin){ - if (*fpp){ - // (*fpp != stdin) does not work here if stdin has been closed & reopened - if (!is_stdin) - fclose(*fpp); - *fpp=NULL; - } - - return; -} - - -// 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 ==> cfgentries==NULL -// No configuration file ==> cfgentries[0]->lineno == 0 -// SCANDIRECTIVE found ==> cfgentries[0]->lineno != 0 -int ParseConfigFile(){ - FILE *fp=NULL; - int entry=0,lineno=1,cont=0,contlineno=0; - char line[MAXLINELEN+2]; - char fullline[MAXCONTLINE+1]; - - int is_stdin = (configfile == configfile_stdin); // pointer comparison ok here - - // Open config file, if it exists and is not <stdin> - if (!is_stdin) { - fp=fopen(configfile,"r"); - if (fp==NULL && (errno!=ENOENT || configfile_alt)) { - // 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) - fp = stdin; - - // No configuration file found -- use fake one - if (fp==NULL) { - int len=strlen(SCANDIRECTIVE)+4; - char *fakeconfig=(char *)calloc(len,1); - - if (!fakeconfig || - (len-1) != snprintf(fakeconfig, len, "%s -a", SCANDIRECTIVE) || - -1 != ParseConfigLine(entry, 0, fakeconfig) - ) { - PrintOut(LOG_CRIT,"Internal error in ParseConfigFile() at line %d of file %s\n%s", - __LINE__, filenameandversion, reportbug); - EXIT(EXIT_BADCODE); - } - fakeconfig=CheckFree(fakeconfig, __LINE__,filenameandversion); - return 0; - } - - // configuration file exists - PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile); - - // parse config file line by line - while (1) { - 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,fp); - - // are we at the end of the file? - if (!code){ - if (cont) { - scandevice=ParseConfigLine(entry,contlineno,fullline); - // See if we found a SCANDIRECTIVE directive - if (scandevice==-1) { - cleanup(&fp, is_stdin); - return 0; - } - // did we find a syntax error - if (scandevice==-2) { - cleanup(&fp, is_stdin); - 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){ - 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); - cleanup(&fp, is_stdin); - 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); - cleanup(&fp, is_stdin); - return -1; - } - - // copy string so far into fullline, and increment length - strcpy(fullline+cont,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(entry,contlineno,fullline); - - // did we find a scandevice directive? - if (scandevice==-1) { - cleanup(&fp, is_stdin); - return 0; - } - // did we find a syntax error - if (scandevice==-2) { - cleanup(&fp, is_stdin); - return -1; - } - - entry+=scandevice; - lineno++; - cont=0; - } - cleanup(&fp, is_stdin); - - // note -- may be zero if syntax of file OK, but no valid entries! - return entry; -} - - -// Prints copyright, license and version information -void PrintCopyleft(void){ - debugmode=1; - PrintHead(); - PrintCVS(); - return; -} - -/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> <=======\n", where - <LIST> is the list of valid arguments for option opt. */ -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, (char *)s); - PrintOut(LOG_CRIT, " <=======\n"); -} - -// Parses input line, prints usage message and -// version/license/copyright messages -void ParseOpts(int argc, char **argv){ - extern char *optarg; - extern int optopt, optind, opterr; - int optchar; - int badarg; - char *tailptr; - long lchecktime; - // Please update GetValidArgList() if you edit shortopts - const char *shortopts = "c:l:q:dDi:p:r:Vh?"; -#ifdef HAVE_GETOPT_LONG - char *arg; - // 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' }, - { "pidfile", required_argument, 0, 'p' }, - { "report", required_argument, 0, 'r' }, -#ifdef _WIN32 - { "service", no_argument, 0, 'S' }, -#endif - { "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' }, - { 0, 0, 0, 0 } - }; -#endif - - opterr=optopt=0; - badarg=FALSE; - - // Parse input options. This horrible construction is so that emacs - // indents properly. Sorry. - while (-1 != (optchar = -#ifdef HAVE_GETOPT_LONG - getopt_long(argc, argv, shortopts, longopts, NULL) -#else - getopt(argc, argv, shortopts) -#endif - )) { - - 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,"errors"))) { - quit=4; - } 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 = TRUE; - break; - case 'D': - // print summary of all valid directives - debugmode = TRUE; - 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")) { - con->reportataioctl = con->reportscsiioctl = i; - } else if (!strcmp(s,"ataioctl")) { - con->reportataioctl = i; - } else if (!strcmp(s,"scsiioctl")) { - con->reportscsiioctl = i; - } else { - badarg = TRUE; - } - s=CheckFree(s, __LINE__,filenameandversion); - } - break; - case 'c': - // alternate configuration file - if (strcmp(optarg,"-")) - configfile=configfile_alt=CustomStrDup(optarg, 1, __LINE__,filenameandversion); - else // read from stdin - configfile=configfile_stdin; - break; - case 'p': - // output file with PID number - pid_file=CustomStrDup(optarg, 1, __LINE__,filenameandversion); - break; -#ifdef _WIN32 - case 'S': - // running as service, option already handled by deamon_main(), so ignore it - break; -#endif - case 'V': - // print version and CVS info - PrintCopyleft(); - EXIT(0); - break; - case 'h': - // help: print summary of command-line options - debugmode=1; - PrintHead(); - Usage(); - EXIT(0); - break; - case '?': - default: - // unrecognized option - debugmode=1; - PrintHead(); -#ifdef HAVE_GETOPT_LONG - // 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); - } -#endif - 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) { - 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); - pid_file=FreeNonZero(pid_file, -1,__LINE__,filenameandversion); - EXIT(EXIT_BADCMD); - } - - // print header - PrintHead(); - - return; -} - -// Function we call if no configuration file was found or if the -// SCANDIRECTIVE Directive was found. It makes entries for device -// names returned by make_device_names() in os_OSNAME.c -int MakeConfigEntries(const char *type, int start){ - int i; - int num; - char** devlist = NULL; - cfgfile *first=cfgentries[0],*cfg=first; - - // make list of devices - if ((num=make_device_names(&devlist,type))<0) - PrintOut(LOG_CRIT,"Problem creating device name scan list\n"); - - // if no devices, or error constructing list, return - if (num<=0) - return 0; - - // loop over entries to create - for (i=0; i<num; i++){ - - // make storage and copy for all but first entry - if (start+i) { - // allocate more storage if needed - while (cfgentries_max<=start+i) - cfgentries=AllocateMoreSpace(cfgentries, &cfgentries_max, "simulated configuration file device"); - cfg=cfgentries[start+i]=CreateConfigEntry(first); - } - - // ATA or SCSI? - if (!strcmp(type,"ATA") ) - cfg->controller_type = CONTROLLER_ATA; - if (!strcmp(type,"SCSI") ) - cfg->controller_type = CONTROLLER_SCSI; - - // remove device name, if it's there, and put in correct one - cfg->name=FreeNonZero(cfg->name, -1,__LINE__,filenameandversion); - // save pointer to the device name created within - // make_device_names - cfg->name=devlist[i]; - } - - // If needed, free memory used for devlist: pointers now in - // cfgentries[]->names. If num==0 we never get to this point, but - // that's OK. If we realloc()d the array length in - // make_device_names() that was ALREADY equivalent to calling - // free(). - devlist = FreeNonZero(devlist,(sizeof (char*) * num),__LINE__, filenameandversion); - - return num; -} - -void CanNotRegister(char *name, char *type, int line, int scandirective){ - if( !debugmode && scandirective == 1 ) { 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. -// If we found no configuration file, or it contained SCANDIRECTIVE, -// then *scanning is set to 1, else 0. -int ReadOrMakeConfigEntries(int *scanning){ - int entries; - - // deallocate any cfgfile data structures in memory - RmAllConfigEntries(); - - // parse configuration file configfile (normally /etc/smartd.conf) - if ((entries=ParseConfigFile())<0) { - - // There was an error reading the configuration file. - RmAllConfigEntries(); - if (entries == -1) - PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile); - return entries; - } - - // did we find entries or scan? - *scanning=0; - - // 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 (cfgentries && cfgentries[0]) { - // we found a SCANDIRECTIVE or there was no configuration file so - // scan. Configuration file's first entry contains all options - // that were set - cfgfile *first=cfgentries[0]; - int doata = !(first->controller_type==CONTROLLER_SCSI); - int doscsi = !(first->controller_type==CONTROLLER_ATA); - - *scanning=1; - - 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 ATA devices to search for - if (doata) - entries+=MakeConfigEntries("ATA", entries); - // make config list of SCSI devices to search for - if (doscsi) - entries+=MakeConfigEntries("SCSI", entries); - - // warn user if scan table found no devices - if (!entries) { - PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n"); - // get rid of fake entry with SCANDIRECTIVE as name - RmConfigEntry(cfgentries, __LINE__); - } - } - else - PrintOut(LOG_CRIT,"Configuration file %s parsed but has no entries (like /dev/hda)\n",configfile); - - return entries; -} - - -// This function tries devices from cfgentries. Each one that can be -// registered is moved onto the [ata|scsi]devices lists and removed -// from the cfgentries list, else it's memory is deallocated. -void RegisterDevices(int scanning){ - int i; - - // start by clearing lists/memory of ALL existing devices - RmAllDevEntries(); - numdevata=numdevscsi=0; - - // Register entries - for (i=0; i<cfgentries_max ; i++){ - - cfgfile *ent=cfgentries[i]; - - // skip any NULL entries (holes) - if (!ent) - continue; - - // register ATA devices - if (ent->controller_type!=CONTROLLER_SCSI){ - if (ATADeviceScan(ent, scanning)) - CanNotRegister(ent->name, "ATA", ent->lineno, scanning); - else { - // move onto the list of ata devices - cfgentries[i]=NULL; - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); - atadevlist[numdevata++]=ent; - } - } - - // then register SCSI devices - if (ent->controller_type==CONTROLLER_SCSI || ent->controller_type==CONTROLLER_UNKNOWN){ - int retscsi=0; - -#if SCSITIMEOUT - struct sigaction alarmAction, defaultaction; - - // Set up an alarm handler to catch USB devices that hang on - // SCSI scanning... - alarmAction.sa_handler= AlarmHandler; - alarmAction.sa_flags = SA_RESTART; - if (sigaction(SIGALRM, &alarmAction, &defaultaction)) { - // if we can't set timeout, just scan device - PrintOut(LOG_CRIT, "Unable to initialize SCSI timeout mechanism.\n"); - retscsi=SCSIDeviceScan(ent, scanning); - } - else { - // prepare return point in case of bad SCSI device - if (setjmp(registerscsienv)) - // SCSI device timed out! - retscsi=-1; - else { - // Set alarm, make SCSI call, reset alarm - alarm(SCSITIMEOUT); - retscsi=SCSIDeviceScan(ent, scanning); - alarm(0); - } - if (sigaction(SIGALRM, &defaultaction, NULL)){ - PrintOut(LOG_CRIT, "Unable to clear SCSI timeout mechanism.\n"); - } - } -#else - retscsi=SCSIDeviceScan(ent, scanning); -#endif - - // Now scan SCSI device... - if (retscsi){ - if (retscsi<0) - PrintOut(LOG_CRIT, "Device %s timed out (poorly-implemented USB device?)\n", ent->name); - CanNotRegister(ent->name, "SCSI", ent->lineno, scanning); - } - else { - // move onto the list of scsi devices - cfgentries[i]=NULL; - while (numdevscsi>=scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); - scsidevlist[numdevscsi++]=ent; - } - } - - // if device is explictly listed and we can't register it, then - // exit unless the user has specified that the device is removable - if (cfgentries[i] && !scanning){ - if (ent->removable || quit==2) - PrintOut(LOG_INFO, "Device %s not available\n", ent->name); - else { - PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n", ent->name); - EXIT(EXIT_BADDEV); - } - } - - // free up memory if device could not be registered - RmConfigEntry(cfgentries+i, __LINE__); - } - - return; -} - - -#ifndef _WIN32 -// Main function -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 -{ - // external control variables for ATA disks - smartmonctrl control; - - // is it our first pass through? - int firstpass=1; - - // next time to wake up - time_t wakeuptime; - - // for simplicity, null all global communications variables/lists - con=&control; - memset(con, 0,sizeof(control)); - - // parse input and print header and usage info if needed - ParseOpts(argc,argv); - - // do we mute printing from ataprint commands? - con->printing_switchable=0; - con->dont_print=debugmode?0:1; - - // don't exit on bad checksums - con->checksumfail=0; - - // the main loop of the code - while (1){ - - // 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)); - - EXIT(isok?0:EXIT_SIGNAL); - } - - // Should we (re)read the config file? - if (firstpass || caughtsigHUP){ - int entries, scanning=0; - - if (!firstpass) { -#ifdef __CYGWIN__ - // Workaround for missing SIGQUIT via keyboard on Cygwin - if (caughtsigHUP==2) { - // Simulate SIGQUIT if another SIGINT arrives soon - caughtsigHUP=0; - sleep(1); - if (caughtsigHUP==2) { - caughtsigEXIT=SIGQUIT; - continue; - } - caughtsigHUP=2; - } -#endif - 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); - } - - // clears cfgentries, (re)reads config file, makes >=0 entries - entries=ReadOrMakeConfigEntries(&scanning); - - if (entries>=0) { - // checks devices, then moves onto ata/scsi list or deallocates. - RegisterDevices(scanning); - } - 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 - int status = (entries==-3 ? EXIT_READCONF : entries==-2 ? EXIT_NOCONF : EXIT_BADCONF); - EXIT(status); - } - - // Log number of devices we are monitoring... - if (numdevata+numdevscsi || quit==2 || (quit==1 && !firstpass)) - PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n", - numdevata, numdevscsi); - else { - PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n"); - EXIT(EXIT_NODEV); - } - - // reset signal - caughtsigHUP=0; - } - - // check all devices once - CheckDevicesOnce(atadevlist, scsidevlist); - - // 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"); - EXIT(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=0; - } - - // sleep until next check time, or a signal arrives - wakeuptime=dosleep(wakeuptime); - } -} - - -#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 diff --git a/sm5/smartd.h b/sm5/smartd.h deleted file mode 100644 index 3f300004ca4d49a2014db12ec348382a2ef43f63..0000000000000000000000000000000000000000 --- a/sm5/smartd.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * smartd.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 SMARTD_H_ -#define SMARTD_H_ - -// Needed since some structure definitions below require POSIX -// extended regular expressions. -#include <sys/types.h> -#include <regex.h> - - -#ifndef SMARTD_H_CVSID -#define SMARTD_H_CVSID "$Id: smartd.h,v 1.73 2004/08/16 22:44:28 ballen4705 Exp $\n" -#endif - -// Configuration file -#define CONFIGFILENAME "smartd.conf" - -// Scan directive for configuration file -#define SCANDIRECTIVE "DEVICESCAN" - -// maximum line length in configuration file -#define MAXLINELEN 128 - -// maximum length of a continued line in configuration file -#define MAXCONTLINE 1023 - -// default for how often SMART status is checked, in seconds -#define CHECKTIME 1800 - -/* Boolean Values */ -#define TRUE 0x01 -#define FALSE 0x00 - -// Number of monitoring flags per Attribute and offsets. See -// monitorattflags below. -#define NMONITOR 4 -#define MONITOR_FAILUSE 0 -#define MONITOR_IGNORE 1 -#define MONITOR_RAWPRINT 2 -#define MONITOR_RAW 3 - - -// Number of allowed mail message types -#define SMARTD_NMAIL 12 - -typedef struct mailinfo_s { - 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; - -// If user has requested email warning messages, then this structure -// stores the information about them, and track type/date of email -// messages. -typedef struct maildata_s { - mailinfo maillog[SMARTD_NMAIL]; // log info on when mail sent - char *emailcmdline; // script to execute - char *address; // email address, or null - unsigned char emailfreq; // Emails once (1) daily (2) diminishing (3) - unsigned char emailtest; // Send test email? -} maildata; - -// If user has requested automatic testing, then this structure stores -// their regular expression pattern, the compiled form of that regex, -// and information about the disk capabilities and when the last text -// took place - -typedef struct testinfo_s { - char *regex; // text form of regex - regex_t cregex; // compiled form of regex - unsigned short hour; // 1+hour of year when last scheduled self-test done - char testtype; // type of test done at hour indicated just above - signed char not_cap_offline; // 0==unknown OR capable of offline, 1==not capable - signed char not_cap_conveyance; - signed char not_cap_short; - signed char not_cap_long; -} testinfo; - - -// cfgfile is the main data structure of smartd. It is used in two -// ways. First, to store a list of devices/options given in the -// configuration smartd.conf or constructed with DEVICESCAN. And -// second, to point to or provide all persistent storage needed to -// track a device, if registered either as SCSI or ATA. -// -// After parsing the config file, each valid entry has a cfgfile data -// structure allocated in memory for it. In parsing the configuration -// file, some storage space may be needed, of indeterminate length, -// for example for the device name. When this happens, memory should -// be allocated and then pointed to from within the corresponding -// cfgfile structure. - -// After parsing the configuration file, each device is then checked -// to see if it can be monitored (this process is called "registering -// the device". This is done in [scsi|ata]devicescan, which is called -// exactly once, after the configuration file has been parsed and -// cfgfile data structures have been created for each of its entries. -// -// If a device can not be monitored, the memory for its cfgfile data -// structure should be freed by calling rmconfigentry(cfgfile *). In -// this case, we say that this device "was not registered". All -// memory associated with that particular cfgfile structure is thus -// freed. -// -// The remaining devices are polled in a timing look, where -// [ata|scsi]CheckDevice looks at each entry in turn. -// -// If you want to add small amounts of "private" data on a per-device -// basis, just make a new field in cfgfile. This is guaranteed zero -// on startup (when ata|scsi]scsidevicescan(cfgfile *cfg) is first -// called with a pointer to cfgfile. -// -// If you need *substantial* persistent data space for a device -// (dozens or hundreds of bytes) please add a pointer field to -// cfgfile. As before, this is guaranteed NULL when -// ata|scsi]scsidevicescan(cfgfile *cfg) is called. Allocate space for -// it in scsidevicescan or atadevicescan, if needed, and deallocate -// the space in rmconfigentry(cfgfile *cfg). Be sure to make the -// pointer NULL unless it points to an area of the heap that can be -// deallocated with free(). In other words, a non-NULL pointer in -// cfgfile means "this points to data space that should be freed if I -// stop monitoring this device." If you don't need the space anymore, -// please call free() and then SET THE POINTER IN cfgfile TO NULL. -// -// Note that we allocate one cfgfile structure per device. This is -// why substantial persisent data storage should only be pointed to -// from within cfgfile, not kept within cfgfile itself - it saves -// memory for those devices that don't need that type of persistent -// data. -// -// In general, the capabilities of devices should be checked at -// registration time within atadevicescan() and scsidevicescan(), and -// then noted within *cfg. So if device lacks some capability, this -// should be visible within *cfg after returning from -// [ata|scsi]devicescan. -// -// Devices are then checked, once per polling interval, within -// ataCheckDevice() and scsiCheckDevice(). These should only check -// the capabilities that devices already are known to have (as noted -// within *cfg). - -typedef struct configfile_s { - // FIRST SET OF ENTRIES CORRESPOND TO WHAT THE USER PUT IN THE - // CONFIG FILE. SOME ENTRIES MAY BE MODIFIED WHEN A DEVICE IS - // REGISTERED AND WE LEARN ITS CAPABILITIES. - int lineno; // Line number of entry in file - char *name; // Device name (+ optional [3ware_disk_XX]) - unsigned char controller_type; // Controller type, ATA/SCSI/3Ware/(more to come) - unsigned char controller_port; // 1 + (disk number in controller). 0 means controller only handles one disk. - char smartcheck; // Check SMART status - char usagefailed; // Check for failed Usage Attributes - char prefail; // Track changes in Prefail Attributes - char usage; // Track changes in Usage Attributes - char selftest; // Monitor number of selftest errors - char errorlog; // Monitor number of ATA errors - char permissive; // Ignore failed SMART commands - char autosave; // 1=disable, 2=enable Autosave Attributes - char autoofflinetest; // 1=disable, 2=enable Auto Offline Test - unsigned char fixfirmwarebug; // Fix firmware bug - char ignorepresets; // Ignore database of -v options - char showpresets; // Show database entry for this device - char removable; // Device may disappear (not be present) - char powermode; // skip check, if disk in idle or standby mode - unsigned char selflogcount; // total number of self-test errors - unsigned short selfloghour; // lifetime hours of last self-test error - testinfo *testdata; // Pointer to data on scheduled testing - unsigned short pending; // lower 8 bits: ID of current pending sector count - // upper 8 bits: ID of offline pending sector count - - // THE NEXT SET OF ENTRIES ALSO TRACK DEVICE STATE AND ARE DYNAMIC - maildata *mailwarn; // non-NULL: info about sending mail or executing script - - // SCSI ONLY - unsigned char SmartPageSupported; // has log sense IE page (0x2f) - unsigned char TempPageSupported; // has log sense temperature page (0xd) - unsigned char Temperature; // last recorded figure (in Celsius) - unsigned char SuppressReport; // minimize nuisance reports - unsigned char modese_len; // mode sense/select cmd len: 0 (don't - // know yet) 6 or 10 - unsigned char notused2[3]; // for packing alignment - - // ATA ONLY FROM HERE ON TO THE END - int ataerrorcount; // Total number of ATA errors - - // following NMONITOR items each point to 32 bytes, in the form of - // 32x8=256 single bit flags - // valid attribute numbers are from 1 <= x <= 255 - // monitorattflags+0 set: ignore failure for a usage attribute - // monitorattflats+32 set: don't track attribute - // monitorattflags+64 set: print raw value when tracking - // monitorattflags+96 set: track changes in raw value - unsigned char *monitorattflags; - - // NULL UNLESS (1) STORAGE IS ALLOCATED WHEN CONFIG FILE SCANNED - // (SET BY USER) or (2) IT IS SET WHEN DRIVE IS AUTOMATICALLY - // RECOGNIZED IN DATABASE (WHEN DRIVE IS REGISTERED) - unsigned char *attributedefs; // -v options, see end of extern.h for def - - // ATA ONLY - SAVE SMART DATA. NULL POINTERS UNLESS NEEDED. IF - // NEEDED, ALLOCATED WHEN DEVICE REGISTERED. - struct ata_smart_values *smartval; // Pointer to SMART data - struct ata_smart_thresholds_pvt *smartthres; // Pointer to SMART thresholds - -} cfgfile; - - -typedef struct changedattribute_s { - unsigned char newval; - unsigned char oldval; - unsigned char id; - unsigned char prefail; - unsigned char sameraw; -} changedattribute_t; - -// Declare our own printing functions. Doing this provides error -// messages if the argument number/types don't match the format. -#ifndef __GNUC__ -#define __attribute__(x) /* nothing */ -#endif -void PrintOut(int priority,char *fmt, ...) __attribute__ ((format(printf, 2, 3))); - -void PrintAndMail(cfgfile *cfg, int which, int priority, char *fmt, ...) __attribute__ ((format(printf, 4, 5))); - -/* Debugging notes: to check for memory allocation/deallocation problems, use: - -export LD_PRELOAD=libnjamd.so; -export NJAMD_PROT=strict; -export NJAMD_CHK_FREE=error; -export NJAMD_DUMP_LEAKS_ON_EXIT=num; -export NJAMD_DUMP_LEAKS_ON_EXIT=3; -export NJAMD_TRACE_LIBS=1 - -*/ - -// Number of seconds to allow for registering a SCSI device. If this -// time expires without sucess or failure, then treat it as failure. -// Set to 0 to eliminate this timeout feature from the code -// (equivalent to an infinite timeout interval). -#define SCSITIMEOUT 0 - -// 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 - -#endif - -#define SELFTEST_ERRORCOUNT(x) (x & 0xff) -#define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff) - -// cfg->pending is a 16 bit unsigned quantity. If the least -// significant 8 bits are zero, this means monitor Attribute -// CUR_UNC_DEFAULT's raw value. If they are CUR_UNC_DEFAULT, this -// means DON'T MONITOR. If the most significant 8 bits are zero, this -// means monitor Attribute OFF_UNC_DEFAULT's raw value. If they are -// OFF_UNC_DEFAULT, this means DON'T MONITOR. -#define OFF_UNC_DEFAULT 198 -#define CUR_UNC_DEFAULT 197 - -#define CURR_PEND(x) (x & 0xff) -#define OFF_PEND(x) ((x >> 8) & 0xff) - -// if cfg->pending has this value, dont' monitor -#define DONT_MONITOR_UNC (256*OFF_UNC_DEFAULT+CUR_UNC_DEFAULT) diff --git a/sm5/smartd.initd.in b/sm5/smartd.initd.in deleted file mode 100755 index 3c4fa58d4fc80b26089c3e79120a58ada95e9715..0000000000000000000000000000000000000000 --- a/sm5/smartd.initd.in +++ /dev/null @@ -1,418 +0,0 @@ -#! @SHELL@ - -# smartmontools init file for smartd -# Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> -# $Id: smartd.initd.in,v 1.26 2004/08/13 12:41:40 arvoreen Exp $ - -# 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 -# X-UnitedLinux-Should-Start: $sendmail -# Required-Stop: $syslog -# X-UnitedLinux-Should-Stop: -# 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., 675 -# Mass Ave, Cambridge, MA 02139, 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" - -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 ] ; 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 - - case "$1" in - start) - echo -n $"Starting $prog: " - daemon /usr/sbin/smartd $smartd_opts - touch /var/lock/subsys/smartd - echo - ;; - stop) - echo -n $"Shutting down $prog: " - killproc smartd - rm -f /var/lock/subsys/smartd - echo - ;; - reload) - echo -n $"Reloading $prog daemon configuration: " - killproc /usr/sbin/smartd -HUP - RETVAL=$? - echo - ;; - report) - echo -n $"Checking SMART devices now: " - killproc /usr/sbin/smartd -USR1 - RETVAL=$? - echo - ;; - restart) - $0 stop - $0 start - ;; - status) - status $prog - ;; - *) - echo $"Usage: $0 {start|stop|reload|report|restart|status}" - RETVAL=1 - 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 - - case "$1" in - start) - echo -n "Starting smartd: " - smartd $smartd_opts - echo - ;; - stop) - echo -n "Shutting down smartd: " - killall smartd - echo - ;; - restart) - $0 stop - sleep 1 - $0 start - ;; - *) - echo "Usage: smartd {start|stop|restart}" - exit 1 - esac - - exit 0 - -# SuSE -elif [ -f /etc/SuSE-release ] ; then - - SMARTD_BIN=/usr/sbin/smartd - test -x $SMARTD_BIN || exit 5 - - # Existence of config file is optional - SMARTD_CONFIG=/etc/smartd.conf - -# source configuration file. This should set the shell variable smartd_opts - [ -r /etc/default/smartmontools ] && . /etc/default/smartmontools - - # 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 ditto but be verbose in local rc status - # rc_status -v -r ditto and clear the local rc status - # rc_failed set local and overall rc status to failed - # rc_reset clear local rc status (overall remains) - # rc_exit exit appropriate to overall rc status - . /etc/rc.status - - # First reset status of this service - rc_reset - - # Return values acc. to LSB for all commands but status: - # 0 - success - # 1 - misc error - # 2 - invalid or excess args - # 3 - unimplemented feature (e.g. reload) - # 4 - insufficient privilege - # 5 - program not installed - # 6 - program not configured - # - # Note that starting an already running service, stopping - # or restarting a not-running service as well as the restart - # with force-reload (in case signalling is not supported) are - # considered a success. - case "$1" in - start) - echo -n "Starting smartd" - ## Start daemon with startproc(8). If this fails - ## the echo return value is set appropriate. - - # startproc should return 0, even if service is - # already running to match LSB spec. - startproc $SMARTD_BIN $smartd_opts - - # Remember status and be verbose - rc_status -v - ;; - stop) - echo -n "Shutting down smartd" - killproc -TERM $SMARTD_BIN - - # Remember status and be verbose - rc_status -v - ;; - restart | force-reload) - $0 stop - $0 start - ;; - reload) - ## Like force-reload, but if daemon does not support - ## signaling, do nothing (!) - rc_failed 3 - 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. - - # Status has a slightly different for the status command: - # 0 - service running - # 1 - service dead, but /var/run/ pid file exists - # 2 - service dead, but /var/lock/ lock file exists - # 3 - service not running - - # NOTE: checkproc returns LSB compliant status values. - 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.2) - - test $SMARTD_CONFIG -nt /var/run/smartd.pid && echo reload - ;; - *) - echo "Usage: $0 {start|stop|status|restart|force-reload|reload|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 - SMARTCTL=/usr/sbin/smartctl - SMARTD=/usr/sbin/smartd - SMARTDPID=/var/run/smartd.pid - [ -x $SMARTCTL ] || exit 0 - [ -x $SMARTD ] || exit 0 - RET=0 - -# source configuration file - [ -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 -- $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|force-reload) - $0 stop - $0 start - ;; - *) - echo "Usage: /etc/init.d/smartmontools {start|stop|restart|force-reload}" - 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="${PREFIX}/bin/smartd" - 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) - $PREFIX/bin/smartd -p $PID_FILE $smartd_flags - echo -n " smartd" - ;; - stop) - kill `cat $PID_FILE` - echo -n " smartd" - ;; - restart) - $0 stop - sleep 1 - $0 start - ;; - *) - echo "Usage: smartd {start|stop|restart}" - 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 -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 - ;; - *) - echo "Usage: smartd {start|stop|restart}" - exit 1 - esac - - exit 0 -elif uname | grep -i CYGWIN > /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 Cygwin - - [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools - - PID_FILE=/var/run/smartd.pid - RETVAL=0 - - case "$1" in - start) - echo -n "Starting smartd: " - /usr/sbin/smartd -p $PID_FILE $smartd_opts - RETVAL=$? - ;; - stop) - echo -n "Shutting down smartd: " - [ -r $PID_FILE ] && kill `cat $PID_FILE` - RETVAL=$? - ;; - reload) - echo -n "Reloading smartd configuration: " - [ -r $PID_FILE ] && kill -HUP `cat $PID_FILE` - RETVAL=$? - ;; - report) - echo -n "Checking SMART devices now: " - [ -r $PID_FILE ] && kill -USR1 `cat $PID_FILE` - RETVAL=$? - ;; - restart) - $0 stop - sleep 1 - $0 start - exit $? - ;; - *) - echo "Usage: $0 {start|stop|restart|reload|report}" - 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 diff --git a/sm5/smartmontools.spec b/sm5/smartmontools.spec deleted file mode 100644 index 181a69217338b0953516ee6a44311e899e7d51f4..0000000000000000000000000000000000000000 --- a/sm5/smartmontools.spec +++ /dev/null @@ -1,1551 +0,0 @@ -Release: 1 -Summary: smartmontools - for monitoring S.M.A.R.T. disks and devices -Summary(cs): smartmontools - pro monitorov�n� S.M.A.R.T. disk� a za��zen� -Summary(de): smartmontools - zur �berwachung von S.M.A.R.T.-Platten und-Ger�ten -Summary(es): smartmontools - para el seguimiento de discos y dispositivos S.M.A.R.T. -Summary(fr): smartmontools - pour le suivi des disques et instruments S.M.A.R.T. -Summary(pt): smartmontools - para monitorar discos e dispositivos S.M.A.R.T. -Summary(it): smartmontools - per monitare dischi e dispositivi S.M.A.R.T. -Summary(pl): Monitorowanie i kontrola dysk�w u�ywaj�� S.M.A.R.T. -Name: smartmontools -Version: 5.33 -License: GPL -Group: Applications/System -Group(de): Applikationen/System -Group(es): Aplicaciones/Sistema -Group(fr): Applications/Syst�me -Group(pt): Aplicativos/Sistema -Group(it): Applicazioni/Sistemi -Source0: %{name}-%{version}.tar.gz -URL: http://smartmontools.sourceforge.net/ -Prereq: /sbin/chkconfig -BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: smartctl -Obsoletes: smartd -Obsoletes: ucsc-smartsuite -Obsoletes: smartsuite -Packager: Bruce Allen <smartmontools-support@lists.sourceforge.net> - -%define redhat %(test ! -f /etc/redhat-release ; echo $?) -%define redhat %(test ! -f /etc/fedora-release ; echo $?) -%define mandrake %(test ! -f /etc/mandrake-release ; echo $?) -%define suse %(test ! -f /etc/SuSE-release ; echo $?) - -# Source code can be found at: -# http://ftp1.sourceforge.net/smartmontools/smartmontools-%{version}-%{release}.tar.gz - -# CVS ID of this file is: -# $Id: smartmontools.spec,v 1.160 2004/07/07 14:45:19 ballen4705 Exp $ - -# Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net> -# Home page: http://smartmontools.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., 675 -# Mass Ave, Cambridge, MA 02139, 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/ - - -%description -smartmontools 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. This is used to check the -reliability of the hard drive and to predict drive failures. The suite -is derived from the smartsuite package, and contains two utilities. The -first, smartctl, is a command line utility designed to perform simple -S.M.A.R.T. tasks. The second, smartd, is a daemon that periodically -monitors smart status and reports errors to syslog. The package is -compatible with the ATA/ATAPI-5 specification. Future releases will be -compatible with the ATA/ATAPI-6 andATA/ATAPI-7 specifications. The -package is intended to incorporate as much "vendor specific" and -"reserved" information as possible about disk drives. man smartctl and -man smartd will provide more information. This RPM file is compatible -with all RedHat releases back to at least 6.2 and should work OK on any -modern linux distribution. The most recent versions of this package and -additional information can be found at the URL: -http://smartmontools.sourceforge.net/ - -%description -l cs -smartmontools ��d� a monitoruj� za��zen� pro ukl�d�n� dat za pou�it� -technologie automatick�ho monitorov�n�, anal�zy a hl�en� -(Self-Monitoring, Analysis and Reporting Technology System - -S.M.A.R.T.) vestav�n�ho do pevn�ch disk� ATA a SCSI. Pou��v� se ke -kontrole pou�itelnosti pevn�ho disku a p�edv�d�n� hav�ri� disk�. -N�stroje jsou odvozeny od bal��ku smartsuite a obsahuj� dva programy. -Prvn�, smartctl, je n�stroj pro prov�d�n� jednoduch�ch S.M.A.R.T. �loh -na p��kazov� ��dce. Druh�, smartd, je d�mon, kter� periodicky -monitoruje stav a hl�s� chyby do syst�mov�ho protokolu. Bal��ek je -kompatibiln� se specifikac� ATA/ATAPI-5. Dal�� verze budou -kompatibiln� se specifikacemi ATA/ATAPI-6 a ATA/ATAPI-7. Bal��ek je -navr�en tak, aby pokryl co nejv�ce polo�ek s informacemi "z�visl� na -v�robci" a "rezervov�no". V�ce informac� z�sk�te pomoc� man smartctl a -man smartd. Tento RPM bal��ek je kompatibiln� se v�emi verzemi RedHatu -a m�l by fungovat na v�ech modern�ch distribuc�ch Linuxu. Aktu�ln� -verzi najdete na URL http://smartmontools.sourceforge.net/ - -%description -l de -Die smartmontools steuern und �berwachen Speicherger�te mittels des -S.M.A.R.T.-Systems (Self-Monitoring, Analysis and Reporting Technology, -Technologie zur Selbst-�berwachung, Analyse und Berichterstellung), das -in ATA- und SCSI-Festplatten eingesetzt wird. Sie werden benutzt, um -die Zuverl�ssigkeit der Festplatte zu pr�fen und Plattenfehler -vorherzusagen. Die Suite wurde vom smartsuite-Paket abgeleitet und -enth�lt zwei Dienstprogramme. Das erste, smartctl, ist ein -Kommandozeilentool, das einfache S.M.A.R.T. Aufgaben ausf�hrt. Das -zweite, smartd, ist ein Daemon, der periodisch den S.M.A.R.T.-Status -�berwacht und Fehler ins Syslog protokolliert. Das Paket ist zur -ATA/ATAPI-5 Spezifikation kompatibel. Zuk�nftige Versionen werden auch -die ATA/ATAPI-6 und ATA/ATAPI-7 Spezifikationen umsetzen. Das Paket -versucht, so viele "herstellerspezifische" und "reservierte" Information -�ber Plattenlaufwerke wie m�glich bereitzustellen. man smartctl und man -smartd liefern mehr Informationen �ber den Einsatz. Dieses RPM ist zu -allen RedHat-Versionen ab sp�testens 6.2 kompatibel und sollte unter -jedem modernen Linux arbeiten. Die aktuellsten Versionen dieses Pakets -und zus�tzliche Informationen sind zu finden unter der URL: -http://smartmontools.sourceforge.net/ - -%description -l es -smartmontools controla y hace el seguimiento de dispositivos de -almacenamiento usando el Self-Monitoring, Analysis and Reporting -Technology System (S.M.A.R.T.) incorporado en discos duros ATA y SCSI. -Es usado para asegurar la fiabilidad de discos duros y predecir averias. -El conjunto de programas proviene del conjunto smartsuite y contiene dos -utilidades. La primera, smartctl, es una utilidad command-line hecha -para hacer operaciones S.M.A.R.T. sencillas. La segunda, smartd, es un -programa que periodicamente chequea el estatus smart e informa de -errores a syslog. Estos programas son compatibles con el sistema -ATA/ATAPI-5. Futuras versiones seran compatibles con los sistemas -ATA/ATAPI-6 y ATA/ATAPI-7. Este conjunto de programas tiene el -proposito de incorporar la mayor cantidad posible de informacion -reservada y especifica de discos duros. Los comandos 'man smartctl' y -'man smartd' contienen mas informacion. Este fichero RPM es compatible -con todas las versiones de RedHat a partir de la 6.2 y posiblemente -funcionaran sin problemas en cualquier distribucion moderna de linux. -La version mas reciente de estos programas ademas de informacion -adicional pueden encontrarse en: http://smartmontools.sourceforge.net/ - -%description -l fr -smartmontools contr�le et fait le suivi de p�riph�riques de stockage -utilisant le syst�me Self-Monitoring, Analysis and Reporting -Technology (S.M.A.R.T) int�gr�dans les disques durs ATA et SCSI. Ce -syst�me est utilis� pour v�rifier la fiabilit� du disque dur et pr�dire -les d�faillances du lecteur. La suite logicielle d�rive du paquet -smartsuite et contient deux utilitaires. Le premier, smartctl, -fonctionne en ligne de commande et permet de r�aliser des t�ches -S.M.A.R.T. simples. Le second, smartd, est un d�mon qui fait -p�riodiquement le suivi du statut smart et transmet les erreurs au -syslog. Ce paquet est compatible avec la sp�cification ATA/ATAPI-5. -Les prochaines versions seront compatibles avec les sp�cifications -ATA/ATAPI-6 et ATA/ATAPI-7. Ce paquet tente d'incorporer le plus -d'informations possible sur les disques durs qu'elles soient sp�cifiques -au constructeur ("vendor specific") ou r�serv�es ("reserved"). man -smartctl et man smartd donnent plus de renseignements. Ce fichier RPM -est compatible avec toutes les versions de RedHat v6.2 et ult�rieures, -et devrait fonctionner sur toutes les distributions r�centes de Linux. -Les derni�res versions de ce paquet et des informations suppl�mentaires -peuvent �tre trouv�es � l'adresse URL: -http://smartmontools.sourceforge.net/ - -%description -l pt -smartmontools controla e monitora dispositivos de armazenamento -utilizando o recurso Self-Monitoring, Analysis and Reporting Technology -System (S.M.A.R.T.) integrado nos discos r�gidos ATA e SCSI, cuja -finalidade � verificar a confiabilidade do disco r�gido e prever falhas -da unidade. A suite � derivada do pacote smartsuite, e cont�m dois -utilit�rios. O primeiro, smartctl, � um utilit�rio de linha de comando -projetado para executar tarefas simples de S.M.A.R.T. O segundo, -smartd, � um daemon que monitora periodicamente estados do smart e -reporta erros para o syslog. O pacote � compat�vel com a especifica��o -ATA/ATAPI-5. Futuras vers�es ser�o compat�veis com as especifica��es -ATA/ATAPI-6 e ATA/ATAPI-7. O pacote pretende incorporar o maior n�mero -poss�vel de informa��es "espec�ficas do fabricante" e "reservadas" sobre -unidades de disco. man smartctl e man smartd cont�m mais informa��es. -Este arquivo RPM � compat�vel com todas as vers�es do RedHat a partir da -6.2 e dever� funcionar perfeitamente em qualquer distribui��o moderna do -Linux. As mais recentes vers�es deste pacote e informa��es adicionais -podem ser encontradas em http://smartmontools.sourceforge.net/ - -%description -l it -smartmontools controlla e monitora dischi che usano il "Self-Monitoring, -Analysis and Reporting Technology System" (S.M.A.R.T.), in hard drive -ATA e SCSI. Esso � usato per controllare l'affidabilit� dei drive e -predire i guasti. La suite � derivata dal package smartsuite e contiene -due utility. La prima, smartctl, � una utility a linea di comando -progettata per eseguire semplici task S.M.A.R.T.. La seconda, smartd, � -un daemon che periodicamente monitora lo stato di smart e riporta errori -al syslog. Il package � compatibile con le specifiche ATA/ATAPI-6 e -ATA/ATAPI-7. Il package vuole incorporare tutte le possibili -informazioni riservate e "vendor specific" sui dischi. man smartctl e -man smartd danno pi� informazioni. Questo file RPM � compatibile con -tutte le release di RedHat, almeno dalla 6.2 e dovrebbe funzionare bene -su ogni moderna distribuzione di linux. Le versioni pi� recenti di -questo package e informazioni addizionali possono essere trovate al sito -http://smartmontools.sourceforge.net/ - -%description -l pl -Pakiet zawiera dwa programy (smartctl oraz smartd) do kontroli i -monitorowania system�w przechowywania danych za pomoc� S.M.A.R.T - -systemu wbudowanego w wi�kszo�� nowych dysk�w ATA oraz SCSI. Pakiet -pochodzi od oprogramowania smartsuite i wspiera dyski ATA/ATAPI-5. - -# The following sections are executed by the SRPM file -%prep - -%setup -q - -%build - %configure - make - -%install - rm -rf $RPM_BUILD_ROOT - rm -rf %{_buildroot} - %makeinstall - rm -f examplescripts/Makefile* - %if %{suse} - mkdir -p $RPM_BUILD_ROOT%{_defaultdocdir} - mv $RPM_BUILD_ROOT/usr/share/doc/%{name}-%{version} $RPM_BUILD_ROOT%{_defaultdocdir}/%{name} - ln -s ../../etc/rc.d/init.d/smartd $RPM_BUILD_ROOT%{_sbindir}/rcsmartd - %endif - -%files - %defattr(-,root,root) - %attr(755,root,root) %{_sbindir}/smartd - %attr(755,root,root) %{_sbindir}/smartctl - %if %{suse} - %attr(755,root,root) %{_sbindir}/rcsmartd - %endif - %attr(755,root,root) /etc/rc.d/init.d/smartd - %attr(644,root,root) %{_mandir}/man8/smartctl.8* - %attr(644,root,root) %{_mandir}/man8/smartd.8* - %attr(644,root,root) %{_mandir}/man5/smartd.conf.5* - %doc AUTHORS CHANGELOG COPYING INSTALL NEWS README TODO WARNINGS smartd.conf examplescripts - %config(noreplace) %{_sysconfdir}/smartd.conf - -%clean - rm -rf $RPM_BUILD_ROOT - rm -rf %{_buildroot} - rm -rf %{_builddir}/%{name}-%{version} - -# The following are executed only by the binary RPM at install/uninstall - -# since this installs the gzipped documentation files, remove -# non-gzipped ones of the same name. - -# run before installation. Passed "1" the first time package installed, else a larger number -%pre -if [ -f /usr/share/man/man8/smartctl.8 ] ; then - echo "You MUST delete (by hand) the outdated file /usr/share/man/man8/smartctl.8 to read the new manual page for smartctl." -fi -if [ -f /usr/share/man/man8/smartd.8 ] ; then - echo "You MUST delete (by hand) the outdated file /usr/share/man/man8/smartd.8 to read the new manual page for smartd." -fi -if [ -f /usr/share/man/man5/smartd.conf.5 ] ; then - echo "You MUST delete (by hand) the outdated file /usr/share/man/man5/smartd.conf.5 to read the new manual page for smartd.conf" -fi - -if [ ! -f /etc/smartd.conf ]; then - echo "Note that you can use a configuration file /etc/smartd.conf to control the" - echo "startup behavior of the smartd daemon. See man 8 smartd for details." -fi - -# run after installation. Passed "1" the first time package installed, else a larger number -%post -# if smartd is already running, restart it with the new daemon -if [ -f /var/lock/subsys/smartd ]; then - /etc/rc.d/init.d/smartd restart 1>&2 - echo "Restarted smartd services" -else -# else tell the user how to start it - echo "Run \"/etc/rc.d/init.d/smartd start\" to start smartd service now." -fi - -# Now see if we should tell user to set service to start on boot -/sbin/chkconfig --list smartd > /dev/null 2> /dev/null -printmessage=$? - -if [ $printmessage -ne 0 ] ; then - echo "Run \"/sbin/chkconfig --add smartd\", to start smartd service on system boot" -else - echo "smartd will continue to start up on system boot" -fi - - -# run before uninstallation. Passed zero when the last version uninstalled, else larger -%preun - -# if uninstalling the final copy, stop and remove any links -if [ "$1" = "0" ]; then - if [ -f /var/lock/subsys/smartd ]; then - /etc/rc.d/init.d/smartd stop 1>&2 - echo "Stopping smartd services" - fi - -# see if any links remain, and kill them if they do - /sbin/chkconfig --list smartd > /dev/null 2> /dev/null - notlinked=$? - - if [ $notlinked -eq 0 ]; then - /sbin/chkconfig --del smartd - echo "Removing chkconfig links to smartd boot-time startup scripts" - fi -fi - -# run after uninstallation. Passed zero when the last version uninstalled, else larger -# %postun - -%define date %(echo `LC_ALL="C" date +"%a %b %d %Y"`) - -# Maintainers / Developers Key: -# [BA] Bruce Allen -# [EB] Erik Inge Bols� -# [SB] Stanislav Brabec -# [PC] Peter Cassidy -# [CD] Capser Dik -# [CF] Christian Franke -# [GF] Guilhem Fr�zou -# [DG] Douglas Gilbert -# [GG] Guido Guenther -# [DK] David Kirkby -# [KM] Kai M�kisarai -# [EM] Eduard Martinescu -# [FM] Fr�d�ric L. W. Meunier -# [KS] Keiji Sawada -# [SS] Sergey Svishchev -# [PW] Phil Williams - -%changelog -* Mon Jul 5 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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. - -* Tue May 4 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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' - -* Sat Mar 6 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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. - -* Tue Feb 24 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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. - -* Thu Feb 12 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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 IDENIFY 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. - -* Sat Nov 29 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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) -* Wed Nov 19 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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. - -* Fri Oct 31 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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 - -* Mon Oct 27 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Wed Oct 15 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> - [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. - -* Sun Oct 05 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [GG] Fixed broken Makefile.am (zero length smartd.conf.5 - was being created) -- [FM] Improved Slackware init script added to /etc/smartd.initd - -* Fri Oct 03 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Fri Aug 22 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [BA] smartd: fixed serious bug - Attributes not monitored unless - user told smartd to ignore at least one of them! - -* Tue Aug 19 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Wed Aug 06 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Wed Jul 23 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Mon Jun 16 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [BA] smartctl: added column to -A output to show if Attributes are - updated only during off-line testing or also during normal - operation. - -* Thu Jun 10 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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] Added mods submitted by Guilhem Frezou 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 -- [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 pgae 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). - -* Wed May 7 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Mon Apr 21 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. - -* Thu Mar 13 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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.. - -* Wed Feb 12 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [BA] smartd: Created a subdirectory examplescripts/ of source - directory that contains executable scripts for the -M exec PATH - Directive of smartd. -- [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. - -* Tue Jan 21 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. -- [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" - -* Sun Jan 12 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [BA] As requested, local time/date now printed by smartctl -i - -* Thu Jan 9 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [PW] Added 'help' argument to -v for smartctl -- [PW] Added -D, --showdirectives option to smartd - -* Sat Jan 4 2003 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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 -- [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. - -* Sun Dec 8 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- [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. -- [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. - -* Fri Nov 22 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Allen: 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. -- Allen: 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. -- Bolso: 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. -- Allen: smartd: added Directive -m for sending test email and - for modifying email reminder behavior. Updated manual, and sample - configuration file to illustrate & explain this. -- Allen: smartd: increased size of a continued smartd.conf line to - 1023 characters. -- Allen: Simplified Directive parsers and improved warning/error - messages. - -* Sun Nov 17 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Fixed bug in smartd where testunitready logic inverted - prevented functioning on scsi devices. -- Added testunitnotready to smartctl for symmetry with smartd. -- Brabec: added Czech descriptions to .spec file -- Brabec: corrected comment in smartd.conf example -- 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. -- Changed Temperature_Centigrade to Temperature_Celsius. - The term "Centigrade" ceased to exist in 1948. (c.f - http://www.bartleby.com/64/C004/016.html). - -* Wed Nov 13 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- smartd SCSI devices: can now send warning email message on failure -- 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. - -* Mon Nov 11 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- 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. - -* Sun Nov 10 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- 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. - -* Thu Nov 7 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Added a Man section 5 page for smartd.conf -- Changed Makefile so that the -V option does not reflect file state - before commit! -- modified .spec file so that locale information now contains - character set definition. Changed pt_BR to pt since we do not use any - aspect other than language. See man setlocale. -- smartctl: added new options -W, -U, and -P to control if and how the - smartctl exits if an error is detected in either a SMART data - structure checksum, or a SMART command returns an error. -- modified manual page to break options into slightly more logical - categories. -- reformatted 'usage' message order to agree with man page ordering - -* Mon Nov 4 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- smartctl: added new options -n and -N to force device to be ATA or SCSI -- smartctl: no longer dies silently if device path does not start/dev/X -- smartctl: now handles arbitrary device paths -- Added additional macros for manual and sbin paths in this SPEC file. -- Modified Makefile to install /etc/smartd.conf, but without overwriting existing config file -- Modified this specfile to do the same, and to not remove any files that it did not install - -* Thu Oct 30 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Fixed typesetting error in man page smartd.8 -- Removed redundant variable (harmless) from smartd.c - -* Wed Oct 29 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- 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. -- 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 #848 at - http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=query -- 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. -- 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 - required. -- 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. - -* Tue Oct 29 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Eliminated some global variables out of header files and other - minor cleanup of smartd. -- Did some revision of the man page for smartd and made the usage - messages for Directives consistent. -- 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?] -- 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. -- 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. - -* Fri Oct 25 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- changes to the Makefile and spec file so that if there are ungzipped manual - pages in place these will be removed so that the new gzipped man pages are - visible. -- 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. If not found, try all ata and ide devices. -- 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 - -* Thu Oct 24 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- 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. - -* Thu Oct 17 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Removed extraneous space before some error message printing. -- Fixed some character buffers that were too short for contents. - Only used for unrecognized drives, so probably damage was minimal. - -* Wed Oct 16 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> -- Initial release. Code is derived from smartsuite, and is - intended to be compatible with the ATA/ATAPI-5 specifications. -- 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 - diff --git a/sm5/tweio.h b/sm5/tweio.h deleted file mode 100644 index 430157fba707664d82619415ee462107e6e77799..0000000000000000000000000000000000000000 --- a/sm5/tweio.h +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * 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. - * - * $FreeBSD: src/sys/dev/twe/tweio.h,v 1.3 2003/12/02 07:57:20 ps Exp $ - */ - - -/* - * 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) - -/* - * Command queue statistics - */ -#define TWEQ_FREE 0 -#define TWEQ_BIO 1 -#define TWEQ_READY 2 -#define TWEQ_BUSY 3 -#define TWEQ_COMPLETE 4 -#define TWEQ_COUNT 5 /* total number of queues */ - -struct twe_qstat { - u_int32_t q_length; - u_int32_t q_max; - u_int32_t q_min; -}; - -/* - * Statistics request - */ -union twe_statrequest { - u_int32_t ts_item; - struct twe_qstat ts_qstat; -}; - -#define TWEIO_STATS _IOWR('T', 101, union twe_statrequest) - -/* - * AEN listen - */ -#define TWEIO_AEN_POLL _IOR('T', 102, u_int16_t) -#define TWEIO_AEN_WAIT _IOR('T', 103, u_int16_t) - -/* - * Controller parameter access - */ -struct twe_paramcommand { - u_int16_t tp_table_id; - u_int8_t tp_param_id; - void *tp_data; - u_int8_t tp_size; -}; - -#define TWEIO_SET_PARAM _IOW ('T', 104, struct twe_paramcommand) -#define TWEIO_GET_PARAM _IOW ('T', 105, struct twe_paramcommand) - -/* - * Request a controller soft-reset - */ -#define TWEIO_RESET _IO ('T', 106) - -/* - * Request a drive addition or deletion - */ -struct twe_drivecommand { - int td_unit; -}; - -#define TWEIO_ADD_UNIT _IOW ('U', 107, int) -#define TWEIO_DEL_UNIT _IOW ('U', 108, int) diff --git a/sm5/twereg.h b/sm5/twereg.h deleted file mode 100644 index 2eea8f542c401d6444332b0c766ac17a4905b32b..0000000000000000000000000000000000000000 --- a/sm5/twereg.h +++ /dev/null @@ -1,495 +0,0 @@ -/*- - * 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. - * - * $FreeBSD: src/sys/dev/twe/twereg.h,v 1.10 2003/12/02 07:57:20 ps Exp $ - */ - -/* - * Register names, bit definitions, structure names and members are - * identical with those in the Linux driver where possible and sane - * for simplicity's sake. (The TW_ prefix has become TWE_) - * Some defines that are clearly irrelevant to FreeBSD have been - * removed. - */ - -/* control register bit definitions */ -#define TWE_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 -#define TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 -#define TWE_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000 -#define TWE_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000 -#define TWE_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000 -#define TWE_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000 -#define TWE_CONTROL_CLEAR_ERROR_STATUS 0x00000200 -#define TWE_CONTROL_ISSUE_SOFT_RESET 0x00000100 -#define TWE_CONTROL_ENABLE_INTERRUPTS 0x00000080 -#define TWE_CONTROL_DISABLE_INTERRUPTS 0x00000040 -#define TWE_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 -#define TWE_CONTROL_CLEAR_PARITY_ERROR 0x00800000 -#define TWE_CONTROL_CLEAR_PCI_ABORT 0x00100000 - -#define TWE_SOFT_RESET(sc) TWE_CONTROL(sc, TWE_CONTROL_ISSUE_SOFT_RESET | \ - TWE_CONTROL_CLEAR_HOST_INTERRUPT | \ - TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT | \ - TWE_CONTROL_MASK_COMMAND_INTERRUPT | \ - TWE_CONTROL_MASK_RESPONSE_INTERRUPT | \ - TWE_CONTROL_CLEAR_ERROR_STATUS | \ - TWE_CONTROL_DISABLE_INTERRUPTS) - -/* status register bit definitions */ -#define TWE_STATUS_MAJOR_VERSION_MASK 0xF0000000 -#define TWE_STATUS_MINOR_VERSION_MASK 0x0F000000 -#define TWE_STATUS_PCI_PARITY_ERROR 0x00800000 -#define TWE_STATUS_QUEUE_ERROR 0x00400000 -#define TWE_STATUS_MICROCONTROLLER_ERROR 0x00200000 -#define TWE_STATUS_PCI_ABORT 0x00100000 -#define TWE_STATUS_HOST_INTERRUPT 0x00080000 -#define TWE_STATUS_ATTENTION_INTERRUPT 0x00040000 -#define TWE_STATUS_COMMAND_INTERRUPT 0x00020000 -#define TWE_STATUS_RESPONSE_INTERRUPT 0x00010000 -#define TWE_STATUS_COMMAND_QUEUE_FULL 0x00008000 -#define TWE_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000 -#define TWE_STATUS_MICROCONTROLLER_READY 0x00002000 -#define TWE_STATUS_COMMAND_QUEUE_EMPTY 0x00001000 -#define TWE_STATUS_ALL_INTERRUPTS 0x000F0000 -#define TWE_STATUS_CLEARABLE_BITS 0x00D00000 -#define TWE_STATUS_EXPECTED_BITS 0x00002000 -#define TWE_STATUS_UNEXPECTED_BITS 0x00F80000 - -/* XXX this is a little harsh, but necessary to chase down firmware problems */ -#define TWE_STATUS_PANIC_BITS (TWE_STATUS_MICROCONTROLLER_ERROR) - -/* for use with the %b printf format */ -#define TWE_STATUS_BITS_DESCRIPTION \ - "\20\15CQEMPTY\16UCREADY\17RQEMPTY\20CQFULL\21RINTR\22CINTR\23AINTR\24HINTR\25PCIABRT\26MCERR\27QERR\30PCIPERR\n" - -/* detect inconsistencies in the status register */ -#define TWE_STATUS_ERRORS(x) \ - (((x & TWE_STATUS_PCI_ABORT) || \ - (x & TWE_STATUS_PCI_PARITY_ERROR) || \ - (x & TWE_STATUS_QUEUE_ERROR) || \ - (x & TWE_STATUS_MICROCONTROLLER_ERROR)) && \ - (x & TWE_STATUS_MICROCONTROLLER_READY)) - -/* Response queue bit definitions */ -#define TWE_RESPONSE_ID_MASK 0x00000FF0 - -/* PCI related defines */ -#define TWE_IO_CONFIG_REG 0x10 -#define TWE_DEVICE_NAME "3ware 7000 series Storage Controller" -#define TWE_VENDOR_ID 0x13C1 -#define TWE_DEVICE_ID 0x1000 -#define TWE_DEVICE_ID_ASIC 0x1001 -#define TWE_PCI_CLEAR_PARITY_ERROR 0xc100 -#define TWE_PCI_CLEAR_PCI_ABORT 0x2000 - -/* command packet opcodes */ -#define TWE_OP_NOP 0x00 -#define TWE_OP_INIT_CONNECTION 0x01 -#define TWE_OP_READ 0x02 -#define TWE_OP_WRITE 0x03 -#define TWE_OP_READVERIFY 0x04 -#define TWE_OP_VERIFY 0x05 -#define TWE_OP_ZEROUNIT 0x08 -#define TWE_OP_REPLACEUNIT 0x09 -#define TWE_OP_HOTSWAP 0x0a -#define TWE_OP_SETATAFEATURE 0x0c -#define TWE_OP_FLUSH 0x0e -#define TWE_OP_ABORT 0x0f -#define TWE_OP_CHECKSTATUS 0x10 -#define TWE_OP_ATA_PASSTHROUGH 0x11 -#define TWE_OP_GET_PARAM 0x12 -#define TWE_OP_SET_PARAM 0x13 -#define TWE_OP_CREATEUNIT 0x14 -#define TWE_OP_DELETEUNIT 0x15 -#define TWE_OP_REBUILDUNIT 0x17 -#define TWE_OP_SECTOR_INFO 0x1a -#define TWE_OP_AEN_LISTEN 0x1c -#define TWE_OP_CMD_PACKET 0x1d -#define TWE_OP_CMD_WITH_DATA 0x1f - -/* command status values */ -#define TWE_STATUS_RESET 0xff /* controller requests reset */ -#define TWE_STATUS_FATAL 0xc0 /* fatal errors not requiring reset */ -#define TWE_STATUS_WARNING 0x80 /* warnings */ -#define TWE_STAUS_INFO 0x40 /* informative status */ - -/* misc defines */ -#define TWE_ALIGNMENT 0x200 -#define TWE_MAX_UNITS 16 -#define TWE_COMMAND_ALIGNMENT_MASK 0x1ff -#define TWE_INIT_MESSAGE_CREDITS 0xff /* older firmware has issues with 256 commands */ -#define TWE_SHUTDOWN_MESSAGE_CREDITS 0x001 -#define TWE_INIT_COMMAND_PACKET_SIZE 0x3 -#define TWE_MAX_SGL_LENGTH 62 -#define TWE_MAX_ATA_SGL_LENGTH 60 -#define TWE_MAX_PASSTHROUGH 4096 -#define TWE_Q_LENGTH TWE_INIT_MESSAGE_CREDITS -#define TWE_Q_START 0 -#define TWE_MAX_RESET_TRIES 3 -#define TWE_BLOCK_SIZE 0x200 /* 512-byte blocks */ -#define TWE_SECTOR_SIZE 0x200 /* generic I/O bufffer */ -#define TWE_IOCTL 0x80 -#define TWE_MAX_AEN_TRIES 100 -#define TWE_UNIT_ONLINE 1 - -/* 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:4; - u_int8_t host_id:4; - 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; - -/* - * From 3ware's documentation: - * All parameters maintained by the controller are grouped into related tables. - * Tables are are accessed indirectly via get and set parameter commands. - * To access a specific parameter in a table, the table ID and parameter index - * are used to uniquely identify a parameter. Table 0xffff is the directory - * table and provides a list of the table IDs and sizes of all other tables. - * Index zero in each table specifies the entire table, and index one specifies - * the size of the table. An entire table can be read or set by using index zero. - */ - -#define TWE_PARAM_PARAM_ALL 0 -#define TWE_PARAM_PARAM_SIZE 1 - -#define TWE_PARAM_DIRECTORY 0xffff /* size is 4 * number of tables */ -#define TWE_PARAM_DIRECTORY_TABLES 2 /* 16 bits * number of tables */ -#define TWE_PARAM_DIRECTORY_SIZES 3 /* 16 bits * number of tables */ - -#define TWE_PARAM_DRIVESUMMARY 0x0002 -#define TWE_PARAM_DRIVESUMMARY_Num 2 /* number of physical drives [2] */ -#define TWE_PARAM_DRIVESUMMARY_Status 3 /* array giving drive status per aport */ -#define TWE_PARAM_DRIVESTATUS_Missing 0x00 -#define TWE_PARAM_DRIVESTATUS_NotSupp 0xfe -#define TWE_PARAM_DRIVESTATUS_Present 0xff - -#define TWE_PARAM_UNITSUMMARY 0x0003 -#define TWE_PARAM_UNITSUMMARY_Num 2 /* number of logical units [2] */ -#define TWE_PARAM_UNITSUMMARY_Status 3 /* array giving unit status [16] */ -#define TWE_PARAM_UNITSTATUS_Online (1<<0) -#define TWE_PARAM_UNITSTATUS_Complete (1<<1) -#define TWE_PARAM_UNITSTATUS_MASK 0xfc -#define TWE_PARAM_UNITSTATUS_Normal 0xfc -#define TWE_PARAM_UNITSTATUS_Initialising 0xf4 /* cannot be incomplete */ -#define TWE_PARAM_UNITSTATUS_Degraded 0xec -#define TWE_PARAM_UNITSTATUS_Rebuilding 0xdc /* cannot be incomplete */ -#define TWE_PARAM_UNITSTATUS_Verifying 0xcc /* cannot be incomplete */ -#define TWE_PARAM_UNITSTATUS_Corrupt 0xbc /* cannot be complete */ -#define TWE_PARAM_UNITSTATUS_Missing 0x00 /* cannot be complete or online */ - -#define TWE_PARAM_DRIVEINFO 0x0200 /* add drive number 0x00-0x0f XXX docco confused 0x0100 vs 0x0200 */ -#define TWE_PARAM_DRIVEINFO_Size 2 /* size in blocks [4] */ -#define TWE_PARAM_DRIVEINFO_Model 3 /* drive model string [40] */ -#define TWE_PARAM_DRIVEINFO_Serial 4 /* drive serial number [20] */ -#define TWE_PARAM_DRIVEINFO_PhysCylNum 5 /* physical geometry [2] */ -#define TWE_PARAM_DRIVEINFO_PhysHeadNum 6 /* [2] */ -#define TWE_PARAM_DRIVEINFO_PhysSectorNym 7 /* [2] */ -#define TWE_PARAM_DRIVEINFO_LogCylNum 8 /* logical geometry [2] */ -#define TWE_PARAM_DRIVEINFO_LogHeadNum 9 /* [2] */ -#define TWE_PARAM_DRIVEINFO_LogSectorNum 10 /* [2] */ -#define TWE_PARAM_DRIVEINFO_UnitNum 11 /* unit number this drive is associated with or 0xff [1] */ -#define TWE_PARAM_DRIVEINFO_DriveFlags 12 /* N/A [1] */ - -#define TWE_PARAM_APORTTIMEOUT 0x02c0 /* add (aport_number * 3) to parameter index */ -#define TWE_PARAM_APORTTIMEOUT_READ 2 /* read timeouts last 24hrs [2] */ -#define TWE_PARAM_APORTTIMEOUT_WRITE 3 /* write timeouts last 24hrs [2] */ -#define TWE_PARAM_APORTTIMEOUT_DEGRADE 4 /* degrade threshold [2] */ - -#define TWE_PARAM_UNITINFO 0x0300 /* add unit number 0x00-0x0f */ -#define TWE_PARAM_UNITINFO_Number 2 /* unit number [1] */ -#define TWE_PARAM_UNITINFO_Status 3 /* unit status [1] */ -#define TWE_PARAM_UNITINFO_Capacity 4 /* unit capacity in blocks [4] */ -#define TWE_PARAM_UNITINFO_DescriptorSize 5 /* unit descriptor size + 3 bytes [2] */ -#define TWE_PARAM_UNITINFO_Descriptor 6 /* unit descriptor, TWE_UnitDescriptor or TWE_Array_Descriptor */ -#define TWE_PARAM_UNITINFO_Flags 7 /* unit flags [1] */ -#define TWE_PARAM_UNITFLAGS_WCE (1<<0) - -#define TWE_PARAM_AEN 0x0401 -#define TWE_PARAM_AEN_UnitCode 2 /* (unit number << 8) | AEN code [2] */ -#define TWE_AEN_QUEUE_EMPTY 0x00 -#define TWE_AEN_SOFT_RESET 0x01 -#define TWE_AEN_DEGRADED_MIRROR 0x02 /* reports unit */ -#define TWE_AEN_CONTROLLER_ERROR 0x03 -#define TWE_AEN_REBUILD_FAIL 0x04 /* reports unit */ -#define TWE_AEN_REBUILD_DONE 0x05 /* reports unit */ -#define TWE_AEN_INCOMP_UNIT 0x06 /* reports unit */ -#define TWE_AEN_INIT_DONE 0x07 /* reports unit */ -#define TWE_AEN_UNCLEAN_SHUTDOWN 0x08 /* reports unit */ -#define TWE_AEN_APORT_TIMEOUT 0x09 /* reports unit, rate limited to 1 per 2^16 errors */ -#define TWE_AEN_DRIVE_ERROR 0x0a /* reports unit */ -#define TWE_AEN_REBUILD_STARTED 0x0b /* reports unit */ -#define TWE_AEN_QUEUE_FULL 0xff -#define TWE_AEN_TABLE_UNDEFINED 0x15 -#define TWE_AEN_CODE(x) ((x) & 0xff) -#define TWE_AEN_UNIT(x) ((x) >> 8) - -#define TWE_PARAM_VERSION 0x0402 -#define TWE_PARAM_VERSION_Mon 2 /* monitor version [16] */ -#define TWE_PARAM_VERSION_FW 3 /* firmware version [16] */ -#define TWE_PARAM_VERSION_BIOS 4 /* BIOSs version [16] */ -#define TWE_PARAM_VERSION_PCB 5 /* PCB version [8] */ -#define TWE_PARAM_VERSION_ATA 6 /* A-chip version [8] */ -#define TWE_PARAM_VERSION_PCI 7 /* P-chip version [8] */ -#define TWE_PARAM_VERSION_CtrlModel 8 /* N/A */ -#define TWE_PARAM_VERSION_CtrlSerial 9 /* N/A */ -#define TWE_PARAM_VERSION_SBufSize 10 /* N/A */ -#define TWE_PARAM_VERSION_CompCode 11 /* compatibility code [4] */ - -#define TWE_PARAM_CONTROLLER 0x0403 -#define TWE_PARAM_CONTROLLER_DCBSectors 2 /* # sectors reserved for DCB per drive [2] */ -#define TWE_PARAM_CONTROLLER_PortCount 3 /* number of drive ports [1] */ - -#define TWE_PARAM_FEATURES 0x404 -#define TWE_PARAM_FEATURES_DriverShutdown 2 /* set to 1 if driver supports shutdown notification [1] */ - -typedef struct -{ - u_int8_t num_subunits; /* must be zero */ - u_int8_t configuration; -#define TWE_UD_CONFIG_CBOD 0x0c /* JBOD with DCB, used for mirrors */ -#define TWE_UD_CONFIG_SPARE 0x0d /* same as CBOD, but firmware will use as spare */ -#define TWE_UD_CONFIG_SUBUNIT 0x0e /* drive is a subunit in an array */ -#define TWE_UD_CONFIG_JBOD 0x0f /* plain drive */ - u_int8_t phys_drv_num; /* may be 0xff if port can't be determined at runtime */ - u_int8_t log_drv_num; /* must be zero for configuration == 0x0f */ - u_int32_t start_lba; - u_int32_t block_count; /* actual drive size if configuration == 0x0f, otherwise less DCB size */ -} __packed TWE_Unit_Descriptor; - -typedef struct -{ - u_int8_t flag; /* must be 0xff */ - u_int8_t res1; - u_int8_t mirunit_status[4]; /* bitmap of functional subunits in each mirror */ - u_int8_t res2[6]; -} __packed TWE_Mirror_Descriptor; - -typedef struct -{ - u_int8_t num_subunits; /* number of subunits, or number of mirror units in RAID10 */ - u_int8_t configuration; -#define TWE_UD_CONFIG_RAID0 0x00 -#define TWE_UD_CONFIG_RAID1 0x01 -#define TWE_UD_CONFIG_TwinStor 0x02 -#define TWE_UD_CONFIG_RAID5 0x05 -#define TWE_UD_CONFIG_RAID10 0x06 - u_int8_t stripe_size; -#define TWE_UD_STRIPE_4k 0x03 -#define TWE_UD_STRIPE_8k 0x04 -#define TWE_UD_STRIPE_16k 0x05 -#define TWE_UD_STRIPE_32k 0x06 -#define TWE_UD_STRIPE_64k 0x07 - u_int8_t log_drv_status; /* bitmap of functional subunits, or mirror units in RAID10 */ - u_int32_t start_lba; - u_int32_t block_count; /* actual drive size if configuration == 0x0f, otherwise less DCB size */ - TWE_Unit_Descriptor subunit[0]; /* subunit descriptors, in RAID10 mode is [mirunit][subunit] */ -} __packed TWE_Array_Descriptor; - -typedef struct -{ - u_int16_t table_id; - u_int8_t parameter_id; - u_int8_t parameter_size_bytes; - u_int8_t data[0]; -} __packed TWE_Param; - diff --git a/sm5/utility.c b/sm5/utility.c deleted file mode 100644 index f1e54ee89ce5e0fd83344f45ad9726d8b28aef74..0000000000000000000000000000000000000000 --- a/sm5/utility.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * utility.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 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 <stdio.h> -#include <string.h> -#include <time.h> -#include <errno.h> -#include <stdlib.h> -#include <ctype.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/stat.h> - -#include "config.h" -#include "int64.h" -#include "utility.h" - -// Any local header files should be represented by a CVSIDX just below. -const char* utility_c_cvsid="$Id: utility.c,v 1.53 2004/07/29 21:00:36 chrfranke Exp $" -CONFIG_H_CVSID INT64_H_CVSID UTILITY_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" -}; - -// Whenever exit() status is EXIT_BADCODE, please print this message -const char *reportbug="Please report this bug to the Smartmontools developers at " PACKAGE_BUGREPORT ".\n"; - - -// hang on to exit code, so we can make use of more generic 'atexit()' -// functionality and still check our exit code -int exitstatus = 0; - -// command-line argument: are we running in debug mode?. -unsigned char debugmode = 0; - - -// 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("TZ=GMT"); - tzset(); - putenv("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; -} - -// 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"; -} - - -// Returns 1 if machine is big endian, else zero. This is a run-time -// rather than a compile-time function. We could do it at -// compile-time but in principle there are architectures that can run -// with either byte-ordering. -int isbigendian(){ - short i=0x0100; - char *tmp=(char *)&i; - return *tmp; -} - -// 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; - char *timezonename; - char datebuffer[DATEANDEPOCHLEN]; - int lenm1; - - 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=""; - - // 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; -} - -// These are two utility functions for printing CVS IDs. Massagecvs() -// returns distance that it has moved ahead in the input string -int massagecvs(char *out, const char *cvsid){ - char *copy,*filename,*date,*version; - int retVal=0; - const char delimiters[] = " ,$"; - - // make a copy on the heap, go to first token, - if (!(copy=strdup(cvsid))) - return 0; - - if (!(filename=strtok(copy, delimiters))){ - free(copy); - return 0; - } - - // move to first instance of "Id:" - while (strcmp(filename,"Id:")) - if (!(filename=strtok(NULL, delimiters))){ - free(copy); - return 0; - } - - // get filename, skip "v", get version and date - if (!( filename=strtok(NULL, delimiters) ) || - !( strtok(NULL, delimiters) ) || - !( version=strtok(NULL, delimiters) ) || - !( date=strtok(NULL, delimiters) ) ) { - free(copy); - return 0; - } - - sprintf(out,"%-16s revision: %-5s date: %-15s", filename, version, date); - retVal = (date-copy)+strlen(date); - free(copy); - return retVal; -} - -// prints a single set of CVS ids -void printone(char *block, const char *cvsid){ - char strings[CVSMAXLEN]; - const char *here=cvsid; - int line=1,len=strlen(cvsid)+1; - - // check that the size of the output block is sufficient - if (len>=CVSMAXLEN) { - pout("CVSMAXLEN=%d must be at least %d\n",CVSMAXLEN,len+1); - EXIT(1); - } - - // loop through the different strings - while ((len=massagecvs(strings,here))){ - switch (line++){ - case 1: - block+=snprintf(block,CVSMAXLEN,"Module:"); - break; - default: - block+=snprintf(block,CVSMAXLEN," uses:"); - } - block+=snprintf(block,CVSMAXLEN," %s\n",strings); - here+=len; - } - return; -} - - -// A replacement for perror() that sends output to our choice of -// printing. -void syserror(const char *message){ - const char *errormessage; - - // Get the correct system error message: - 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); - - return; -} - -// Prints a warning message for a failed regular expression compilation from -// regcomp(). -void printregexwarning(int errcode, regex_t *compiled){ - size_t length = regerror(errcode, compiled, NULL, 0); - char *buffer = malloc(length); - if (!buffer){ - pout("Out of memory in printregexwarning()\n"); - return; - } - regerror(errcode, compiled, buffer, length); - pout("%s\n", buffer); - free(buffer); - return; -} - -// A wrapper for regcomp(). Returns zero for success, non-zero otherwise. -int compileregex(regex_t *compiled, const char *pattern, int cflags) -{ - int errorcode; - - if ((errorcode = regcomp(compiled, pattern, cflags))) { - pout("Internal error: unable to compile regular expression %s", pattern); - printregexwarning(errorcode, compiled); - pout("Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n"); - return 1; - } - return 0; -} - -// 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; -} - -// same as above but sets *i to -1 if missing , argument -int split_report_arg2(char *s, int *i){ - char *tailptr; - s+=6; - - if (*s=='\0' || !isdigit((int)*s)) { - // What's left must be integer - *i=-1; - return 1; - } - - errno = 0; - *i = (int) strtol(s, &tailptr, 10); - if (errno || *tailptr != '\0') { - *i=-1; - return 1; - } - - return 0; -} - -#ifndef HAVE_STRTOULL -// Replacement for missing strtoull() (Linux with libc < 6, MSVC 6.0) -// Functionality reduced to split_selective_arg()'s requirements. - -static uint64_t strtoull(const char * p, char * * endp, int base) -{ - uint64_t result, maxres; - int i = 0; - char c = p[i++]; - // assume base == 0 - 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++]; - } - *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) -{ - char *tailptr; - - if (!(s = strchr(s, ','))) - return 1; - if (!isdigit((int)(*++s))) - return 1; - 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; - if (errno || *s++ != '-') - return 1; - *stop = strtoull(s, &tailptr, 0); - if (errno || *tailptr != '\0') - return 1; - return 0; -} - -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 *FreeNonZero(void *address, int size, int line, const char* file){ - if (address) { - if (size<0) - bytes-=1+strlen(address); - else - bytes-=size; - return CheckFree(address, line, file); - } - return NULL; -} - -// To help with memory checking. Use when it is known that address is -// NOT null. -void *CheckFree(void *address, int whatline, const char* file){ - if (address){ - free(address); - return NULL; - } - - PrintOut(LOG_CRIT, "Internal error in CheckFree() at line %d of file %s\n%s", - whatline, file, reportbug); - EXIT(EXIT_BADCODE); -} - -// 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(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) { - PrintOut(LOG_CRIT, "Internal error in CustomStrDup() at line %d of file %s\n%s", - whatline, file, reportbug); - EXIT(EXIT_BADCODE); - } - else - return NULL; - } - - // make a copy of the string... - tmp=strdup(ptr); - - if (!tmp) { - PrintOut(LOG_CRIT, "No memory to duplicate string %s at line %d of file %s\n", ptr, whatline, file); - EXIT(EXIT_NOMEM); - } - - // and track memory usage - bytes+=1+strlen(ptr); - - return tmp; -} - -// Returns nonzero if region of memory contains non-zero entries -int nonempty(unsigned char *testarea,int n){ - int i; - for (i=0;i<n;i++) - if (testarea[i]) - return 1; - return 0; -} - - -// This routine converts an integer number of milliseconds into a test -// string of the form Xd+Yh+Zm+Ts.msec. The resulting text string is -// written to the array. -void MsecToText(unsigned int msec, char *txt){ - int start=0; - unsigned int days, hours, min, sec; - - days = msec/86400000U; - msec -= days*86400000U; - - hours = msec/3600000U; - msec -= hours*3600000U; - - min = msec/60000U; - msec -= min*60000U; - - sec = msec/1000U; - msec -= sec*1000U; - - if (days) { - txt += sprintf(txt, "%2dd+", (int)days); - start=1; - } - - sprintf(txt, "%02d:%02d:%02d.%03d", (int)hours, (int)min, (int)sec, (int)msec); - return; -} - - - diff --git a/sm5/utility.cpp b/sm5/utility.cpp deleted file mode 100644 index 57e862049a9993486be30320288f8b01f6ab599b..0000000000000000000000000000000000000000 --- a/sm5/utility.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* - * utility.c - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 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 <stdio.h> -#include <string.h> -#include <time.h> -#include <errno.h> -#include <stdlib.h> -#include <ctype.h> -#include <syslog.h> -#include <stdarg.h> -#include <sys/stat.h> - -#include "config.h" -#include "int64.h" -#include "utility.h" - -// Any local header files should be represented by a CVSIDX just below. -const char* utility_c_cvsid="$Id: utility.cpp,v 1.53 2004/07/29 21:00:36 chrfranke Exp $" -CONFIG_H_CVSID INT64_H_CVSID UTILITY_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" -}; - -// Whenever exit() status is EXIT_BADCODE, please print this message -const char *reportbug="Please report this bug to the Smartmontools developers at " PACKAGE_BUGREPORT ".\n"; - - -// hang on to exit code, so we can make use of more generic 'atexit()' -// functionality and still check our exit code -int exitstatus = 0; - -// command-line argument: are we running in debug mode?. -unsigned char debugmode = 0; - - -// 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("TZ=GMT"); - tzset(); - putenv("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; -} - -// 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"; -} - - -// Returns 1 if machine is big endian, else zero. This is a run-time -// rather than a compile-time function. We could do it at -// compile-time but in principle there are architectures that can run -// with either byte-ordering. -int isbigendian(){ - short i=0x0100; - char *tmp=(char *)&i; - return *tmp; -} - -// 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; - char *timezonename; - char datebuffer[DATEANDEPOCHLEN]; - int lenm1; - - 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=""; - - // 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; -} - -// These are two utility functions for printing CVS IDs. Massagecvs() -// returns distance that it has moved ahead in the input string -int massagecvs(char *out, const char *cvsid){ - char *copy,*filename,*date,*version; - int retVal=0; - const char delimiters[] = " ,$"; - - // make a copy on the heap, go to first token, - if (!(copy=strdup(cvsid))) - return 0; - - if (!(filename=strtok(copy, delimiters))){ - free(copy); - return 0; - } - - // move to first instance of "Id:" - while (strcmp(filename,"Id:")) - if (!(filename=strtok(NULL, delimiters))){ - free(copy); - return 0; - } - - // get filename, skip "v", get version and date - if (!( filename=strtok(NULL, delimiters) ) || - !( strtok(NULL, delimiters) ) || - !( version=strtok(NULL, delimiters) ) || - !( date=strtok(NULL, delimiters) ) ) { - free(copy); - return 0; - } - - sprintf(out,"%-16s revision: %-5s date: %-15s", filename, version, date); - retVal = (date-copy)+strlen(date); - free(copy); - return retVal; -} - -// prints a single set of CVS ids -void printone(char *block, const char *cvsid){ - char strings[CVSMAXLEN]; - const char *here=cvsid; - int line=1,len=strlen(cvsid)+1; - - // check that the size of the output block is sufficient - if (len>=CVSMAXLEN) { - pout("CVSMAXLEN=%d must be at least %d\n",CVSMAXLEN,len+1); - EXIT(1); - } - - // loop through the different strings - while ((len=massagecvs(strings,here))){ - switch (line++){ - case 1: - block+=snprintf(block,CVSMAXLEN,"Module:"); - break; - default: - block+=snprintf(block,CVSMAXLEN," uses:"); - } - block+=snprintf(block,CVSMAXLEN," %s\n",strings); - here+=len; - } - return; -} - - -// A replacement for perror() that sends output to our choice of -// printing. -void syserror(const char *message){ - const char *errormessage; - - // Get the correct system error message: - 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); - - return; -} - -// Prints a warning message for a failed regular expression compilation from -// regcomp(). -void printregexwarning(int errcode, regex_t *compiled){ - size_t length = regerror(errcode, compiled, NULL, 0); - char *buffer = malloc(length); - if (!buffer){ - pout("Out of memory in printregexwarning()\n"); - return; - } - regerror(errcode, compiled, buffer, length); - pout("%s\n", buffer); - free(buffer); - return; -} - -// A wrapper for regcomp(). Returns zero for success, non-zero otherwise. -int compileregex(regex_t *compiled, const char *pattern, int cflags) -{ - int errorcode; - - if ((errorcode = regcomp(compiled, pattern, cflags))) { - pout("Internal error: unable to compile regular expression %s", pattern); - printregexwarning(errorcode, compiled); - pout("Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n"); - return 1; - } - return 0; -} - -// 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; -} - -// same as above but sets *i to -1 if missing , argument -int split_report_arg2(char *s, int *i){ - char *tailptr; - s+=6; - - if (*s=='\0' || !isdigit((int)*s)) { - // What's left must be integer - *i=-1; - return 1; - } - - errno = 0; - *i = (int) strtol(s, &tailptr, 10); - if (errno || *tailptr != '\0') { - *i=-1; - return 1; - } - - return 0; -} - -#ifndef HAVE_STRTOULL -// Replacement for missing strtoull() (Linux with libc < 6, MSVC 6.0) -// Functionality reduced to split_selective_arg()'s requirements. - -static uint64_t strtoull(const char * p, char * * endp, int base) -{ - uint64_t result, maxres; - int i = 0; - char c = p[i++]; - // assume base == 0 - 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++]; - } - *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) -{ - char *tailptr; - - if (!(s = strchr(s, ','))) - return 1; - if (!isdigit((int)(*++s))) - return 1; - 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; - if (errno || *s++ != '-') - return 1; - *stop = strtoull(s, &tailptr, 0); - if (errno || *tailptr != '\0') - return 1; - return 0; -} - -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 *FreeNonZero(void *address, int size, int line, const char* file){ - if (address) { - if (size<0) - bytes-=1+strlen(address); - else - bytes-=size; - return CheckFree(address, line, file); - } - return NULL; -} - -// To help with memory checking. Use when it is known that address is -// NOT null. -void *CheckFree(void *address, int whatline, const char* file){ - if (address){ - free(address); - return NULL; - } - - PrintOut(LOG_CRIT, "Internal error in CheckFree() at line %d of file %s\n%s", - whatline, file, reportbug); - EXIT(EXIT_BADCODE); -} - -// 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(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) { - PrintOut(LOG_CRIT, "Internal error in CustomStrDup() at line %d of file %s\n%s", - whatline, file, reportbug); - EXIT(EXIT_BADCODE); - } - else - return NULL; - } - - // make a copy of the string... - tmp=strdup(ptr); - - if (!tmp) { - PrintOut(LOG_CRIT, "No memory to duplicate string %s at line %d of file %s\n", ptr, whatline, file); - EXIT(EXIT_NOMEM); - } - - // and track memory usage - bytes+=1+strlen(ptr); - - return tmp; -} - -// Returns nonzero if region of memory contains non-zero entries -int nonempty(unsigned char *testarea,int n){ - int i; - for (i=0;i<n;i++) - if (testarea[i]) - return 1; - return 0; -} - - -// This routine converts an integer number of milliseconds into a test -// string of the form Xd+Yh+Zm+Ts.msec. The resulting text string is -// written to the array. -void MsecToText(unsigned int msec, char *txt){ - int start=0; - unsigned int days, hours, min, sec; - - days = msec/86400000U; - msec -= days*86400000U; - - hours = msec/3600000U; - msec -= hours*3600000U; - - min = msec/60000U; - msec -= min*60000U; - - sec = msec/1000U; - msec -= sec*1000U; - - if (days) { - txt += sprintf(txt, "%2dd+", (int)days); - start=1; - } - - sprintf(txt, "%02d:%02d:%02d.%03d", (int)hours, (int)min, (int)sec, (int)msec); - return; -} - - - diff --git a/sm5/utility.h b/sm5/utility.h deleted file mode 100644 index 6eb82431307cae2d1033d004bf1ba137a8a3e004..0000000000000000000000000000000000000000 --- a/sm5/utility.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * utility.h - * - * Home page of code is: http://smartmontools.sourceforge.net - * - * Copyright (C) 2002-4 Bruce Allen <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., 675 Mass Ave, Cambridge, MA 02139, 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 UTILITY_H_ -#define UTILITY_H_ - -#define UTILITY_H_CVSID "$Id: utility.h,v 1.37 2004/08/16 22:44:28 ballen4705 Exp $\n" - -#include <time.h> -#include <sys/types.h> // for regex.h (according to POSIX) -#include <regex.h> - -#include "int64.h" - -#if defined(_WIN32) && defined(_MSC_VER) -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#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); - -// utility function for printing out CVS strings -#define CVSMAXLEN 1024 -void printone(char *block, const char *cvsid); - -// 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. -#ifndef __GNUC__ -#define __attribute__(x) /* nothing */ -#endif -void pout(char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -// replacement for perror() with redirected output. -void syserror(const char *message); - -// Prints a warning message for a failed regular expression compilation from -// regcomp(). -void printregexwarning(int errcode, regex_t *compiled); - -// A wrapper for regcomp(). Returns zero for success, non-zero otherwise. -int compileregex(regex_t *compiled, const char *pattern, int cflags); - -// Function for processing -r option in smartctl and smartd -int split_report_arg(char *s, int *i); -// Function for processing -c option in smartctl and smartd -int split_report_arg2(char *s, int *i); -// Function for processing -t selective... option in smartctl -int split_selective_arg(char *s, uint64_t *start, uint64_t *stop); - - -// Guess device type (ata or scsi) based on device name -// Guessing will now use Controller Type defines below - -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 -int make_device_names (char ***devlist, const char* name); - - -#define EXIT(x) { exitstatus = (x); exit((x)); } - -// replacement for calloc() that tracks memory usage -void *Calloc(size_t nmemb, size_t size); - -// Utility function to free memory -void *FreeNonZero(void* address, int size, int whatline, const char* 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(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 *CheckFree(void *address, int whatline, const char* file); - -// This function prints either to stdout or to the syslog as needed - -// [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 PrintOut(int priority,char *fmt, ...); - -// run time, determine byte ordering -int isbigendian(); - -// 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); - -int deviceopen(const char *pathname, char *type); - -int deviceclose(int fd); - -// returns 1 if any of the n bytes are nonzero, else zero. -int nonempty(unsigned char *testarea,int n); - -// needed to fix glibc bug -void FixGlibcTimeZoneBug(); - -// convert time in msec to a text string -void MsecToText(unsigned int msec, char *txt); - -// 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 - - -// macros to control printing -#define PRINT_ON(control) {if (control->printing_switchable) control->dont_print=0;} -#define PRINT_OFF(control) {if (control->printing_switchable) control->dont_print=1;} - -// possible values for controller_type in extern.h -#define CONTROLLER_UNKNOWN 0x00 -#define CONTROLLER_ATA 0x01 -#define CONTROLLER_SCSI 0x02 -#define CONTROLLER_3WARE 0x03 // set by -d option, but converted to one of three types below -#define CONTROLLER_3WARE_678K 0x04 // NOT set by guess_device_type() -#define CONTROLLER_3WARE_9000_CHAR 0x05 // set by guess_device_type() -#define CONTROLLER_3WARE_678K_CHAR 0x06 // set by guess_device_type() - -#endif diff --git a/www/3w-xxxx.txt b/www/3w-xxxx.txt deleted file mode 100644 index 5dde49c574c8ad84e69d89797ceeea17115f68e6..0000000000000000000000000000000000000000 --- a/www/3w-xxxx.txt +++ /dev/null @@ -1,157 +0,0 @@ ---------------------------------------------------------------------------- -# November 27, 2003 -# -# This patch is now against the official 3ware version 1.02.00.036 3w-xxxx.c driver -# dated Wed Jul 16 20:30:28 2003. Instructions for use: -# -# [1] download the 1.02.00.036 3w-xxxx.c driver from -# http://www.3ware.com/support/download.asp -# -# [2] Unpack it: -# tar zxvf rh7x_8x.tgz (or su7x_8x.tgz for SuSE) -# -# [3] Unpack the source code, and move to the right directory: -# cd src/2.4 -# tar zxvf 3w-xxxx.tgz -# cd driver -# -# [4] Copy THIS FILE (what you are reading!) into that -# directory and name it 3w-xxxx.txt -# -# [5] Patch the driver: -# patch < 3w-xxxx.txt -# You should get the response 'patching file 3w-xxxx.c'. -# -# [6] Build the driver with the command: -# make -# This will create the driver: a file named 3w-xxxx.o -# -# [7] Load the driver (you must be root to do this): -# /sbin/insmod ./3w-xxxx.o -# [Note: if '/sbin/lsmod' shows that the driver is loaded already, -# then unmount any file systems that use it, then unload the driver -# with '/sbin/rmmod 3w-xxxx' first!] -# -# [8] Copy the driver into place in the kernel tree: -# cp ./3w-xxxx.o /lib/modules/`uname -r`/kernel/drivers/scsi -# That's it! -# -# August 14, 2003 -# -# Adam Radford has incorporated a change that now allows the 3w-xxxx -# driver to return the Cylinder Low/High values. These are needed to -# get the SMART health status. This patch incorporates those changes -# as well. -# -# August 12, 2003 -# -# 3ware has incorporated a more general version of this fix into their latest -# 3w-xxxx driver release. Rather than using this patch, you can upgrade your -# 3w-xxxx driver to version 1.02.00.037 or greater. Or you can use this patch. -# -# August 8, 2003 -# PATCH FOR 3WARE 3w-xxxx DRIVER -# Bruce Allen ballen at gravity.phys.uwm.edu -# CVS ID of this file: $Id: 3w-xxxx.txt,v 1.5 2003/11/28 17:58:50 ballen4705 Exp $ -# -# To apply this patch, save this entire file to 3w-xxxx.txt in a -# directory containing the original unpatched 3w-xxxx.c file. Then -# given the command: -# patch < 3w-xxxx.txt -# That's it! -# -# TECHNICAL EXPLANATION OF THE PATCH FOLLOWS. SKIP IT IF YOU DON'T CARE. -# -# The 3w-xxxx SCSI RAID driver for 3ware Escalade controller cards has a bug -# in the "passthru" ioctl() which prevents two SMART commands from being -# passed to the ATA devices behind the controller. The commands are: -# -# SMART ENABLE/DISABLE ATTRIBUTE AUTOSAVE -# (Command Register=0xB0/Feature Register=0xD2) -# -# SMART ENABLE/DISABLE AUTOMATIC OFF-LINE -# (Command Register=0xB0/Feature Register=0xDB) -# -# [Note: the second of these commands is listed as "Obsolete" in the ATA -# specifications. It was originally defined in SFF-8035i. Most vendors -# (IBM/Hitachi, Maxtor, Samsung, WD, among others) still implement it for -# backwards compatibility.] -# -# The problem arises because in both cases (stupidly!) the ENABLE subcommand -# is indicated with a nonzero value of the Sector Count Register. For the -# AUTOSAVE command one uses Sector Count Register=0xF1 and for the AUTOMATIC -# OFF-LINE command one uses Sector Count Register=0xF8. -# -# This provokes the following error messages from the 3w-xxxx driver: -# 3w-xxxx: tw_ioctl(): Passthru size (123392) too big. -# 3w-xxxx: tw_ioctl(): Passthru size (126976) too big. -# and the driver doesn't pass the ATA command on. This is because the -# passthru part of the 3w-xxxx driver assumes that the value in the Sector -# Count Register is the number of 512-byte blocks to transfer, and these -# values exceed the internal buffer sizes. -# -# In fact both of these are non-data commands, and so this is trivial to -# fix. I am attaching an 8-line patch for this purpose. It looks for these -# particular commands and then treats them as non-data commands. It has been -# tested on both a 6800 and a 7500 controller, and should be endian-order -# and 32/64-bit clean. -# -# [Note: the normal linux ide drivers also assume that the Sector Count -# Register is the number of 512-byte sectors to transfer to user space. -# But in that case the user can simply allocate a userland buffer large -# enough to hold the 0xf1*0x200 or 0xf8*0x200 bytes, and then ignore the -# contents.] -# -# ----------------------------------------------------------------------- - ---- 3w-xxxx.c.orig Wed Jul 16 20:30:28 2003 -+++ 3w-xxxx.c Thu Nov 27 11:20:25 2003 -@@ -173,6 +173,9 @@ - 1.02.00.035 - Improve tw_allocate_memory() memory allocation. - Fix tw_chrdev_ioctl() to sleep correctly. - 1.02.00.036 - Increase character ioctl timeout to 60 seconds. -+ -+ This version 1.02.00.036 3w-xxxx.c driver has been patched for full smartmontools support. -+ - */ - - #include <linux/module.h> -@@ -1930,12 +1933,15 @@ - } - - passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id]; -- passthru->sg_list[0].length = passthru->sector_count*512; -- if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) { -- printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length); -- return 1; -+ /* Don't load sg_list for non-data ATA cmds */ -+ if ((passthru->param != 0) && (passthru->param != 0x8)) { -+ passthru->sg_list[0].length = passthru->sector_count*512; -+ if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) { -+ printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length); -+ return 1; -+ } -+ passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id]; - } -- passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id]; - tw_post_command_packet(tw_dev, request_id); - return 0; - case TW_CMD_PACKET: -@@ -2185,8 +2191,15 @@ - ioctl = (TW_Ioctl *)buff; - switch (ioctl->opcode) { - case TW_ATA_PASSTHRU: -- passthru = (TW_Passthru *)ioctl->data; -- memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); -+ passthru = (TW_Passthru *)ioctl->data; -+ /* Don't return data for non-data ATA cmds */ -+ if ((passthru->param != 0) && (passthru->param != 0x8)) -+ memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); -+ else { -+ /* For non-data cmds, return cmd pkt */ -+ if (tw_dev->srb[request_id]->request_bufflen >= sizeof(TW_Command)) -+ memcpy(buff, tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command)); -+ } - break; - case TW_CMD_PACKET_WITH_DATA: - dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n"); diff --git a/www/BadBlockHowTo.txt b/www/BadBlockHowTo.txt deleted file mode 100644 index f9782784634f6c5e9fcaa010ff9da865b6a3e3e5..0000000000000000000000000000000000000000 --- a/www/BadBlockHowTo.txt +++ /dev/null @@ -1,316 +0,0 @@ -THIS DOCUMENT SHOWS HOW TO IDENTIFY THE FILE ASSOCIATED WITH AN -UNREADABLE DISK SECTOR, AND HOW TO FORCE THAT SECTOR TO REALLOCATE. - -Assumptions: Linux OS, ext2 or ext3 file system. - -Bruce Allen <smartmontools-support@lists.sourceforge.net> - -Thanks to Sergey Vlasov, Theodore Ts'o, Michael Bendzick, and others -for explaining this to me. I would like to add text showing how to do -this for other file systems, in particular ReiserFS, XFS, and JFS: -please email me if you can provide this information. - - - -In this example, the disk is failing self-tests at Logical Block -Address LBA = 0x016561e9 = 23421417. The LBA counts sectors in units -of 512 bytes, and starts at zero. - ------------------------------------------------------------------------------------------------ -root]# smartctl -l selftest /dev/hda: - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed: read failure 90% 217 0x016561e9 ------------------------------------------------------------------------------------------------ - -Note that other signs that there is a bad sector on the disk can be -found in the non-zero value of the Current Pending Sector count: ------------------------------------------------------------------------------------------------ -root]# smartctl -A /dev/hda -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 1 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 1 ------------------------------------------------------------------------------------------------ - -First Step: We need to locate the partition on which this sector of -the disk lives: ------------------------------------------------------------------------------------------------ -root]# fdisk -lu /dev/hda - -Disk /dev/hda: 123.5 GB, 123522416640 bytes -255 heads, 63 sectors/track, 15017 cylinders, total 241254720 sectors -Units = sectors of 1 * 512 = 512 bytes - - Device Boot Start End Blocks Id System -/dev/hda1 * 63 4209029 2104483+ 83 Linux -/dev/hda2 4209030 5269319 530145 82 Linux swap -/dev/hda3 5269320 238227884 116479282+ 83 Linux -/dev/hda4 238227885 241248104 1510110 83 Linux ------------------------------------------------------------------------------------------------ - -The partition /dev/hda3 starts at LBA 5269320 and extends past the -'problem' LBA. The 'problem' LBA is offset 23421417 - 5269320 = -18152097 sectors into the partition /dev/hda3. - -To verify the type of the file system and the mount point, look in -/etc/fstab: ------------------------------------------------------------------------------------------------ -root]# grep hda3 /etc/fstab -/dev/hda3 /data ext2 defaults 1 2 ------------------------------------------------------------------------------------------------ -You can see that this is an ext2 file system, mounted at /data. - -Second Step: we need to find the blocksize of the file system -(normally 4096 bytes for ext2): ------------------------------------------------------------------------------------------------ -root]# tune2fs -l /dev/hda3 | grep Block -Block count: 29119820 -Block size: 4096 ------------------------------------------------------------------------------------------------ -In this case the block size is 4096 bytes. - -Third Step: we need to determine which File System Block contains this -LBA. The formula is: - b = (int)((L-S)*512/B) -where: -b = File System block number -B = File system block size in bytes -L = LBA of bad sector -S = Starting sector of partition as shown by fdisk -lu -and (int) denotes the integer part. - -In our example, L=23421417, S=5269320, and B=4096. Hence the -'problem' LBA is in block number - b = (int)18152097*512/4096 = (int)2269012.125 -so b=2269012. - -Note: the fractional part of 0.125 indicates that this problem LBA is -actually the second of the eight sectors that make up this file system -block. - -Fourth Step: we use debugfs to locate the inode stored in this block, -and the file that contains that inode: ------------------------------------------------------------------------------------------------ -root]# debugfs -debugfs 1.32 (09-Nov-2002) -debugfs: open /dev/hda3 -debugfs: icheck 2269012 -Block Inode number -2269012 41032 -debugfs: ncheck 41032 -Inode Pathname -41032 /S1/R/H/714197568-714203359/H-R-714202192-16.gwf ------------------------------------------------------------------------------------------------ - -In this example, you can see that the problematic file (with the mount -point included in the path) is: -/data/S1/R/H/714197568-714203359/H-R-714202192-16.gwf - - -To force the disk to reallocate this bad block we'll write zeros to -the bad block, and sync the disk: ------------------------------------------------------------------------------------------------ -root]# dd if=/dev/zero of=/dev/hda3 bs=4096 count=1 seek=2269012 -root]# sync ------------------------------------------------------------------------------------------------ - -NOTE: THIS LAST STEP HAS PERMANENTLY AND IRRETREVIABLY DESTROYED SOME -OF THE DATA THAT WAS IN THIS FILE. DON'T DO THIS UNLESS YOU DON'T -NEED THE FILE OR YOU CAN REPLACE IT WITH A FRESH OR CORRECT VERSION. - - -Now everything is back to normal: the sector has been reallocated. -Compare the output just below to similar output near the top of this -article: ------------------------------------------------------------------------------------------------ -root]# smartctl -A /dev/hda -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 1 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 1 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 1 ------------------------------------------------------------------------------------------------ - -Note: for some disks it may be necessary to update the SMART Attribute values by using -smartctl -t offline /dev/hda - -The disk now passes its self-tests again: - ------------------------------------------------------------------------------------------------ -root]# smartctl -t long /dev/hda [wait until test completes, then] -root]# smartctl -l selftest /dev/hda - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed without error 00% 239 - -# 2 Extended offline Completed: read failure 90% 217 0x016561e9 -# 3 Extended offline Completed: read failure 90% 212 0x016561e9 -# 4 Extended offline Completed: read failure 90% 181 0x016561e9 -# 5 Extended offline Completed without error 00% 14 - -# 6 Extended offline Completed without error 00% 4 - ------------------------------------------------------------------------------------------------ - -and no longer shows any offline uncorrectable sectors: - ------------------------------------------------------------------------------------------------ -root]# smartctl -A /dev/hda -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 1 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 1 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 0 ------------------------------------------------------------------------------------------------ - - - -A SECOND EXAMPLE - -On this drive, the first sign of trouble was this email from smartd: - - To: ballen - Subject: SMART error (selftest) detected on host: medusa-slave166.medusa.phys.uwm.edu - - This email was generated by the smartd daemon running on host: - medusa-slave166.medusa.phys.uwm.edu in the domain: master001-nis - - The following warning/error was logged by the smartd daemon: - Device: /dev/hda, Self-Test Log error count increased from 0 to 1 - - -Running smartctl -a /dev/hda confirmed the problem: - -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed: read failure 80% 682 0x021d9f44 - -Note that the failing LBA reported is 0x021d9f44 (base 16) = 35495748 (base 10) - -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 3 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 3 - -and one can see above that there are 3 sectors on the list of pending -sectors that the disk can't read but would like to reallocate. - -The device also shows errors in the SMART error log: - -Error 212 occurred at disk power-on lifetime: 690 hours - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 12 46 9f 1d e2 Error: UNC 18 sectors at LBA = 0x021d9f46 = 35495750 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 25 00 12 46 9f 1d e0 00 2485545.000 READ DMA EXT - -Signs of trouble at this LBA may also be found in SYSLOG: - -[root]# grep LBA /var/log/messages | awk '{print $12}' | sort | uniq - LBAsect=35495748 - LBAsect=35495750 - -So I decide to do a quick check to see how many bad sectors there -really are. Using the bash shell I check 70 sectors around the trouble -area: - -[root]# export i=35495730 -[root]# while [ $i -lt 35495800 ] - > do echo $i - > dd if=/dev/hda of=/dev/null bs=512 count=1 skip=$i - > let i+=1 - > done - -<SNIP> - -35495734 -1+0 records in -1+0 records out -35495735 -dd: reading `/dev/hda': Input/output error -0+0 records in -0+0 records out - -<SNIP> - -35495751 -dd: reading `/dev/hda': Input/output error -0+0 records in -0+0 records out -35495752 -1+0 records in -1+0 records out - -<SNIP> - -which shows that the seventeen sectors 35495735-35495751 (inclusive) -are not readable. - -Next, we identify the files at those locations. The partitioning -information on this disk is identical to the first example above, and -as in that case the problem sectors are on the third partition -/dev/hda3. So we have: - L=35495735 to 35495751 - S=5269320 - B=4096 -so that b=3778301 to 3778303 are the three bad blocks in the file -system. - -[root]# debugfs -debugfs 1.32 (09-Nov-2002) -debugfs: open /dev/hda3 -debugfs: icheck 3778301 -Block Inode number -3778301 45192 -debugfs: icheck 3778302 -Block Inode number -3778302 45192 -debugfs: icheck 3778303 -Block Inode number -3778303 45192 -debugfs: ncheck 45192 -Inode Pathname -45192 /S1/R/H/714979488-714985279/H-R-714979984-16.gwf -debugfs: quit - -And finally, just to confirm that this is really the damaged file: - -[root]# md5sum /data/S1/R/H/714979488-714985279/H-R-714979984-16.gwf -md5sum: /data/S1/R/H/714979488-714985279/H-R-714979984-16.gwf: Input/output error - -Finally we force the disk to reallocate the three bad blocks: -[root]# dd if=/dev/zero of=/dev/hda3 bs=4096 count=3 seek=3778301 -[root]# sync - -We could also probably use: -[root]# dd if=/dev/zero of=/dev/hda bs=512 count=17 seek=35495735 - -At this point we now have: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 0 - -which is encouraging, since the pending sectors count is now zero. -Note that the drive reallocation count has not yet increased: the -drive may now have confidence in these sectors and have decided not to -reallocate them.. - -A device self test: - [root#] smartctl -t long /dev/hda -(then wait about an hour) shows no unreadable sectors or errors: - -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed without error 00% 692 - -# 2 Extended offline Completed: read failure 80% 682 0x021d9f44 - -This document is version $Id: BadBlockHowTo.txt,v 1.4 2004/03/21 20:38:32 ballen4705 Exp $ -It is Copyright Bruce Allen (2004) and distributed under GPL2. - - diff --git a/www/FAQ.xml b/www/FAQ.xml deleted file mode 100644 index 51fd9fbbd56e1bc1cdc6e5504cfa9dfe6b6e8923..0000000000000000000000000000000000000000 --- a/www/FAQ.xml +++ /dev/null @@ -1,543 +0,0 @@ -<?xml version='1.0' encoding='ISO-8859-1'?> -<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" > - -<!-- -Layout borrowed from Doug's smartmontools_scsi.xml. The following text -is also from his file. - -This is DocBook XML that can be rendered into a single HTML page with a -command like 'xmlto html-nochunks <this_file_name>'. It can also be -rendered into multi-page HTML (drop the "-nochunks") or pdf, ps, txt, -etc. ---> - -<article id="index"> - <articleinfo> - <title>FAQ - Frequently Asked Questions</title> - <author> - <firstname>smartmontools</firstname> - <surname>developers</surname> - <affiliation> - <address> - <email>smartmontools-support@lists.sourceforge.net</email> - </address> - </affiliation> - </author> - <authorinitials>sd</authorinitials> - <pubdate>2003-09-24</pubdate> - - <revhistory> - <revision> - <revnumber>1.0</revnumber> - <date>2003-10-22</date> - <authorinitials>sd</authorinitials> - <revremark> - Moved from index.html to XML - </revremark> - </revision> - </revhistory> - - <copyright> - <year>2003</year> - <holder>Bruce Allen</holder> - </copyright> - - <legalnotice> - <para> - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free Documentation License, - Version 1.1 or any later version published by the Free Software - Foundation; with no Invariant Sections, with no Front-Cover Texts, - and with no Back-Cover Texts. - </para> - <para> - For an online copy of the license see - <ulink url="http://www.fsf.org/copyleft/fdl.html"> - <literal>http://www.fsf.org/copyleft/fdl.html</literal></ulink> . - </para> - - </legalnotice> - - <abstract> - <para> - FAQ - Frequently Asked Questions - </para> - </abstract> - </articleinfo> - -<!-- -<toc></toc> ---> - - -<sect1 id="a"> - -<title>What do I do if I have problems, or need support? Suppose I want -to become a developer, or suggest some new extensions?</title> - -<para>First, search the support mailing list archives to see if your -question has been answered. Instructions are in the following -paragraph. If you don't find an answer there, then please send an -e-mail to the smartmontools-support mailing list. Instructions are -available at <ulink url="http://lists.sourceforge.net/mailman/listinfo/smartmontools-support"> -<literal>http://lists.sourceforge.net/mailman/listinfo/smartmontools-support</literal></ulink> -. The list is moderated but you're not required to subscribe to it in -order to post your question.</para> - -<para>To search the archives, first go to <ulink url="http://sourceforge.net/mailarchive/forum.php?forum=smartmontools-support"> -<literal>http://sourceforge.net/mailarchive/forum.php?forum=smartmontools-support</literal></ulink> -. In the top left corner you will see a search box: use <emphasis -role="bold">Mailing List</emphasis> as the type of search. This tool -works very well.</para> - -<para>Note that from time to time SourceForge has mailing problems and -you'll get a message telling you that <emphasis role="italic">Either -your mailing list name was misspelled or your mailing list has not been -archived yet. If this list has just been created, please retry in 2-4 -hours</emphasis>. If this happens, you'll have to try again -later.</para> - -</sect1> - -<sect1 id="b"> - -<title>What are the future plans for smartmontools?</title> - -<para>My plan is that smartmontools-5.x will support ATA/ATAPI-5 disks. -Eventually, we'll do smartmontools-6.x to support ATA/ATAPI-6 disks, -smartmontools-7.x for the ATA/ATAPI-7 standard, and so on. The "x" will -denote revision level, as bugs get found and fixed, and as enhancements -get added. If it's possible to maintain backwards compatibility, that -would be nice, but I don't know if it will be possible or -practical.</para> - -</sect1> - -<sect1 id="c"> - -<title>Why are you doing this?</title> - -<para>My research group at U. Wisconsin - Milwaukee runs a beowulf -cluster - <ulink url="http://www.lsc-group.phys.uwm.edu/beowulf/medusa/"> -<literal>http://www.lsc-group.phys.uwm.edu/beowulf/medusa/</literal></ulink> -- with 600 ATA-5 and -6 disks (300 IBM and 300 Maxtor). We have more -than 50 TB of data stored on the system. I also help out with a cluster -- <ulink url="http://pandora.aei.mpg.de/merlin/"> -<literal>http://pandora.aei.mpg.de/merlin/</literal></ulink> - at the -Albert Einstein Institute that has another 300 IBM ATA-6 disks (36 TB -total). It's nice to have advanced warning when a disk is going to -fail.</para> - -</sect1> - -<sect1 id="d"> - -<title>I see some strange output from smartctl. What does it -mean?</title> - -<para>The raw S.M.A.R.T. attributes (temperature, power-on lifetime, and -so on) are stored in vendor-specific structures. Sometime these are -strange. Hitachi disks (at least some of them) store power-on lifetime -in minutes, rather than hours (see next question below). IBM disks (at -least some of them) have three temperatures stored in the raw structure, -not just one. And so on. If you find strange output, or unknown -attributes, please send an e-mail to the mailing list and we'll help you -try and figure it out.</para> - -</sect1> - -<sect1 id="e"> - -<title>What Kernel Version is needed? (Linux)</title> - -<para>Kernel versions 2.4.0 or later should work. We recommend the -latest 2.4 kernel.</para> - -<para>Vanilla kernel.org 2.2.X kernels do not support the -HDIO_DRIVE_TASK ioctl(), which is needed for the ATA drive to execute -the ATA SMART RETURN STATUS command. So these kernels will not -work.</para> - -<para>Vendor-supplied 2.2.X kernels, and vanilla 2.2.X kernels patched -with Andre Hedrick's IDE patches - <ulink url="http://www.funet.fi/pub/linux/kernel/people/hedrick/ide-2.2.20/"> -<literal>http://www.funet.fi/pub/linux/kernel/people/hedrick/ide-2.2.20/</literal></ulink> -(also available from your local kernel.org mirror, not updated for -2.2.21 or later, and probably still containing a few bugs) may support -the needed ioctl().</para> - -<para>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 smartmontools. Note that this kernel configuration option does -<emphasis role="italic">not</emphasis> need to be enabled. Its presence -merely indicates that the required HDIO_DRIVE_TASK ioctl() is -supported.</para> - -</sect1> - -<sect1 id="f"> - -<title>What attributes does smartmontools not yet recognize?</title> - -<para>From Maxtor disks (99), (100), (101)</para> - -<para>If you can attach names/meanings to these attributes, please send -a note to the mailing list. If you have access to other SMART utilities -(especially manufacturer-specific ones, see below) and can send us -comparison output from smartctl and the other utility, that's especially -useful.</para> - -</sect1> - -<sect1 id="g"> - -<title>My Maxtor/Hitachi/Fujitsu disk is only a few days old, yet -smartctl reports its age (Attribute 9) as thousands of hours!</title> - -<para>On some recent disks, Maxtor has started to use Attribute 9 to -store the lifetime in minutes rather than hours. In this case, use the --m option (smartctl versions 5.0.X) or the --vendorattribute=9,minutes -(smartctl 5.1.X) option to correctly display hours and minutes.</para> - -<para>Some models of Fujitsu disks are known to use Attribute 9 for -lifetime in seconds. In that case, use the --vendorattribute=9,seconds -option to correctly display hours, minutes and seconds.</para> - -</sect1> - -<sect1 id="h"> - -<title>The power-on timer (Attribute 9 raw value) on my Maxtor disk acts -strange.</title> - -<para>There are three related problems with Maxtor's SMART -firmware:</para> - -<para><emphasis role="bold">1 - </emphasis>On some disks from 2001/2002, -the raw value of Attribute 9 (Power On Time) is <emphasis -role="italic">supposed</emphasis> to be minutes. But it advances at an -unpredictable rate, always more slowly than one count per minute. One -(unconfirmed) theory is that when the disk is in idle mode, the counter -stops advancing. This is only supposed to happen in standby -mode.</para> - -<para><emphasis role="bold">2 - </emphasis> In Maxtor disks that use the -raw value of Attribute 9 as a minutes counter, only two bytes (of the -six available) are used to store the raw value. So it resets to zero -once every 65536=2^16 minutes, or about once every 1092 hours. This is -fixed in all Maxtor disks manufactured after July 2003, where the raw -value was extended to four bytes.</para> - -<para><emphasis role="bold">3 - </emphasis> In Maxtor disks that use the -raw value of Attribute 9 as a minutes counter, the hour time-stamps in -the self-test and ATA error logs are calculated by right shifting 6 -bits. This is equivalent to dividing by 64 rather than by 60. As a -result, the hour time-stamps in these logs advance 7% more slowly than -they should. Thus, if you do self-tests once per week at the same time, -instead of the time-stamps being 168 hours apart, they are 157 hours -apart. This is also fixed in all Maxtor disks manufactured after July -2003.</para> - -</sect1> - -<sect1 id="i"> - -<title>Where can I find manufacturer-specific disk-testing -utilities?</title> - -<para>A good listing of such utilities can be found at <ulink url="http://www.benchmarkhq.ru/english.html?/be_hdd2.html"> -<literal>http://www.benchmarkhq.ru/english.html?/be_hdd2.html</literal></ulink> -. Unfortunately most of these are for MS operating systems, but most can -be run from an MS-DOS boot disk. Note: if you do run one of these -utilities, and it identifies the meanings of any SMART Attributes that -are not known to smartmontools, please report them to the mailing -list.</para> - -<para>These utilities have an important role to fill. If your disk has -bad sectors (for example, as revealed by running self-tests with -smartmontools) and the disk is not able to recover the data from those -sectors, then the disk will <emphasis role="italic">not</emphasis> -automatically reallocate those damaged sectors from its set of spare -sectors, because forcing the reallocation to take place may entail some -loss of data. Because the commands that force such reallocation are -<emphasis role="italic">Vendor Specific</emphasis>, most manufactuers -provide a utility for this purpose. It may cause data loss but can -repair damaged sectors (at least, until it runs out of replacement -sectors).</para> - -</sect1> - -<sect1 id="j"> - -<title>When I run <emphasis role="tt">smartd</emphasis>, -the SYSLOG <emphasis role="tt">/var/log/messages</emphasis> contains -messages like this:</title> - -<programlisting> -smartd: Reading Device /dev/sdv -modprobe: modprobe: Can't locate module block-major-65 -</programlisting> - -<para>This is because when <emphasis role="tt">smartd</emphasis> starts, -it looks for all ATA and SCSI devices to monitor (matching the pattern -<emphasis role="tt">/dev/hd[a-z]</emphasis> or <emphasis -role="tt">/dev/sd[a-z]</emphasis>). The log messages appear because -your system doesn't have most of these devices.</para> - -<para>Recent releases of smartd can use a configuration file <emphasis -role="tt">smartd.conf</emphasis> to specify which devices to include or -exclude from start-up search.</para> - -</sect1> - -<sect1 id="k"> - -<title>What's the story on IBM SMART disks?</title> - -<para>Apparently some of the older SMART firmware on IBM disks can -interfere with the regular operation of the disk. If you have this -problem, a firmware upgrade that fixes the problem is avaialable at -<ulink url="http://www.geocities.com/dtla_update/"> -<literal>http://www.geocities.com/dtla_update/</literal></ulink> -.</para> - -</sect1> - -<sect1 id="l"> - -<title>How can I check that the package hasn't been tampered -with?</title> - -<para>Since the <emphasis role="tt">smartmontools</emphasis> utilities -run as root, you might be concerned about something harmful being -embedded within them. Starting with release 5.19 of <emphasis -role="tt">smartmontools</emphasis>, the .rpm files and tarball have been -GPG signed. (The tarball's fingerprint is given in the SoureForge -Release Notes.) Please verify these using the GPG Signing Key available -at <ulink url="http://smartmontools.sourceforge.net/SmartmontoolsSigningKey.txt"> -<literal>http://smartmontools.sourceforge.net/SmartmontoolsSigningKey.txt</literal></ulink> -.</para> - -</sect1> - -<sect1 id="m"> - -<title>Is there a bootable standalone CD or floppy that contains -smartmontools?</title> - -<para>If you have a system that is showing signs of disk trouble (for -example, it's unbootable and the console is full of disk error messages) -it can be handy to have a version of smartmontools that can be run off -of a bootable CD or floppy to examine the disk's SMART data and run -self-tests. This is also useful if you want to run Captive Self-Tests -(the <emphasis role="bold"><emphasis role="tt">-C</emphasis></emphasis> -option of <emphasis role="bold"><emphasis -role="tt">smartctl</emphasis></emphasis> ) on disks that can not easily -be unmounted, such as those hosting the Operating System files. Or you -can use this to run <emphasis role="tt">smartctl</emphasis> on computers -that don't use Linux as the day-to-day Operating System.</para> - -<para>At present I am only aware of three such bootable disks:</para> - -<itemizedlist> -<listitem> -<para>LNX-BBC Bootable CD - <ulink url="http://www.lnx-bbc.org/"> -<literal>http://www.lnx-bbc.org/</literal></ulink></para> -</listitem> - -<listitem> -<para>Stresslinux Bootable CD - <ulink url="http://www.stresslinux.org/"> -<literal>http://www.stresslinux.org/</literal></ulink></para> -</listitem> - -<listitem> -<para>RIP (Recovery Is Possible) Bootable CD/Floppy - <ulink url="http://www.tux.org/pub/people/kent-robotti/looplinux/rip/"> -<literal>http://www.tux.org/pub/people/kent-robotti/looplinux/rip/</literal></ulink></para> -</listitem> -</itemizedlist> - -<para> Please let us know if there are others, and we'll add them to -this list.</para> - -</sect1> - -<sect1 id="n"> - -<title>Can I monitor ATA disks behind SCSI RAID controllers?</title> - -<para>From release 5.1-16, smartmontools supports 3ware SCSI RAID -controllers that use ATA disks internally. To pass commands through the -3ware controller, use the smartmontools <emphasis role="bold">-d -3ware,N</emphasis> option or Directive.</para> - -<para>In smartmontools release 5.1-16, the SMART HEALTH STATUS -(smartmontools <emphasis role="bold">-H</emphasis>) is not returned -correctly for 3ware devices. In this release, the ENABLE AUTOMATIC -OFFLINE and ENABLE ATTRIBUTE AUTOSAVE commands (smartmontools <emphasis -role="bold">-o on</emphasis> and <emphasis role="bold">-S on</emphasis>) -are <emphasis role="italic">disabled</emphasis> for 3ware devices, -because at the time 5.1-16 was released, the 3w-xxxx driver could not -pass these commands through to the ATA disks.</para> - -<para>Later smartmontools CVS code and releases <emphasis -role="italic">do</emphasis> correctly support <emphasis -role="italic">all</emphasis> of these commands. You may:</para> - -<itemizedlist> -<listitem> -<para>Use version <emphasis role="bold">1.02.00.037</emphasis> or -greater of the 3w-xxxx driver, or</para> -</listitem> - -<listitem> -<para>Patch earlier 3ware 3w-xxxx drivers with <ulink url="http://smartmontools.sourceforge.net/3w-xxxx.txt"> -<literal>http://smartmontools.sourceforge.net/3w-xxxx.txt</literal></ulink> -so that these commands reach the disks, or</para> -</listitem> - -<listitem> -<para>Use an <emphasis role="bold">unpatched</emphasis> earlier 3w-xxxx -driver (which won't pass these commands to the disks but will instead -print harmless warning messages to SYSLOG).</para> -</listitem> -</itemizedlist> - -<para>Since smartmontools 3ware support is new, please report positive -or negative experiences to the mailing list, particularly for 64-bit -and/or big-endian architectures.</para></sect1> - -<sect1 id="o"> - -<title>SCSI disks and tapes (TapeAlert)</title> - -<para>smartmontools for SCSI disks and tapes (including medium changers) -is discussed at <ulink url="http://smartmontools.sourceforge.net/smartmontools_scsi.html"> -<literal>http://smartmontools.sourceforge.net/smartmontools_scsi.html</literal></ulink> -.</para> - -</sect1> - -<sect1 id="p"> - -<title>FireWire, USB, and SATA disks/systems</title> - -<para>As for USB and FireWire (ieee1394) disks and tape drives, the news -isn't good. They appear to Linux as SCSI devices but their -implementations do not usually support those SCSI commands needed by -smartmontools. The ieee1394 consortium recently certified the first -external enclosure (containing a ATA disk and a protocol bridge) as -being compliant to the relevant standards. Such devices have already -been on the market for about 3 years and they tend to only support the -bare minimum of commands needed for device operation (i.e. S.M.A.R.T. -support is an unsupported extra).</para> - -<para>I'd be very grateful to find someone who could help me test the -smartmontools code on serial ATA (SATA) disks. They should appear as -normal ATA disks in Linux.</para> - -</sect1> - -<sect1 id="q"> - -<title>How does smartmontools differ from smartsuite?</title> - -<para>The smartsuite code was originally developed as a Senior Thesis by -Michael Cornwell at the Concurrent Systems Laboratory (now part of the -Storage Systems Research Center - <ulink url="http://ssrc.soe.ucsc.edu/"> -<literal>http://ssrc.soe.ucsc.edu/</literal></ulink>), Jack Baskin -School of Engineering, University of California, Santa Cruz. You can -find some information about the original smartsuite project here:</para> - -<itemizedlist> -<listitem> -<para>Press Release 1 - <ulink url="http://www.ucsc.edu/news_events/press_releases/archive/99-00/09-99/smart_software.htm"> -<literal>http://www.ucsc.edu/news_events/press_releases/archive/99-00/09-99/smart_software.htm</literal></ulink></para> -</listitem> - -<listitem> -<para>Press Release 2 - <ulink url="http://www.santa-cruz.com/archive/1999/September/22/local/stories/5local.htm"> -<literal>http://www.santa-cruz.com/archive/1999/September/22/local/stories/5local.htm</literal></ulink></para> -</listitem> - -<listitem> -<para>Press Release 3 - <ulink url="http://www.ucsc.edu/currents/99-00/09-27/smart.html"> -<literal>http://www.ucsc.edu/currents/99-00/09-27/smart.html</literal></ulink></para> -</listitem> -</itemizedlist> - -<para>smartmontools was derived directly from smartsuite. It differs -from smartsuite in that it supports the ATA/ATAPI-5 standard. So for -example <emphasis role="tt">smartctl</emphasis> from smartsuite has no -facility for printing the SMART self-test logs, and doesn't print -timestamp information in the most usable way.</para> - -<para>The <emphasis role="tt">smartctl</emphasis> utility in -smartmontools has added functionality for this (<emphasis role="tt">-q, --l selftest,-S, -T, -v and -m</emphasis> options), updated -documentation, and also fixes small technical bugs in smartsuite. [One -example: smartsuite does not actually use the ATA SMART RETURN STATUS -command to find out the health status of a disk. It instead tries to -infer this from the SMART Attribute values.] See <ulink url="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?rev=HEAD&content-type=text/plain"> -<literal>http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?rev=HEAD&content-type=text/plain</literal></ulink> for a summary of what's been done.</para> - -<para>The <emphasis role="tt">smartd</emphasis> utility differs from the -smartsuite <emphasis role="tt">smartd</emphasis> in major ways. First, -it prints somewhat more informative error messages to the syslog. -Second, on startup it looks for a configuration file <emphasis -role="tt">smartd.conf</emphasis>, and if <emphasis -role="tt">smartd</emphasis> finds this file, it monitors the list of -devices therein, rather than querying all IDE and SCSI devices on your -system. (If the configuration file does not exist, then it does query -all IDE and SCSI devices.) Also, it's a well-behaved daemon and doesn't -leave open file descriptors and other detrius behind.</para> - -<para>In addition, the <emphasis role="tt">smartmontools</emphasis> -version of <emphasis role="tt">smartd</emphasis> can be instructed (via -Directives in the configuration file) to monitor for changes in a number -of different disk properties: the SMART status, failure or prefailure -attributes going below threshold, new errors appearing in the ATA Error -Log or the SMART Self-Test Log, and so on. <emphasis -role="tt">smartd</emphasis> can also send an e-mail warning or run a -user-specified executable if it detects a problem with the disk.</para> - -<para>The other principle difference is that smartmontools is an -OpenSource development project, meaning that we keep the files in CVS, -and that other developers who wish to contribute can commit changes to -the archive. If you would like to contribute, please write to the -mailing-list.</para> - -<para>But the bottom line is that the code in smartmontools is derived -directly from smartsuite and is similar. The smartsuite package can be -found at <ulink url="http://sourceforge.net/projects/smartsuite/"> -<literal>http://sourceforge.net/projects/smartsuite/</literal></ulink> -.</para></sect1> - -<sect1 id="r"> - -<title>Does it work on Windows?</title> - -<para>Currently not, but we consider Cygwin - <ulink url="http://www.cygwin.com/"> -<literal>http://www.cygwin.com/</literal></ulink> - the way to go, -where CVS compiles almost out of the box but still lacks any specific -code to make it work. Write to the mailing list if you're interested in -porting it. Someone already sent some S.M.A.R.T. code for Windows, -which may be of use. Porting to other platforms may be easier as well -now that any Linux specific code (like linux/hdreg.h) has been removed, -and more will be done soon in that direction.</para> - -<para>A Cygwin port would probably only require and additional DLL, -cygwin1.dll, to run on plain Windows.</para></sect1> - -<sect1 id="s"> - -<title>Why has the versioning scheme changed?</title> - -<para>With the move to GNU Autoconf and GNU Automake it changed from -5.X-Y (where X and Y are one or more numbers) to 5.Y. This had to be -done because the -Y extension is used by distributions to almost always -denote a new build of the same version. So, the first version with that -change will be 5.19 and not 5.1-19.</para> - -</sect1> - -</article> diff --git a/www/Makefile b/www/Makefile deleted file mode 100644 index 7af3daaef2868613ea340bf144be16aa79138be0..0000000000000000000000000000000000000000 --- a/www/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Manufactures HTML file from XML file. Note: do NOT edit the HTML -# file, only the XML file. - -all: smartmontools_scsi.html - -smartmontools_scsi.html: smartmontools_scsi.xml - xmlto html-nochunks smartmontools_scsi.xml - -upload: smartmontools_scsi.html index.html - scp smartmontools_scsi.html ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs - scp 3w-xxxx.txt ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs - scp index.html ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs - scp examples/*.html ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs/examples - scp examples/*.txt ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs/examples - scp BadBlockHowTo.txt ballen4705@smartmontools.sourceforge.net:/home/groups/s/sm/smartmontools/htdocs diff --git a/www/SmartmontoolsSigningKey.txt b/www/SmartmontoolsSigningKey.txt deleted file mode 100644 index 0ac19356f748d2b5f81b33962e588e8af28fb16d..0000000000000000000000000000000000000000 --- a/www/SmartmontoolsSigningKey.txt +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.0.7 (GNU/Linux) - -mQGiBD9XAXIRBACgLEphBmhUKWE1mRKzjkq/8vZHtJsVUiFivcbxaSLa9jBbJoZV -sQk5fdcleVE6CcuodMetVE6Gl8uM4W4iymp0i35lwefdgmUzJYmza1ZD7Uk0x4zv -tKi9xZ9Hc+yrf4SHRwLTZxuUyLf9TURwGXfLd2bxP1USYJVL4vOYoiBwBwCgq/w3 -EyO5PhlGp5rfE+WIoyy9GHcEAIYP3ctigHu6tnSobIGA77BFOv+v7DbXRjbKhEz1 -s4lPGQQP5h2t4VFRiy9RlD4GlEXD51cRFMmtFk4cBbOuONQbNOJFQQ/9JpVBU6/O -CZrVMUqDnQMd2mdUU8pxM7cguaw5cPFxqqX5dkW1JikGrlG1QsH5UxuYhdadO+al -1fTnA/9RMRscXd6aAdN66pZ9mGoqIxVUO6N+icXO7DP+ArIt7gu4GLgvvARlgMiS -neRV4g7mvLm41kBDEv5gug+h2ha5ZI+P51oSRYs8yA5fVtl0GA2YRA2QercALv6C -CtAvnFXWFqSeyW1ESdd2zFKBjhXlBVkmujOyKDS6LXRpZjwJXrRWU21hcnRtb250 -b29scyBTaWduaW5nIEtleSAodGhyb3VnaCAyMDA0KSA8c21hcnRtb250b29scy1z -dXBwb3J0QGxpc3RzLnNvdXJjZWZvcmdlLm5ldD6IZAQTEQIAJAUCP1cBcgIbAwUJ -AnjQAAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRAjPh86m7GaIlTQAJ9IsqaxHbqX -BSd+xfJwUAZyKWqyLwCgoa2rMvHAHa/Pvpt4E0i0xF9NW3yITAQTEQIADAUCP1cB -+QWDAnjPeQAKCRARGZEEN/UVgWa7AJ95rEDeEw9G3uqAZO7L9u650QPX6wCgoHJ9 -Hq/akQJZhOgSKyrgVEyAc8S5AQ0EP1cBeBAEAMLXV8RwVFDs5EvfkQNwasoKNS+N -PvvhO/weED188XklZ3QTiToEp2b4JFaoUkTk1l2f9JxagDPaVHR6XU8H740x25LZ -gC6XObKMBxqJ9CrBLGcMt/bCugquDu18KFlL3Y1rq9uBxq9JS6CJthUzeaaFdFQS -V7tF2+3hBz/Okqo7AAMFA/9l0YcKnTKDy8jdOtNjky1NEbaF1LjyRc4laT6N4O6q -Xg2oGD6MgS7zSK/ORcT3B0T5kpTo6gnKLTYDxEAvpNjrOjlwn08Jtm3xrQZLId/W -RAo+Qqn5Or+sugZZpQPHrGGB9TTc0AL3MfCbK4mlssVhS0SAq35E/osCLQcor7Sx -sohPBBgRAgAPBQI/VwF4AhsMBQkCeNAAAAoJECM+HzqbsZoi4WUAn2IQhEtHY/48 -4rljbro8yUwYlrXzAJ44VfTwmjLlI9aoYdRW/cTtZ0tPgw== -=f2kQ ------END PGP PUBLIC KEY BLOCK----- diff --git a/www/cvs-script b/www/cvs-script deleted file mode 100755 index 42e4fa2e8d709db8ae2b49a1ff0739f5431dcc00..0000000000000000000000000000000000000000 --- a/www/cvs-script +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# execute this script in the current shell, using for example -# . cvs_script -unset CVS_SERVER -export CVS_RSH=ssh -export CVSROOT=:ext:ballen4705@cvs.sourceforge.net:/cvsroot/smartmontools diff --git a/www/examples/FUJITSU1.txt b/www/examples/FUJITSU1.txt deleted file mode 100644 index b10abf7a3b232514e1133510003645544d3ad932..0000000000000000000000000000000000000000 --- a/www/examples/FUJITSU1.txt +++ /dev/null @@ -1,80 +0,0 @@ -[root/]# smartctl -v 9,seconds -v 200,writeerrorcount /dev/hda - -smartctl version 5.1-18 Copyright (C) 2002-3 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: FUJITSU MHR2040AT -Serial Number: NJ41T291391J -Firmware Version: 40BA -Device is: Not in smartctl database [for details use: -P showall] -ATA Version is: 6 -ATA Standard is: ATA/ATAPI-6 T13 1410D revision 1 -Local Time is: Thu Sep 4 22:18:48 2003 CEST -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. - Auto Off-line Data Collection: Disabled. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 468) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 60) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000f 100 100 046 Pre-fail Always - 52685626284 - 2 Throughput_Performance 0x0005 100 100 020 Pre-fail Offline - 0 - 3 Spin_Up_Time 0x0003 093 093 025 Pre-fail Always - 24065 - 4 Start_Stop_Count 0x0032 100 100 000 Old_age Always - 160 - 5 Reallocated_Sector_Ct 0x0033 099 099 024 Pre-fail Always - 31 - 7 Seek_Error_Rate 0x000f 100 100 047 Pre-fail Always - 131071 - 8 Seek_Time_Performance 0x0005 100 100 019 Pre-fail Offline - 0 - 9 Power_On_Seconds 0x0032 092 092 000 Old_age Always - 1335h+10m+34s - 10 Spin_Retry_Count 0x0013 100 100 020 Pre-fail Always - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 150 -192 Power-Off_Retract_Count 0x0032 099 099 000 Old_age Always - 7 -193 Load_Cycle_Count 0x0032 074 074 000 Old_age Always - 95890 -194 Temperature_Celsius 0x0022 090 100 000 Old_age Always - 57 -195 Hardware_ECC_Recovered 0x001a 100 100 000 Old_age Always - 10141348 -196 Reallocated_Event_Count 0x0032 099 099 000 Old_age Always - 30 -197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 0 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0 -199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 0 -200 Write_Error_Count 0x000f 036 033 060 Pre-fail Always FAILING_NOW 2883583 -203 Run_Out_Cancel 0x0002 091 091 000 Old_age Always - 2589872160305 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log structure revision number 1 -No self-tests have been logged - - diff --git a/www/examples/FUJITSU_MHR2020AT.txt b/www/examples/FUJITSU_MHR2020AT.txt deleted file mode 100644 index 4f8dc82b9c5b6858e849cf8e682dbe855fdb0c53..0000000000000000000000000000000000000000 --- a/www/examples/FUJITSU_MHR2020AT.txt +++ /dev/null @@ -1,158 +0,0 @@ -smartctl version 5.32 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: FUJITSU MHR2020AT -Serial Number: NJ13T2215TUH -Firmware Version: 30B8 -Device is: Not in smartctl database [for details use: -P showall] -ATA Version is: 6 -ATA Standard is: ATA/ATAPI-6 T13 1410D revision 1 -Local Time is: Sun Aug 15 13:21:33 2004 MEST -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Offline data collection status: (0x00) Offline data collection activity - was never started. - Auto Offline Data Collection: Disabled. -Self-test execution status: ( 105) The previous self-test completed having - the servo (and/or seek) element of the - test failed. -Total time to complete Offline -data collection: ( 234) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Auto Offline data collection on/off support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 30) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000f 007 001 046 Pre-fail Always FAILING_NOW 154618843423 - 2 Throughput_Performance 0x0005 100 100 020 Pre-fail Offline - 145 - 3 Spin_Up_Time 0x0003 094 083 025 Pre-fail Always - 24321 - 4 Start_Stop_Count 0x0032 097 097 000 Old_age Always - 1887 - 5 Reallocated_Sector_Ct 0x0033 099 099 024 Pre-fail Always - 1 - 7 Seek_Error_Rate 0x000f 100 100 047 Pre-fail Always - 458751 - 8 Seek_Time_Performance 0x0005 100 100 019 Pre-fail Offline - 0 - 9 Power_On_Seconds 0x0032 088 088 000 Old_age Always - 1819h+16m+52s - 10 Spin_Retry_Count 0x0013 100 100 020 Pre-fail Always - 0 - 12 Power_Cycle_Count 0x0032 091 091 000 Old_age Always - 1467 -192 Power-Off_Retract_Count 0x0032 099 099 000 Old_age Always - 44 -193 Load_Cycle_Count 0x0032 086 086 000 Old_age Always - 49810 -194 Temperature_Celsius 0x0022 100 100 000 Old_age Always - 32 -195 Hardware_ECC_Recovered 0x001a 100 100 000 Old_age Always - 1221 -196 Reallocated_Event_Count 0x0032 099 099 000 Old_age Always - 1 -197 Current_Pending_Sector 0x0012 001 001 000 Old_age Always - 10 -198 Offline_Uncorrectable 0x0010 092 092 000 Old_age Offline - 17 -199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 0 -200 Multi_Zone_Error_Rate 0x000f 100 100 060 Pre-fail Always - 393215 -203 Run_Out_Cancel 0x0002 100 100 000 Old_age Always - 429515210380 - -SMART Error Log Version: 1 -ATA Error Count: 6861 (device log contains only the most recent five errors) - CR = Command Register [HEX] - FR = Features Register [HEX] - SC = Sector Count Register [HEX] - SN = Sector Number Register [HEX] - CL = Cylinder Low Register [HEX] - CH = Cylinder High Register [HEX] - DH = Device/Head Register [HEX] - DC = Device Command Register [HEX] - ER = Error register [HEX] - ST = Status register [HEX] -Powered_Up_Time is measured from power on, and printed as -DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes, -SS=sec, and sss=millisec. It "wraps" after 49.710 days. - -Error 6861 occurred at disk power-on lifetime: 1818 hours (75 days + 18 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 8b 7d 16 51 f0 Error: UNC 139 sectors at LBA = 0x0051167d = 5314173 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 90 78 16 51 f0 00 08:22:32.857 READ DMA EXT - -Error 6860 occurred at disk power-on lifetime: 1818 hours (75 days + 18 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 8b 7d 16 51 f0 Error: UNC 139 sectors at LBA = 0x0051167d = 5314173 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 98 70 16 51 f0 00 08:22:27.700 READ DMA EXT - -Error 6859 occurred at disk power-on lifetime: 1818 hours (75 days + 18 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 8b 7d 16 51 f0 Error: UNC 139 sectors at LBA = 0x0051167d = 5314173 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 a0 68 16 51 f0 00 08:22:22.558 READ DMA EXT - -Error 6858 occurred at disk power-on lifetime: 1818 hours (75 days + 18 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 8b 7d 16 51 f0 Error: UNC 139 sectors at LBA = 0x0051167d = 5314173 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 a8 60 16 51 f0 00 08:22:17.458 READ DMA EXT - -Error 6857 occurred at disk power-on lifetime: 1818 hours (75 days + 18 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 8b 7d 16 51 f0 Error: UNC 139 sectors at LBA = 0x0051167d = 5314173 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 b0 58 16 51 f0 00 08:22:12.558 READ DMA EXT - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short offline Completed: servo/seek failure 90% 1819 - -# 2 Extended offline Completed: servo/seek failure 90% 1816 - - -Device does not support Selective Self Tests/Logging diff --git a/www/examples/HITACHI_DK23AA-12B.txt b/www/examples/HITACHI_DK23AA-12B.txt deleted file mode 100644 index 6f9b62e60cff0d5751ceceeae48873b665319356..0000000000000000000000000000000000000000 --- a/www/examples/HITACHI_DK23AA-12B.txt +++ /dev/null @@ -1,173 +0,0 @@ -smartctl version 5.30 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: HITACHI_DK23AA-12B -Serial Number: xxxxxx -Firmware Version: 00XDA0B6 -Device is: Not in smartctl database [for details use: -P showall] -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -Local Time is: Sat Apr 24 17:19:58 2004 EST -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Offline data collection status: (0x00) Offline data collection activity was - never started. - Auto Offline Data Collection: Disabled. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete Offline -data collection: (1110) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Auto Offline data collection on/off support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 1) minutes. -Extended self-test routine -recommended polling time: ( 19) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000d 099 099 050 Pre-fail Offline - 68719476757 - 4 Start_Stop_Count 0x0032 097 097 050 Old_age Always - 3259 - 5 Reallocated_Sector_Ct 0x0033 001 001 010 Pre-fail Always FAILING_NOW 1876 - 7 Seek_Error_Rate 0x000b 100 100 050 Pre-fail Always - 760 - 9 Power_On_Hours 0x0032 090 090 060 Old_age Always - 21783 - 10 Spin_Retry_Count 0x0013 100 100 050 Pre-fail Always - 0 -196 Reallocated_Event_Count 0x0032 001 001 001 Old_age Always FAILING_NOW 254 -197 Current_Pending_Sector 0x0032 097 093 001 Old_age Always - 3 -198 Offline_Uncorrectable 0x0010 100 100 001 Old_age Offline - 0 -199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age Always - 0 -221 G-Sense_Error_Rate 0x000a 100 100 050 Old_age Always - 42 -223 Load_Retry_Count 0x0012 100 100 050 Old_age Always - 149 -225 Load_Cycle_Count 0x0032 050 050 050 Old_age Always FAILING_NOW 5110222858734 -250 Read_Error_Retry_Rate 0x000a 090 001 050 Old_age Always In_the_past 103 - -SMART Error Log Version: 1 -ATA Error Count: 1151 (device log contains only the most recent five errors) - CR = Command Register [HEX] - FR = Features Register [HEX] - SC = Sector Count Register [HEX] - SN = Sector Number Register [HEX] - CL = Cylinder Low Register [HEX] - CH = Cylinder High Register [HEX] - DH = Device/Head Register [HEX] - DC = Device Command Register [HEX] - ER = Error register [HEX] - ST = Status register [HEX] -Timestamp = decimal seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 1151 occurred at disk power-on lifetime: 5445 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 01 51 01 01 4f c2 e0 Error: obs - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - b0 d5 01 01 4f c2 e0 00 46273.155 SMART READ LOG - b0 d1 01 01 4f c2 e0 00 46273.138 SMART READ ATTRIBUTE THRESHOLDS [OBS-4] - b0 d0 01 00 4f c2 e0 00 46273.009 SMART READ DATA - b0 da 00 00 4f c2 a0 00 46272.881 SMART RETURN STATUS - b0 da 00 00 4f c2 e0 00 46272.760 SMART RETURN STATUS - -Error 1150 occurred at disk power-on lifetime: 5354 hours - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 01 51 01 56 36 54 e1 Error: AMNF 1 sectors at LBA = 0x01543656 = 22296150 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 80 d7 35 54 e1 00 1517.332 READ DMA - c8 00 80 57 35 54 e1 00 1517.329 READ DMA - ca 00 08 67 1d cb e0 00 1516.014 WRITE DMA - ca 00 30 37 1d cb e0 00 1515.992 WRITE DMA - ca 00 10 2f e0 ca e0 00 1515.874 WRITE DMA - -Error 1149 occurred at disk power-on lifetime: 5352 hours - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 01 51 0c bb c5 57 e1 Error: AMNF 12 sectors at LBA = 0x0157c5bb = 22529467 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 20 a7 c5 57 e1 00 380.146 READ DMA - 10 00 3f 00 00 00 e0 00 380.146 RECALIBRATE [OBS-4] - c8 00 20 a7 c5 57 e1 00 377.932 READ DMA - c8 00 20 a7 c5 57 e1 00 373.729 READ DMA - c8 00 80 6f 41 5f e1 00 371.776 READ DMA - -Error 1148 occurred at disk power-on lifetime: 5352 hours - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 01 51 0c bb c5 57 e1 Error: AMNF 12 sectors at LBA = 0x0157c5bb = 22529467 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 20 a7 c5 57 e1 00 377.932 READ DMA - c8 00 20 a7 c5 57 e1 00 373.729 READ DMA - c8 00 80 6f 41 5f e1 00 371.776 READ DMA - c8 00 80 ef 40 5f e1 00 371.742 READ DMA - ca 00 08 57 1f cb e0 00 371.291 WRITE DMA - -Error 1147 occurred at disk power-on lifetime: 5352 hours - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 01 51 0c bb c5 57 e1 Error: AMNF 12 sectors at LBA = 0x0157c5bb = 22529467 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 20 a7 c5 57 e1 00 373.729 READ DMA - c8 00 80 6f 41 5f e1 00 371.776 READ DMA - c8 00 80 ef 40 5f e1 00 371.742 READ DMA - ca 00 08 57 1f cb e0 00 371.291 WRITE DMA - ca 00 10 47 1f cb e0 00 371.262 WRITE DMA - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short offline Completed without error 00% 5445 - -# 2 Short offline Completed without error 00% 5445 - -# 3 Short offline Aborted by host 90% 5445 - -# 4 Short offline Completed without error 00% 5445 - -# 5 Short offline Completed without error 00% 5445 - - diff --git a/www/examples/HITACHI_DK23BA-20-0.txt b/www/examples/HITACHI_DK23BA-20-0.txt deleted file mode 100644 index 13e9cb0122e0c6e4e072ddfc91efba9d9a4a3d19..0000000000000000000000000000000000000000 --- a/www/examples/HITACHI_DK23BA-20-0.txt +++ /dev/null @@ -1,163 +0,0 @@ -[root@ballen www]# /usr/sbin/smartctl -am /dev/hda - -smartctl version 5.0-25 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: HITACHI_DK23BA-20 -Serial Number: 12H7M8 -Firmware Version: 00E0A0D2 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED -See vendor-specific Attribute list for marginal Attributes. - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: (1530) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 26) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000d 100 083 050 Pre-fail - 677 - 3 Spin_Up_Time 0x0007 100 100 050 Pre-fail - 0 - 4 Start_Stop_Count 0x0032 100 100 050 Old_age - 249 - 5 Reallocated_Sector_Ct 0x0033 099 099 010 Pre-fail - 30 - 7 Seek_Error_Rate 0x000f 100 100 050 Pre-fail - 319 - 9 Power_On_Hours 0x0032 099 099 060 Old_age - 701 h + 42 m - 10 Spin_Retry_Count 0x0013 100 100 050 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 050 Old_age - 249 -192 Power-Off_Retract_Count 0x0032 100 100 050 Old_age - 15 -195 Hardware_ECC_Recovered 0x001a 100 001 050 Old_age In_the_past 559 -196 Reallocated_Event_Count 0x0032 097 097 001 Old_age - 30 -197 Current_Pending_Sector 0x0032 095 095 001 Old_age - 5 -198 Offline_Uncorrectable 0x0010 095 095 001 Old_age - 31 -199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age - 0 -221 G-Sense_Error_Rate 0x000a 100 100 050 Old_age - 0 -223 Load_Retry_Count 0x0012 100 100 050 Old_age - 0 -225 Load_Cycle_Count 0x0032 095 095 050 Old_age - 18446744072753281791 -230 Unknown_Attribute 0x0032 100 100 060 Old_age - 18484 -250 Unknown_Attribute 0x000a 100 070 050 Old_age - 601 - -SMART Error Log Version: 1 -ATA Error Count: 9 (device log contains only the most recent five errors) - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 1 occurred at disk power-on lifetime: 458 hours -When the command that caused the error occurred, the device was active or idle. -After command completion occurred, registers were: -ER:40 SC:01 SN:15 CL:be CH:2e D/H:e0 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 00 01 15 be 2e e0 c8 831.599 - 00 00 01 14 be 2e e0 c8 831.594 - 00 00 01 13 be 2e e0 c8 831.594 - 00 00 01 12 be 2e e0 c8 831.594 - 00 00 01 11 be 2e e0 c8 831.594 - -Error 2 occurred at disk power-on lifetime: 458 hours -When the command that caused the error occurred, the device was active or idle. -After command completion occurred, registers were: -ER:40 SC:45 SN:15 CL:be CH:2e D/H:e0 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 00 80 da bd 2e e0 c8 829.680 - 00 00 80 5a bd 2e e0 c8 829.677 - 00 00 80 da bc 2e e0 c8 829.673 - 00 00 80 5a bc 2e e0 c8 829.671 - 00 00 01 58 bc 2e e0 c8 829.671 - -Error 3 occurred at disk power-on lifetime: 458 hours -When the command that caused the error occurred, the device was active or idle. -After command completion occurred, registers were: -ER:40 SC:01 SN:47 CL:bc CH:2e D/H:e0 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 00 01 47 bc 2e e0 c8 826.962 - 00 00 01 46 bc 2e e0 c8 826.961 - 00 00 01 45 bc 2e e0 c8 826.961 - 00 00 01 44 bc 2e e0 c8 826.961 - 00 00 01 43 bc 2e e0 c8 826.961 - -Error 4 occurred at disk power-on lifetime: 458 hours -When the command that caused the error occurred, the device was active or idle. -After command completion occurred, registers were: -ER:40 SC:13 SN:47 CL:bc CH:2e D/H:e0 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 00 80 da bb 2e e0 c8 825.038 - 00 00 80 5a bb 2e e0 c8 825.033 - 00 00 80 da ba 2e e0 c8 825.030 - 00 00 80 5a ba 2e e0 c8 824.940 - 00 00 80 da b9 2e e0 c8 824.937 - -Error 5 occurred at disk power-on lifetime: 458 hours -When the command that caused the error occurred, the device was active or idle. -After command completion occurred, registers were: -ER:40 SC:01 SN:85 CL:19 CH:2c D/H:e0 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 00 01 85 19 2c e0 c8 816.487 - 00 00 01 84 19 2c e0 c8 816.487 - 00 00 01 83 19 2c e0 c8 816.486 - 00 00 01 82 19 2c e0 c8 816.486 - 00 00 01 81 19 2c e0 c8 816.486 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short off-line Completed 00% 691 -# 2 Extended off-line Completed: read failure 40% 661 0x002c1985 -# 3 Extended off-line Completed: read failure 40% 661 0x002c1985 -# 4 Short off-line Completed 00% 660 -# 5 Extended off-line Completed: read failure 40% 658 0x002c1985 -# 6 Short off-line Completed 00% 658 -# 7 Short off-line Completed 00% 658 -# 8 Extended off-line Completed: read failure 40% 658 0x002c1985 -# 9 Extended off-line Completed: read failure 40% 657 0x002c1985 -#10 Short off-line Completed 00% 647 -#11 Short off-line Completed 00% 587 -#12 Short off-line Completed 00% 583 -#13 Short off-line Completed 00% 551 -#14 Short captive Interrupted (host reset) 40% 551 -#15 Short off-line Completed 00% 551 -#16 Extended off-line Completed: read failure 40% 550 0x002c1985 -#17 Extended off-line Aborted by host 50% 550 -#18 Short off-line Completed 00% 550 -#19 Short off-line Completed 00% 537 -#20 Extended off-line Completed: read failure 40% 536 0x002c1985 -#21 Short off-line Completed 00% 536 diff --git a/www/examples/IC35L120AVV207-0.txt b/www/examples/IC35L120AVV207-0.txt deleted file mode 100644 index 4e43e8c2d0976622c07e0e0cddc4507716f5cca6..0000000000000000000000000000000000000000 --- a/www/examples/IC35L120AVV207-0.txt +++ /dev/null @@ -1,67 +0,0 @@ -# smartctl -a /dev/hda -smartctl version 5.0-45 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: IC35L120AVV207-0 -Serial Number: VNVD02G4G4BDEG -Firmware Version: V24OA63A -ATA Version is: 6 -ATA Standard is: ATA/ATAPI-6 T13 1410D revision 3a -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: (2855) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 1) minutes. -Extended self-test routine -recommended polling time: ( 48) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 100 100 060 Pre-fail - 0 - 2 Throughput_Performance 0x0005 100 100 050 Pre-fail - 0 - 3 Spin_Up_Time 0x0007 102 102 024 Pre-fail - 16974103 - 4 Start_Stop_Count 0x0012 100 100 000 Old_age - 14 - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 067 Pre-fail - 0 - 8 Seek_Time_Performance 0x0005 100 100 020 Pre-fail - 0 - 9 Power_On_Hours 0x0012 100 100 000 Old_age - 242 - 10 Spin_Retry_Count 0x0013 100 100 060 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age - 14 -192 Power-Off_Retract_Count 0x0032 100 100 050 Old_age - 24 -193 Load_Cycle_Count 0x0012 100 100 050 Old_age - 24 -194 Temperature_Celsius 0x0002 203 203 000 Old_age - 27 (Lifetime Min/Max 20/37) -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 54 diff --git a/www/examples/IC35L120AVV207-1.txt b/www/examples/IC35L120AVV207-1.txt deleted file mode 100644 index 48a69910371771d2fdf0b10b19e3ce0ea3d4aff6..0000000000000000000000000000000000000000 --- a/www/examples/IC35L120AVV207-1.txt +++ /dev/null @@ -1,191 +0,0 @@ -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: IC35L120AVV207-1 -Serial Number: VNVD09G4H3HPMT -Firmware Version: V24OA66A -Device is: In smartctl database [for details use: -P show] -ATA Version is: 6 -ATA Standard is: ATA/ATAPI-6 T13 1410D revision 3a -Local Time is: Tue Jun 15 23:38:56 2004 CDT -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Offline data collection status: (0x84) Offline data collection activity - was suspended by an interrupting command from host. - Auto Offline Data Collection: Enabled. -Self-test execution status: ( 121) The previous self-test completed having - the read element of the test failed. -Total time to complete Offline -data collection: (2855) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Auto Offline data collection on/off support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - General Purpose Logging supported. -Short self-test routine -recommended polling time: ( 1) minutes. -Extended self-test routine -recommended polling time: ( 48) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 089 089 060 Pre-fail Always - 1703986 - 2 Throughput_Performance 0x0005 015 015 050 Pre-fail Offline FAILING_NOW 5518 - 3 Spin_Up_Time 0x0007 100 100 024 Pre-fail Always - 278 - 4 Start_Stop_Count 0x0012 100 100 000 Old_age Always - 9 - 5 Reallocated_Sector_Ct 0x0033 091 091 005 Pre-fail Always - 277 - 7 Seek_Error_Rate 0x000b 100 100 067 Pre-fail Always - 0 - 8 Seek_Time_Performance 0x0005 123 123 020 Pre-fail Offline - 37 - 9 Power_On_Hours 0x0012 100 100 000 Old_age Always - 2759 - 10 Spin_Retry_Count 0x0013 100 100 060 Pre-fail Always - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 9 -192 Power-Off_Retract_Count 0x0032 100 100 050 Old_age Always - 45 -193 Load_Cycle_Count 0x0012 100 100 050 Old_age Always - 45 -194 Temperature_Celsius 0x0002 166 166 000 Old_age Always - 33 (Lifetime Min/Max 23/44) -196 Reallocated_Event_Count 0x0032 092 092 000 Old_age Always - 319 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 49 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 20 -199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age Always - 0 - -SMART Error Log Version: 1 -ATA Error Count: 161 (device log contains only the most recent five errors) - CR = Command Register [HEX] - FR = Features Register [HEX] - SC = Sector Count Register [HEX] - SN = Sector Number Register [HEX] - CL = Cylinder Low Register [HEX] - CH = Cylinder High Register [HEX] - DH = Device/Head Register [HEX] - DC = Device Command Register [HEX] - ER = Error register [HEX] - ST = Status register [HEX] -Powered_Up_Time is measured from power on, and printed as -DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes, -SS=sec, and sss=millisec. It "wraps" after 49.710 days. - -Error 161 occurred at disk power-on lifetime: 2752 hours (114 days + 16 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 46 c2 a7 02 e0 Error: UNC 70 sectors at LBA = 0x0002a7c2 = 174018 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 46 c2 a7 02 e0 00 23d+03:19:20.800 READ DMA EXT - 25 00 48 c0 a7 02 e0 00 23d+03:19:16.000 READ DMA EXT - 25 00 1c a4 a7 02 e0 00 23d+03:19:15.200 READ DMA EXT - 25 00 1e a2 a7 02 e0 00 23d+03:19:10.400 READ DMA EXT - 25 00 20 a0 a7 02 e0 00 23d+03:19:02.200 READ DMA EXT - -Error 160 occurred at disk power-on lifetime: 2752 hours (114 days + 16 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 47 c1 a7 02 e0 Error: UNC 71 sectors at LBA = 0x0002a7c1 = 174017 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 48 c0 a7 02 e0 00 23d+03:19:16.000 READ DMA EXT - 25 00 1c a4 a7 02 e0 00 23d+03:19:15.200 READ DMA EXT - 25 00 1e a2 a7 02 e0 00 23d+03:19:10.400 READ DMA EXT - 25 00 20 a0 a7 02 e0 00 23d+03:19:02.200 READ DMA EXT - 25 00 22 9e a7 02 e0 00 23d+03:18:57.400 READ DMA EXT - -Error 159 occurred at disk power-on lifetime: 2752 hours (114 days + 16 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 02 be a7 02 e0 Error: UNC 2 sectors at LBA = 0x0002a7be = 174014 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 1e a2 a7 02 e0 00 23d+03:19:10.400 READ DMA EXT - 25 00 20 a0 a7 02 e0 00 23d+03:19:02.200 READ DMA EXT - 25 00 22 9e a7 02 e0 00 23d+03:18:57.400 READ DMA EXT - 25 00 24 9c a7 02 e0 00 23d+03:18:52.400 READ DMA EXT - 25 00 26 9a a7 02 e0 00 23d+03:18:40.200 READ DMA EXT - -Error 158 occurred at disk power-on lifetime: 2752 hours (114 days + 16 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 02 be a7 02 e0 Error: UNC 2 sectors at LBA = 0x0002a7be = 174014 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 20 a0 a7 02 e0 00 23d+03:19:02.200 READ DMA EXT - 25 00 22 9e a7 02 e0 00 23d+03:18:57.400 READ DMA EXT - 25 00 24 9c a7 02 e0 00 23d+03:18:52.400 READ DMA EXT - 25 00 26 9a a7 02 e0 00 23d+03:18:40.200 READ DMA EXT - 25 00 28 98 a7 02 e0 00 23d+03:18:32.100 READ DMA EXT - -Error 157 occurred at disk power-on lifetime: 2752 hours (114 days + 16 hours) - When the command that caused the error occurred, the device was active or idle. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 03 bd a7 02 e0 Error: UNC 3 sectors at LBA = 0x0002a7bd = 174013 - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name - -- -- -- -- -- -- -- -- ---------------- -------------------- - 25 00 22 9e a7 02 e0 00 23d+03:18:57.400 READ DMA EXT - 25 00 24 9c a7 02 e0 00 23d+03:18:52.400 READ DMA EXT - 25 00 26 9a a7 02 e0 00 23d+03:18:40.200 READ DMA EXT - 25 00 28 98 a7 02 e0 00 23d+03:18:32.100 READ DMA EXT - 25 00 2a 96 a7 02 e0 00 23d+03:18:26.400 READ DMA EXT - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed: read failure 90% 2692 173893 -# 2 Short offline Completed: read failure 10% 2654 173911 -# 3 Extended offline Completed: read failure 90% 2524 174132 -# 4 Extended offline Completed without error 00% 2358 - -# 5 Extended offline Completed without error 00% 2192 - -# 6 Extended offline Completed without error 00% 2023 - -# 7 Extended offline Completed without error 00% 1857 - -# 8 Extended offline Completed without error 00% 1689 - -# 9 Extended offline Completed without error 00% 1521 - -#10 Extended offline Completed without error 00% 1355 - -#11 Extended offline Completed without error 00% 1187 - -#12 Extended offline Completed without error 00% 1020 - -#13 Extended offline Completed without error 00% 854 - -#14 Extended offline Completed without error 00% 685 - -#15 Extended offline Completed without error 00% 517 - -#16 Extended offline Completed without error 00% 349 - -#17 Extended offline Completed without error 00% 181 - -#18 Extended offline Completed without error 00% 13 - -#19 Extended offline Completed without error 00% 4 - - -Device does not support Selective Self Tests/Logging diff --git a/www/examples/IC35L120AVVA07-0-0.txt b/www/examples/IC35L120AVVA07-0-0.txt deleted file mode 100644 index 57926ccfba480e32daeec54bd0011e23ffdfc5e3..0000000000000000000000000000000000000000 --- a/www/examples/IC35L120AVVA07-0-0.txt +++ /dev/null @@ -1,69 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: IC35L120AVVA07-0 -Serial Number: VNC605A6GG8W8A -Firmware Version: VA6OA52A -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: (3399) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 1) minutes. -Extended self-test routine -recommended polling time: ( 57) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 100 100 060 Pre-fail - 0 - 2 Throughput_Performance 0x0005 147 147 050 Pre-fail - 266 - 3 Spin_Up_Time 0x0007 093 093 024 Pre-fail - 23593335 - 4 Start_Stop_Count 0x0012 100 100 000 Old_age - 13 - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 067 Pre-fail - 0 - 8 Seek_Time_Performance 0x0005 138 138 020 Pre-fail - 30 - 9 Power_On_Hours 0x0012 100 100 000 Old_age - 554 - 10 Spin_Retry_Count 0x0013 100 100 060 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age - 13 -192 Power-Off_Retract_Count 0x0032 100 100 050 Old_age - 36 -193 Load_Cycle_Count 0x0012 100 100 050 Old_age - 36 -194 Temperature_Centigrade 0x0002 183 183 000 Old_age - 30 (Lifetime Min/Max 23/39) -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 492 -# 2 Short off-line Completed 00% 296 -# 3 Extended off-line Completed 00% 169 -# 4 Short off-line Completed 00% 168 diff --git a/www/examples/IC35L120AVVA07-0-1.txt b/www/examples/IC35L120AVVA07-0-1.txt deleted file mode 100644 index 992a620cec64e49651e672bbf8da46d9f6a57e77..0000000000000000000000000000000000000000 --- a/www/examples/IC35L120AVVA07-0-1.txt +++ /dev/null @@ -1,67 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: IC35L120AVVA07-0 -Serial Number: VNC605A6GEWZDA -Firmware Version: VA6OA52A -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: (3399) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 1) minutes. -Extended self-test routine -recommended polling time: ( 57) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 100 100 060 Pre-fail - 0 - 2 Throughput_Performance 0x0005 100 100 050 Pre-fail - 0 - 3 Spin_Up_Time 0x0007 098 098 024 Pre-fail - 22348126 - 4 Start_Stop_Count 0x0012 100 100 000 Old_age - 13 - 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 067 Pre-fail - 0 - 8 Seek_Time_Performance 0x0005 100 100 020 Pre-fail - 0 - 9 Power_On_Hours 0x0012 100 100 000 Old_age - 554 - 10 Spin_Retry_Count 0x0013 100 100 060 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age - 13 -192 Power-Off_Retract_Count 0x0032 100 100 050 Old_age - 36 -193 Load_Cycle_Count 0x0012 100 100 050 Old_age - 36 -194 Temperature_Centigrade 0x0002 189 189 000 Old_age - 29 (Lifetime Min/Max 23/36) -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age - 0 -197 Current_Pending_Sector 0x0022 100 100 000 Old_age - 0 -198 Offline_Uncorrectable 0x0008 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 492 -# 2 Extended off-line Completed 00% 169 diff --git a/www/examples/MAXTOR-0.txt b/www/examples/MAXTOR-0.txt deleted file mode 100644 index 13e0eb28e95d5c7d703ac975814277c44d1c525c..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-0.txt +++ /dev/null @@ -1,139 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674205306226 -Firmware Version: A08.1500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x02) Offline data collection activity - completed without error. -Self-test execution status: ( 112) The previous self-test completed having - the read element of the test failed. -Total time to complete off-line -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 077 077 020 Pre-fail - 2909 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 29 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail - 1 - 7 Seek_Error_Rate 0x000b 100 100 023 Pre-fail - 0 - 9 Power_On_Hours 0x0012 097 097 001 Old_age - 1992 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 29 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail - 0 -194 Temperature_Centigrade 0x0022 093 090 042 Old_age - 19 -195 Hardware_ECC_Recovered 0x001a 100 006 000 Old_age - 7683906 -196 Reallocated_Event_Count 0x0010 099 099 020 Old_age - 1 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age - 1 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 198 198 000 Old_age - 2 - -SMART Error Log Version: 1 -ATA Error Count: 11 (device log contains only the most recent five errors) - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 1 occurred at disk power-on lifetime: 1029 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:02 SN:41 CL:2d CH:70 D/H:e8 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 70 08 02 41 2d 70 e8 c4 90.713 - 70 08 04 3f 2d 70 e8 c4 86.648 - 70 08 06 3d 2d 70 e8 c4 82.584 - 70 08 08 3b 2d 70 e8 c4 78.342 - 28 08 04 8b 2c 28 e8 c5 78.341 - -Error 2 occurred at disk power-on lifetime: 1029 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:04 SN:3f CL:2d CH:70 D/H:e8 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 70 08 04 3f 2d 70 e8 c4 86.648 - 70 08 06 3d 2d 70 e8 c4 82.584 - 70 08 08 3b 2d 70 e8 c4 78.342 - 28 08 04 8b 2c 28 e8 c5 78.341 - 28 08 08 4b 2c 28 e8 c5 78.339 - -Error 3 occurred at disk power-on lifetime: 1029 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:06 SN:3d CL:2d CH:70 D/H:e8 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 70 08 06 3d 2d 70 e8 c4 82.584 - 70 08 08 3b 2d 70 e8 c4 78.342 - 28 08 04 8b 2c 28 e8 c5 78.341 - 28 08 08 4b 2c 28 e8 c5 78.339 - 28 08 08 0b 2c 28 e8 c5 78.338 - -Error 4 occurred at disk power-on lifetime: 1029 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:08 SN:3b CL:2d CH:70 D/H:e8 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 70 08 08 3b 2d 70 e8 c4 78.342 - 28 08 04 8b 2c 28 e8 c5 78.341 - 28 08 08 4b 2c 28 e8 c5 78.339 - 28 08 08 0b 2c 28 e8 c5 78.338 - 28 08 08 cb 2b 28 e8 c5 78.337 - -Error 5 occurred at disk power-on lifetime: 1029 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:66 SN:41 CL:2d CH:70 D/H:e8 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 70 08 66 41 2d 70 e8 c4 69.020 - 70 08 68 3f 2d 70 e8 c4 64.956 - 70 08 6a 3d 2d 70 e8 c4 60.891 - 70 08 6c 3b 2d 70 e8 c4 56.826 - 70 08 fe a9 2c 70 e8 c4 52.713 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed: read failure 90% 1965 0x08702f11 -# 2 Short off-line Completed 00% 1800 -# 3 Short off-line Completed 00% 1778 -# 4 Short off-line Completed 00% 1777 diff --git a/www/examples/MAXTOR-1.txt b/www/examples/MAXTOR-1.txt deleted file mode 100644 index b1ed8ace35f6f00813087682bb8b1d9177b3ad2f..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-1.txt +++ /dev/null @@ -1,143 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119123435 -Firmware Version: A08.1500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Off-line data collection status: (0x04) Offline data collection activity was - suspended by an interrupting command from host. -Self-test execution status: ( 89) The previous self-test completed having - the electrical element of the test - failed. -Total time to complete off-line -data collection: (2536) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 074 074 020 Pre-fail - 3294 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 32 - 5 Reallocated_Sector_Ct 0x0033 001 001 020 Pre-fail FAILING_NOW 499 - 7 Seek_Error_Rate 0x000b 100 001 023 Pre-fail In_the_past 0 - 9 Power_On_Hours 0x0012 086 086 001 Old_age - 9812 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 32 - 13 Read_Soft_Error_Rate 0x000b 100 001 023 Pre-fail In_the_past 0 -194 Temperature_Centigrade 0x0022 091 086 042 Old_age - 24 -195 Hardware_ECC_Recovered 0x001a 006 004 000 Old_age - 417912090 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age - 0 -197 Current_Pending_Sector 0x0032 033 032 020 Old_age - 338 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -ATA Error Count: 20255 (device log contains only the most recent five errors) - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 1 occurred at disk power-on lifetime: 9574 hours -When the command that caused the error occurred, the device was in a vendor specific or reserved state. -After command completion occurred, registers were: -ER:40 SC:60 SN:b8 CL:c6 CH:02 D/H:e5 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 02 05 60 b8 c6 02 e5 c4 474.857 - 02 05 f8 20 c6 02 e5 c4 470.748 - 02 05 08 18 c6 02 e5 c4 470.746 - 00 00 f8 20 c5 02 e5 c4 470.732 - 00 00 08 18 c5 02 e5 c4 470.730 - -Error 2 occurred at disk power-on lifetime: 9574 hours -When the command that caused the error occurred, the device was in a vendor specific or reserved state. -After command completion occurred, registers were: -ER:40 SC:68 SN:b0 CL:c6 CH:02 D/H:e5 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 02 05 f8 20 c6 02 e5 c4 470.748 - 02 05 08 18 c6 02 e5 c4 470.746 - 00 00 f8 20 c5 02 e5 c4 470.732 - 00 00 08 18 c5 02 e5 c4 470.730 - 02 05 f8 20 c4 02 e5 c4 470.717 - -Error 3 occurred at disk power-on lifetime: 9574 hours -When the command that caused the error occurred, the device was in a vendor specific or reserved state. -After command completion occurred, registers were: -ER:40 SC:08 SN:c0 CL:3e CH:0e D/H:e5 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0e 05 08 c0 3e 0e e5 c4 181.677 - d0 04 08 b0 67 d0 e4 c5 181.651 - 0e 05 08 a0 45 0e e5 c4 181.646 - 0e 05 80 20 43 0e e5 c4 181.635 - 0e 05 80 20 41 0e e5 c4 181.622 - -Error 4 occurred at disk power-on lifetime: 9574 hours -When the command that caused the error occurred, the device was in a vendor specific or reserved state. -After command completion occurred, registers were: -ER:40 SC:60 SN:c0 CL:3e CH:0e D/H:e5 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0e 05 80 a0 3e 0e e5 c4 172.530 - 0e 05 80 20 3d 0e e5 c4 172.335 - 0e 05 80 20 3c 0e e5 c4 164.744 - 0e 05 10 10 3b 0e e5 c4 164.736 - 0e 05 f8 18 3a 0e e5 c4 157.202 - -Error 5 occurred at disk power-on lifetime: 9574 hours -When the command that caused the error occurred, the device was in a vendor specific or reserved state. -After command completion occurred, registers were: -ER:40 SC:c0 SN:18 CL:04 CH:d3 D/H:e4 ST:d1 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - d3 04 c0 18 04 d3 e4 c4 502.837 - d3 04 f8 e0 03 d3 e4 c4 498.739 - d3 04 f8 e8 02 d3 e4 c4 498.716 - 55 01 c8 90 70 55 e1 c4 498.705 - 55 01 38 48 70 55 e1 c4 498.680 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short off-line Completed: electrical failure 90% 9786 -# 2 Extended captive Completed: servo/seek failure 90% 9676 0x04b7ed3d -# 3 Extended captive Completed 00% 9575 -# 4 Extended off-line Completed 00% 9432 -# 5 Extended off-line Completed 00% 9415 diff --git a/www/examples/MAXTOR-10.txt b/www/examples/MAXTOR-10.txt deleted file mode 100644 index adb8beb9e75050ae872432eac6085f2878023613..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-10.txt +++ /dev/null @@ -1,188 +0,0 @@ -smartctl version 5.22 Copyright (C) 2002-3 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119014987 -Firmware Version: A08.1500 -Device is: In smartctl database [for details use: -P show] -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -Local Time is: Mon Oct 27 14:30:17 2003 CST -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Offline data collection status: (0x80) Offline data collection activity was - never started. - Auto Offline Data Collection: Enabled. -Self-test execution status: ( 112) The previous self-test completed having - the read element of the test failed. -Total time to complete Offline -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Auto Offline data collection on/off support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail Offline - 0 - 3 Spin_Up_Time 0x0027 075 074 020 Pre-fail Always - 3135 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age Always - 54 - 5 Reallocated_Sector_Ct 0x0033 098 097 020 Pre-fail Always - 14 - 7 Seek_Error_Rate 0x000b 100 100 023 Pre-fail Always - 0 - 9 Power_On_Hours 0x0012 072 072 001 Old_age Always - 18875 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age Always - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail Always - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age Always - 53 - 13 Read_Soft_Error_Rate 0x000b 100 085 023 Pre-fail Always - 0 -194 Temperature_Celsius 0x0022 093 088 042 Old_age Always - 20 -195 Hardware_ECC_Recovered 0x001a 028 002 000 Old_age Always - 1472864733 -196 Reallocated_Event_Count 0x0010 100 099 020 Old_age Offline - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age Always - 2 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age Always - 0 - -SMART Error Log Version: 1 -ATA Error Count: 28 (device log contains only the most recent five errors) - CR = Command Register [HEX] - FR = Features Register [HEX] - SC = Sector Count Register [HEX] - SN = Sector Number Register [HEX] - CL = Cylinder Low Register [HEX] - CH = Cylinder High Register [HEX] - DH = Device/Head Register [HEX] - DC = Device Command Register [HEX] - ER = Error register [HEX] - ST = Status register [HEX] -Timestamp = decimal seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 28 occurred at disk power-on lifetime: 18785 hours - When the command that caused the error occurred, the device was in an unknown state. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 d1 38 ce 8f 40 e0 Error: UNC - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 38 ce 8f 40 e0 40 315.769 READ DMA - c8 00 40 c6 8f 40 e0 40 311.634 READ DMA - b0 00 01 01 4f c2 e0 1f 284.485 [Reserved SMART command] - b0 00 01 06 4f c2 e0 34 284.470 [Reserved SMART command] - b0 00 01 00 4f c2 e0 34 284.399 [Reserved SMART command] - -Error 27 occurred at disk power-on lifetime: 18785 hours - When the command that caused the error occurred, the device was in an unknown state. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 38 ce 8f 40 e0 Error: UNC - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 40 c6 8f 40 e0 40 311.634 READ DMA - b0 00 01 01 4f c2 e0 1f 284.485 [Reserved SMART command] - b0 00 01 06 4f c2 e0 34 284.470 [Reserved SMART command] - b0 00 01 00 4f c2 e0 34 284.399 [Reserved SMART command] - b0 00 00 00 4f c2 00 34 284.328 [Reserved SMART command] - -Error 26 occurred at disk power-on lifetime: 18744 hours - When the command that caused the error occurred, the device was in an unknown state. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 d1 08 bf 00 30 e0 Error: UNC - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 00 08 bf 00 30 e0 30 134.258 READ DMA - c8 00 08 cf 3d 34 e0 34 134.247 READ DMA - c8 00 08 af 00 34 e0 34 134.215 READ DMA - c8 00 28 6f 3e 28 e0 28 134.213 READ DMA - c8 00 08 67 3e 28 e0 28 134.201 READ DMA - -Error 25 occurred at disk power-on lifetime: 18619 hours - When the command that caused the error occurred, the device was in an unknown state. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 07 89 67 10 e3 Error: UNC - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 03 08 88 67 10 e3 10 54.493 READ DMA - c8 03 08 88 69 08 e3 08 54.483 READ DMA - c8 03 08 88 67 08 e3 08 54.471 READ DMA - c8 02 08 88 69 ec e2 ec 54.464 READ DMA - c8 02 08 88 67 ec e2 ec 54.439 READ DMA - -Error 24 occurred at disk power-on lifetime: 18619 hours - When the command that caused the error occurred, the device was in an unknown state. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 59 06 8a 67 0c e2 Error: UNC - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - c8 02 08 88 67 0c e2 0c 49.281 READ DMA - c8 02 08 88 69 08 e2 08 49.270 READ DMA - c8 02 08 88 69 04 e2 04 49.259 READ DMA - c8 02 08 88 69 00 e2 00 49.257 READ DMA - c8 02 08 50 5c 00 e2 00 49.254 READ DMA - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended offline Completed: read failure 80% 18841 0x001f807f -# 2 Extended offline Completed: read failure 80% 18673 0x020c678a -# 3 Extended offline Completed: read failure 80% 18505 0x020c678a -# 4 Extended offline Completed: read failure 80% 18338 0x020c678a -# 5 Extended offline Completed: read failure 90% 18229 0x00408f96 -# 6 Extended offline Completed: read failure 80% 18171 0x02386789 -# 7 Extended offline Completed without error 00% 18051 - -# 8 Short offline Completed without error 00% 18051 - -# 9 Extended offline Completed without error 00% 18003 - -#10 Extended offline Completed without error 00% 17836 - -#11 Extended offline Completed without error 00% 17668 - -#12 Extended offline Completed without error 00% 17501 - -#13 Extended offline Completed without error 00% 17334 - -#14 Extended offline Completed without error 00% 17166 - -#15 Extended offline Completed without error 00% 16999 - -#16 Extended offline Completed without error 00% 16831 - -#17 Extended offline Completed without error 00% 16664 - -#18 Extended offline Completed without error 00% 16603 - -#19 Extended offline Completed without error 00% 16497 - -#20 Extended offline Completed without error 00% 16329 - -#21 Extended offline Completed without error 00% 16163 - - diff --git a/www/examples/MAXTOR-2.txt b/www/examples/MAXTOR-2.txt deleted file mode 100644 index 9ff60ffcb3927d55bfa1c40ff5b803b9cc9ced87..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-2.txt +++ /dev/null @@ -1,79 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119113862 -Firmware Version: A08.1500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED -See vendor-specific Attribute list for marginal Attributes. - -General SMART Values: -Off-line data collection status: (0x05) Offline data collection activity was - aborted by an interrupting command from host. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 075 075 020 Pre-fail - 3249 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 31 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 001 023 Pre-fail In_the_past 0 - 9 Power_On_Hours 0x0012 086 086 001 Old_age - 9754 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 31 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail - 0 -194 Temperature_Centigrade 0x0022 035 032 042 Old_age FAILING_NOW 168 -195 Hardware_ECC_Recovered 0x001a 100 002 000 Old_age - 880099716 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age - 0 -198 Offline_Uncorrectable 0x0010 100 253 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short off-line Completed 00% 9691 -# 2 Short captive Completed 00% 9691 -# 3 Extended captive Completed 00% 9618 -# 4 Extended captive Interrupted (host reset) 90% 9563 -# 5 Short captive Completed 00% 9563 -# 6 Short off-line Completed 00% 9563 -# 7 Short captive Completed 00% 9545 -# 8 Extended off-line Completed 00% 9541 -# 9 Short captive Completed 00% 9541 -#10 Extended off-line Completed 00% 9537 -#11 Extended off-line Completed 00% 9536 -#12 Extended off-line Interrupted (host reset) 90% 9534 -#13 Extended off-line Completed 00% 9517 -#14 Extended off-line Completed 00% 9484 diff --git a/www/examples/MAXTOR-3.txt b/www/examples/MAXTOR-3.txt deleted file mode 100644 index 26df69e5977a8b4e46958290ac79b663d7246e4e..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-3.txt +++ /dev/null @@ -1,67 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 6L080J4 -Serial Number: 664201100034 -Firmware Version: A93.0500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 35) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 40) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 069 066 020 Pre-fail - 3984 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 110 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 023 Pre-fail - 0 - 9 Power_On_Hours 0x0012 099 099 001 Old_age - 1294 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 110 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail - 0 -194 Temperature_Centigrade 0x0022 092 087 042 Old_age - 22 -195 Hardware_ECC_Recovered 0x001a 100 100 000 Old_age - 1163 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age - 0 -198 Offline_Uncorrectable 0x0010 100 253 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 1038 -# 2 Extended off-line Aborted by host 00% 786 -# 3 Extended off-line Aborted by host 00% 786 diff --git a/www/examples/MAXTOR-4.txt b/www/examples/MAXTOR-4.txt deleted file mode 100644 index 65ae2850d953448898079f827870b697f26dc07d..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-4.txt +++ /dev/null @@ -1,65 +0,0 @@ -smartctl version 5.0-24 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 6L080J4 -Serial Number: 664205757172 -Firmware Version: A93.0500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x04) Offline data collection activity was - suspended by an interrupting command from host. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 35) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 40) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 065 064 020 Pre-fail - 4481 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 81 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 023 Pre-fail - 0 - 9 Power_On_Hours 0x0012 098 098 001 Old_age - 1767 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 100 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 81 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail - 0 -194 Temperature_Centigrade 0x0022 091 084 042 Old_age - 24 -195 Hardware_ECC_Recovered 0x001a 100 100 000 Old_age - 52795 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age - 0 -198 Offline_Uncorrectable 0x0010 100 253 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 1283 diff --git a/www/examples/MAXTOR-6.txt b/www/examples/MAXTOR-6.txt deleted file mode 100644 index fe37f6541cc9b0f487578982b94f6a4931f984fd..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-6.txt +++ /dev/null @@ -1,156 +0,0 @@ -# /usr/sbin/smartctl -a -m /dev/hda -smartctl version 5.0-49 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: Maxtor 4R080J0 -Serial Number: R20BZ3LE -Firmware Version: RAMB1TU0 -ATA Version is: 7 -ATA Standard is: Unrecognized. Minor revision code: 0x1e -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x82) Offline data collection activity - completed without error. -Self-test execution status: ( 33) The self-test routine was interrupted - by the host with a hard or soft reset. -Total time to complete off-line -data collection: ( 241) seconds. -Offline data collection -capabilities: (0x5b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 41) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 3 Spin_Up_Time 0x0027 252 252 063 Pre-fail - 1621 - 4 Start_Stop_Count 0x0032 253 253 000 Old_age - 18 - 5 Reallocated_Sector_Ct 0x0033 253 253 063 Pre-fail - 0 - 6 Read_Channel_Margin 0x0001 253 253 100 Pre-fail - 0 - 7 Seek_Error_Rate 0x000a 253 252 000 Old_age - 0 - 8 Seek_Time_Performance 0x0027 252 244 187 Pre-fail - 41642 - 9 Power_On_Hours 0x0032 253 253 000 Old_age - 27 h + 13 m - 10 Spin_Retry_Count 0x002b 252 252 157 Pre-fail - 0 - 11 Calibration_Retry_Count 0x002b 253 252 223 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 253 253 000 Old_age - 24 -192 Power-Off_Retract_Count 0x0032 253 253 000 Old_age - 0 -193 Load_Cycle_Count 0x0032 253 253 000 Old_age - 0 -194 Temperature_Celsius 0x0032 253 253 000 Old_age - 29 -195 Hardware_ECC_Recovered 0x000a 253 252 000 Old_age - 31004 -196 Reallocated_Event_Count 0x0008 253 253 000 Old_age - 0 -197 Current_Pending_Sector 0x0008 253 253 000 Old_age - 0 -198 Offline_Uncorrectable 0x0008 253 253 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x0008 199 199 000 Old_age - 0 -200 Multi_Zone_Error_Rate 0x000a 253 252 000 Old_age - 0 -201 Unknown_Attribute 0x000a 253 252 000 Old_age - 3 -202 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -203 Unknown_Attribute 0x000b 253 252 180 Pre-fail - 2 -204 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -205 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -207 Unknown_Attribute 0x002a 252 252 000 Old_age - 0 -208 Unknown_Attribute 0x002a 252 252 000 Old_age - 0 -209 Unknown_Attribute 0x0024 079 063 000 Old_age - 0 - 99 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 -100 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 -101 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 - -SMART Error Log Version: 1 -ATA Error Count: 5 - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 5 occurred at disk power-on lifetime: 4 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:00 SN:00 CL:f4 CH:2c D/H:00 ST:01 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0e d4 00 82 4f c2 f0 b0 8907.296 - 08 d4 00 82 4f c2 f0 b0 6260.832 - 08 d1 01 01 4f c2 f0 b0 6260.800 - 08 d0 01 00 4f c2 f0 b0 6260.768 - 08 da 00 00 4f c2 10 b0 6260.736 - -Error 4 occurred at disk power-on lifetime: 1 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:00 SN:00 CL:f4 CH:2c D/H:00 ST:01 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0e d4 00 82 4f c2 f0 b0 1944.192 - 08 d4 00 82 4f c2 f0 b0 1824.240 - 08 d1 01 01 4f c2 f0 b0 1824.224 - 08 d0 01 00 4f c2 f0 b0 1824.160 - 08 00 08 3f 00 00 f0 ca 1810.400 - -Error 3 occurred at disk power-on lifetime: 1 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:00 SN:00 CL:f4 CH:2c D/H:00 ST:01 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0e d4 00 82 4f c2 f0 b0 1456.432 - 08 d4 00 82 4f c2 f0 b0 1379.456 - 08 d1 01 01 4f c2 f0 b0 1379.440 - 08 d0 01 00 4f c2 f0 b0 1379.376 - 08 00 08 f7 01 54 f0 ca 1378.544 - -Error 2 occurred at disk power-on lifetime: 0 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:00 SN:00 CL:f4 CH:2c D/H:00 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 08 d4 00 82 4f c2 f0 b0 908.320 - 08 d1 01 01 4f c2 f0 b0 908.320 - 08 d0 01 00 4f c2 f0 b0 908.272 - 08 d4 00 7f 4f c2 f0 b0 905.696 - 08 d1 01 01 4f c2 f0 b0 905.664 - -Error 1 occurred at disk power-on lifetime: 0 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:50 SN:40 CL:97 CH:03 D/H:10 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 fe 00 00 00 00 10 ef 137.184 - 00 3d 00 00 00 00 10 c3 137.136 - 00 e4 00 00 00 00 10 c3 137.088 - 00 3d 00 00 00 00 10 c3 137.088 - 00 00 00 00 5e 20 10 70 137.040 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended captive Interrupted (host reset) 10% 4 -# 2 Short off-line Completed 00% 2 -# 3 Short captive Completed 00% 2 -# 4 Extended captive Interrupted (host reset) 40% 1 -# 5 Extended captive Interrupted (host reset) 70% 1 -# 6 Extended captive Interrupted (host reset) 40% 0 diff --git a/www/examples/MAXTOR-7.txt b/www/examples/MAXTOR-7.txt deleted file mode 100644 index 1d3fa00491946ea74388b37962bdac003ee8c829..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-7.txt +++ /dev/null @@ -1,157 +0,0 @@ -smartctl version 5.1-4 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119114160 -Firmware Version: A08.1500 -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -Local Time is: Tue May 13 08:59:49 2003 CDT -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Off-line data collection status: (0x82) Offline data collection activity - completed without error. -Self-test execution status: ( 112) The previous self-test completed having - the read element of the test failed. -Total time to complete off-line -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 075 075 020 Pre-fail - 3214 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age - 58 - 5 Reallocated_Sector_Ct 0x0033 098 098 020 Pre-fail - 12 - 7 Seek_Error_Rate 0x000b 001 001 023 Pre-fail FAILING_NOW 13 - 9 Power_On_Hours 0x0012 078 078 001 Old_age - 14851 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age - 0 - 11 Calibration_Retry_Count 0x0013 100 090 020 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age - 58 - 13 Read_Soft_Error_Rate 0x000b 100 085 023 Pre-fail - 0 -194 Temperature_Celsius 0x0022 091 087 042 Old_age - 24 -195 Hardware_ECC_Recovered 0x001a 004 003 000 Old_age - 513691822 -196 Reallocated_Event_Count 0x0010 099 099 020 Old_age - 1 -197 Current_Pending_Sector 0x0032 098 098 020 Old_age - 12 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age - 0 - -SMART Error Log Version: 1 -ATA Error Count: 25 (device log contains only the most recent five errors) - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 25 occurred at disk power-on lifetime: 14799 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:04 SN:53 CL:1d CH:0c D/H:e0 ST:59 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0c 00 08 4f 1d 0c e0 c8 0.523 - 0c 00 08 47 1d 0c e0 c8 510.677 - 04 00 08 6f 04 04 e0 ca 510.675 - 04 00 08 4f 1c 04 e0 ca 510.674 - 04 00 08 6f 04 04 e0 ca 510.674 - -Error 24 occurred at disk power-on lifetime: 14799 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:03 SN:44 CL:1d CH:0c D/H:e0 ST:59 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0c 00 08 3f 1d 0c e0 c8 495.294 - 0c 00 08 37 1d 0c e0 c8 491.239 - 0c 00 08 2f 1d 0c e0 c8 488.433 - 14 00 08 17 04 14 e0 ca 488.432 - 0c 00 08 b7 00 0c e0 ca 488.432 - -Error 23 occurred at disk power-on lifetime: 14799 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:06 SN:21 CL:18 CH:0c D/H:e0 ST:59 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0c 00 08 1f 18 0c e0 c8 392.659 - 00 00 08 17 18 0c e0 c8 392.654 - 0c 00 08 0f 18 0c e0 c8 392.624 - 00 00 08 07 18 0c e0 c8 392.620 - 00 00 08 ff 17 0c e0 c8 392.615 - -Error 22 occurred at disk power-on lifetime: 14799 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:05 SN:b2 CL:16 CH:0c D/H:e0 ST:59 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0c 00 08 af 16 0c e0 c8 385.889 - 04 00 08 6f 04 04 e0 ca 385.886 - 04 00 08 4f 1c 04 e0 ca 385.886 - 04 00 08 6f 04 04 e0 ca 385.886 - 04 00 08 4f 1c 04 e0 ca 385.885 - -Error 21 occurred at disk power-on lifetime: 14799 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:40 SC:06 SN:a9 CL:16 CH:0c D/H:e0 ST:59 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 0c 00 08 a7 16 0c e0 c8 381.795 - 04 00 08 6f 04 04 e0 ca 381.793 - 04 00 08 4f 1c 04 e0 ca 381.793 - 04 00 08 6f 04 04 e0 ca 381.792 - 04 00 08 4f 1c 04 e0 ca 381.792 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed: read failure 90% 14757 0x000409bb -# 2 Extended off-line Completed: read failure 90% 14755 0x000bf956 -# 3 Extended off-line Completed 00% 14305 - -# 4 Extended off-line Completed 00% 14100 - -# 5 Extended off-line Completed 00% 13721 - -# 6 Extended off-line Completed 00% 13636 - -# 7 Extended off-line Completed 00% 13233 - -# 8 Extended off-line Completed 00% 13078 - -# 9 Extended off-line Completed 00% 12093 - -#10 Extended off-line Completed 00% 11926 - -#11 Extended off-line Completed 00% 11428 - -#12 Extended off-line Completed 00% 11030 - -#13 Extended off-line Completed 00% 10888 - -#14 Extended off-line Completed 00% 10728 - -#15 Extended off-line Completed 00% 10435 - -#16 Extended off-line Completed 00% 10267 - -#17 Extended off-line Completed 00% 10098 - -#18 Extended off-line Completed 00% 9930 - -#19 Extended off-line Completed 00% 9599 - diff --git a/www/examples/MAXTOR-8.txt b/www/examples/MAXTOR-8.txt deleted file mode 100644 index 3ae4d87735563a46d403293ec5ce00b26d6bb3d0..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-8.txt +++ /dev/null @@ -1,82 +0,0 @@ -smartctl version 5.1-14 Copyright (C) 2002-3 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119116076 -Firmware Version: A08.1500 -Device is: In smartctl database [for details use: -P show] -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -Local Time is: Tue Jun 17 14:46:37 2003 CDT -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Off-line data collection status: (0x82) Offline data collection activity was - completed without error. - Auto Off-line Data Collection: Enabled. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail Offline - 0 - 3 Spin_Up_Time 0x0027 075 075 020 Pre-fail Always - 3249 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age Always - 45 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail Always - 0 - 7 Seek_Error_Rate 0x000b 100 001 023 Pre-fail Always In_the_past 0 - 9 Power_On_Hours 0x0012 082 082 001 Old_age Always - 12223 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age Always - 0 - 11 Calibration_Retry_Count 0x0013 020 020 020 Pre-fail Always FAILING_NOW 8 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age Always - 45 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail Always - 0 -194 Temperature_Celsius 0x0022 094 088 042 Old_age Always - 17 -195 Hardware_ECC_Recovered 0x001a 100 007 000 Old_age Always - 494134044 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age Offline - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age Always - 0 -198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age Always - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 11610 - -# 2 Extended off-line Completed 00% 11213 - -# 3 Extended off-line Completed 00% 11072 - -# 4 Extended off-line Completed 00% 10911 - -# 5 Extended off-line Completed 00% 10618 - -# 6 Extended off-line Completed 00% 10450 - -# 7 Extended off-line Completed 00% 10282 - -# 8 Extended off-line Completed 00% 10114 - -# 9 Extended off-line Completed 00% 9783 - - diff --git a/www/examples/MAXTOR-9.txt b/www/examples/MAXTOR-9.txt deleted file mode 100644 index 6a692423d766812c05a4c6f298bda322d780a655..0000000000000000000000000000000000000000 --- a/www/examples/MAXTOR-9.txt +++ /dev/null @@ -1,94 +0,0 @@ -smartctl version 5.1-14 Copyright (C) 2002-3 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: MAXTOR 4K080H4 -Serial Number: 674119123112 -Firmware Version: A08.1500 -Device is: In smartctl database [for details use: -P show] -ATA Version is: 5 -ATA Standard is: ATA/ATAPI-5 T13 1321D revision 1 -Local Time is: Tue Aug 19 02:06:11 2003 CDT -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Off-line data collection status: (0x80) Offline data collection activity was - never started. - Auto Off-line Data Collection: Enabled. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 44) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - No Conveyance Self-test supported. - No Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 50) minutes. - -SMART Attributes Data Structure revision number: 11 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x0029 100 253 020 Pre-fail Offline - 0 - 3 Spin_Up_Time 0x0027 075 074 020 Pre-fail Always - 3186 - 4 Start_Stop_Count 0x0032 100 100 008 Old_age Always - 68 - 5 Reallocated_Sector_Ct 0x0033 100 100 020 Pre-fail Always - 0 - 7 Seek_Error_Rate 0x000b 100 100 023 Pre-fail Always - 0 - 9 Power_On_Hours 0x0012 074 074 001 Old_age Always - 17202 - 10 Spin_Retry_Count 0x0026 100 100 000 Old_age Always - 0 - 11 Calibration_Retry_Count 0x0013 010 010 020 Pre-fail Always FAILING_NOW 9 - 12 Power_Cycle_Count 0x0032 100 100 008 Old_age Always - 68 - 13 Read_Soft_Error_Rate 0x000b 100 100 023 Pre-fail Always - 0 -194 Temperature_Celsius 0x0022 092 087 042 Old_age Always - 22 -195 Hardware_ECC_Recovered 0x001a 018 003 000 Old_age Always - 1082933060 -196 Reallocated_Event_Count 0x0010 100 100 020 Old_age Offline - 0 -197 Current_Pending_Sector 0x0032 100 100 020 Old_age Always - 0 -198 Offline_Uncorrectable 0x0010 100 253 000 Old_age Offline - 0 -199 UDMA_CRC_Error_Count 0x001a 200 200 000 Old_age Always - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 17157 - -# 2 Extended off-line Completed 00% 16990 - -# 3 Extended off-line Completed 00% 16823 - -# 4 Extended off-line Completed 00% 16657 - -# 5 Extended off-line Completed 00% 16598 - -# 6 Extended off-line Completed 00% 16490 - -# 7 Extended off-line Completed 00% 16323 - -# 8 Extended off-line Completed 00% 16157 - -# 9 Extended off-line Completed 00% 15991 - -#10 Extended off-line Completed 00% 15696 - -#11 Extended off-line Completed 00% 15614 - -#12 Extended off-line Completed 00% 15241 - -#13 Extended off-line Completed 00% 15026 - -#14 Extended off-line Completed 00% 14785 - -#15 Extended off-line Completed 00% 14334 - -#16 Extended off-line Completed 00% 14129 - -#17 Extended off-line Completed 00% 13750 - -#18 Extended off-line Completed 00% 13665 - -#19 Extended off-line Completed 00% 13262 - -#20 Extended off-line Completed 00% 13108 - -#21 Extended off-line Completed 00% 12125 - - diff --git a/www/examples/Maxtor-5.txt b/www/examples/Maxtor-5.txt deleted file mode 100644 index 3bb171eb6fd032d5ad56dea9925c85bec295c545..0000000000000000000000000000000000000000 --- a/www/examples/Maxtor-5.txt +++ /dev/null @@ -1,127 +0,0 @@ -smartctl version 5.0-36 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: Maxtor 98196H8 -Serial Number: V80HV6NC -Firmware Version: ZAH814Y0 -ATA Version is: 6 -ATA Standard is: ATA/ATAPI-6 T13 1410D revision 0 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 30) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 60) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000a 253 252 000 Old_age - 26 - 3 Spin_Up_Time 0x0027 208 206 063 Pre-fail - 11285 - 4 Start_Stop_Count 0x0032 253 253 000 Old_age - 62 - 5 Reallocated_Sector_Ct 0x0033 253 253 063 Pre-fail - 0 - 6 Read_Channel_Margin 0x0001 253 253 100 Pre-fail - 0 - 7 Seek_Error_Rate 0x000a 253 252 000 Old_age - 0 - 8 Seek_Time_Performance 0x0027 249 244 187 Pre-fail - 50271 - 9 Power_On_Hours 0x0032 236 236 000 Old_age - 32671 - 10 Spin_Retry_Count 0x002b 253 252 223 Pre-fail - 0 - 11 Calibration_Retry_Count 0x002b 253 252 223 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 253 253 000 Old_age - 67 -196 Reallocated_Event_Count 0x0008 253 253 000 Old_age - 0 -197 Current_Pending_Sector 0x0008 253 253 000 Old_age - 0 -198 Offline_Uncorrectable 0x0008 253 253 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x0008 199 199 000 Old_age - 0 -200 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -201 Unknown_Attribute 0x000a 253 252 000 Old_age - 1 -202 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -203 Unknown_Attribute 0x000b 253 252 180 Pre-fail - 2 -204 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -205 Unknown_Attribute 0x000a 253 252 000 Old_age - 0 -207 Unknown_Attribute 0x002a 253 252 000 Old_age - 0 -208 Unknown_Attribute 0x002a 253 252 000 Old_age - 0 -209 Unknown_Attribute 0x0024 253 253 000 Old_age - 0 - 96 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 - 97 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 - 98 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 - 99 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 -100 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 -101 Unknown_Attribute 0x0004 253 253 000 Old_age - 0 - -SMART Error Log Version: 1 -ATA Error Count: 3 - DCR = Device Control Register - FR = Features Register - SC = Sector Count Register - SN = Sector Number Register - CL = Cylinder Low Register - CH = Cylinder High Register - D/H = Device/Head Register - CR = Content written to Command Register - ER = Error register - STA = Status register -Timestamp is seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 1 occurred at disk power-on lifetime: 0 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:40 SN:42 CL:97 CH:23 D/H:00 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 fe 00 00 00 00 00 ef 137.440 - 00 d9 00 00 4f c2 00 b0 137.328 - 00 da 00 00 4f c2 00 b0 137.232 - 00 d8 00 00 4f c2 00 b0 137.152 - 00 db 00 00 4f c2 00 b0 136.976 - -Error 2 occurred at disk power-on lifetime: 0 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:40 SN:40 CL:97 CH:23 D/H:00 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 fe 00 00 00 00 00 ef 342.432 - 00 e4 00 00 00 00 00 c3 342.368 - 00 d0 00 00 0a 00 00 c3 342.368 - 00 fe 00 00 00 00 00 ef 342.304 - 00 3d 00 00 00 00 00 c3 342.256 - -Error 3 occurred at disk power-on lifetime: 0 hours -When the command that caused the error occurred, the device was in an unknown state. -After command completion occurred, registers were: -ER:04 SC:40 SN:40 CL:97 CH:03 D/H:00 ST:51 -Sequence of commands leading to the command that caused the error were: -DCR FR SC SN CL CH D/H CR Timestamp - 00 fe 00 00 00 00 00 ef 342.304 - 00 3d 00 00 00 00 00 c3 342.256 - 00 e4 00 00 00 00 00 c3 342.192 - 00 3d 00 00 00 00 00 c3 342.192 - 00 00 01 01 00 00 00 ec 342.144 - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short off-line Completed 00% 5255 diff --git a/www/examples/TOSHIBA-0.txt b/www/examples/TOSHIBA-0.txt deleted file mode 100644 index 965e55d99af8af42a5d6592c3159dd9fbb70312a..0000000000000000000000000000000000000000 --- a/www/examples/TOSHIBA-0.txt +++ /dev/null @@ -1,73 +0,0 @@ -smartctl version 5.0-31 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: TOSHIBA MK2018GAS -Serial Number: X22F7553T -Firmware Version: Q2.03 D -ATA Version is: 5 -ATA Standard is: Unrecognized. Minor revision code: 0x00 -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 212) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 23) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 100 100 050 Pre-fail - 0 - 2 Throughput_Performance 0x0005 100 100 050 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 100 100 001 Pre-fail - 910 - 4 Start_Stop_Count 0x0032 100 100 000 Old_age - 18 - 5 Reallocated_Sector_Ct 0x0033 100 100 050 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 050 Pre-fail - 0 - 8 Seek_Time_Performance 0x0005 100 100 050 Pre-fail - 0 - 9 Power_On_Hours 0x0032 100 100 000 Old_age - 9 - 10 Spin_Retry_Count 0x0033 100 100 030 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age - 18 -192 Power-Off_Retract_Count 0x0032 100 100 000 Old_age - 6 -193 Load_Cycle_Count 0x0032 100 100 000 Old_age - 437 -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age - 0 -197 Current_Pending_Sector 0x0032 100 100 000 Old_age - 0 -198 Offline_Uncorrectable 0x0030 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x0032 200 200 000 Old_age - 0 -220 Disk_Shift 0x0002 100 100 000 Old_age - 4250 -222 Loaded_Hours 0x0032 100 100 000 Old_age - 4 -223 Load_Retry_Count 0x0032 100 100 000 Old_age - 0 -224 Load_Friction 0x0022 100 100 000 Old_age - 0 -226 Load-in_Time 0x0026 100 100 000 Old_age - 590 -240 Unknown_Attribute 0x0001 100 100 001 Pre-fail - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 4 -# 2 Short captive Completed 00% 0 -# 3 Short off-line Completed 00% 0 diff --git a/www/examples/TOSHIBA-MK6021GAS.txt b/www/examples/TOSHIBA-MK6021GAS.txt deleted file mode 100644 index 776cb3dcee4f794a875c763556a27b001893c597..0000000000000000000000000000000000000000 --- a/www/examples/TOSHIBA-MK6021GAS.txt +++ /dev/null @@ -1,74 +0,0 @@ -smartctl version 5.1-7 Copyright (C) 2002 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: TOSHIBA MK6021GAS -Serial Number: Y2MJ1530T -Firmware Version: GA023A -ATA Version is: 5 -ATA Standard is: Unrecognized. Minor revision code: 0x00 -Local Time is: Mon Feb 17 09:37:27 2003 CST -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: PASSED - -General SMART Values: -Off-line data collection status: (0x00) Offline data collection activity was - never started. -Self-test execution status: ( 0) The previous self-test routine completed - without error or no self-test has ever - been run. -Total time to complete off-line -data collection: ( 587) seconds. -Offline data collection -capabilities: (0x1b) SMART execute Offline immediate. - Automatic timer ON/OFF support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 65) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 100 100 050 Pre-fail - 0 - 2 Throughput_Performance 0x0005 100 100 050 Pre-fail - 0 - 3 Spin_Up_Time 0x0027 100 100 001 Pre-fail - 1267 - 4 Start_Stop_Count 0x0032 100 100 000 Old_age - 18 - 5 Reallocated_Sector_Ct 0x0033 100 100 050 Pre-fail - 0 - 7 Seek_Error_Rate 0x000b 100 100 050 Pre-fail - 0 - 8 Seek_Time_Performance 0x0005 100 100 050 Pre-fail - 0 - 9 Power_On_Hours 0x0032 100 100 000 Old_age - 39 - 10 Spin_Retry_Count 0x0033 100 100 030 Pre-fail - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age - 16 -192 Power-Off_Retract_Count 0x0032 100 100 000 Old_age - 1 -193 Load_Cycle_Count 0x0032 100 100 000 Old_age - 460 -194 Temperature_Celsius 0x0022 100 100 000 Old_age - 40 (Lifetime Min/Max 17/51) -196 Reallocated_Event_Count 0x0032 100 100 000 Old_age - 0 -197 Current_Pending_Sector 0x0032 100 100 000 Old_age - 0 -198 Offline_Uncorrectable 0x0030 100 100 000 Old_age - 0 -199 UDMA_CRC_Error_Count 0x0032 200 200 000 Old_age - 0 -220 Disk_Shift 0x0002 100 100 000 Old_age - 8332 -222 Loaded_Hours 0x0032 100 100 000 Old_age - 30 -223 Load_Retry_Count 0x0032 100 100 000 Old_age - 0 -224 Load_Friction 0x0022 100 100 000 Old_age - 0 -226 Load-in_Time 0x0026 100 100 000 Old_age - 159 -240 Head flying hours 0x0001 100 100 001 Pre-fail - 0 - -SMART Error Log Version: 1 -No Errors Logged - -SMART Self-test log, version number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Extended off-line Completed 00% 4 - - diff --git a/www/examples/WD2500JB.txt b/www/examples/WD2500JB.txt deleted file mode 100644 index 04e963a8b2bbeff348eb643fcb2e4748c210356f..0000000000000000000000000000000000000000 --- a/www/examples/WD2500JB.txt +++ /dev/null @@ -1,192 +0,0 @@ -smartctl version 5.30 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -=== START OF INFORMATION SECTION === -Device Model: WDC WD2500JB-32EVA0 -Serial Number: WD-WMAEH1156826 -Firmware Version: 15.05R15 -Device is: In smartctl database [for details use: -P show] -ATA Version is: 6 -ATA Standard is: Exact ATA specification draft version not indicated -Local Time is: Fri Jun 25 08:14:16 2004 CDT -SMART support is: Available - device has SMART capability. -SMART support is: Enabled - -=== START OF READ SMART DATA SECTION === -SMART overall-health self-assessment test result: FAILED! -Drive failure expected in less than 24 hours. SAVE ALL DATA. -See vendor-specific Attribute list for failed Attributes. - -General SMART Values: -Offline data collection status: (0x84) Offline data collection activity was - suspended by an interrupting command from host. - Auto Offline Data Collection: Enabled. -Self-test execution status: ( 73) The previous self-test completed having - a test element that failed and the test - element that failed is not known. -Total time to complete Offline -data collection: (7608) seconds. -Offline data collection -capabilities: (0x7b) SMART execute Offline immediate. - Auto Offline data collection on/off support. - Suspend Offline collection upon new - command. - Offline surface scan supported. - Self-test supported. - Conveyance Self-test supported. - Selective Self-test supported. -SMART capabilities: (0x0003) Saves SMART data before entering - power-saving mode. - Supports SMART auto save timer. -Error logging capability: (0x01) Error logging supported. - No General Purpose Logging support. -Short self-test routine -recommended polling time: ( 2) minutes. -Extended self-test routine -recommended polling time: ( 95) minutes. -Conveyance self-test routine -recommended polling time: ( 5) minutes. - -SMART Attributes Data Structure revision number: 16 -Vendor Specific SMART Attributes with Thresholds: -ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE - 1 Raw_Read_Error_Rate 0x000b 001 001 051 Pre-fail Always FAILING_NOW 2777 - 3 Spin_Up_Time 0x0007 125 120 021 Pre-fail Always - 4283 - 4 Start_Stop_Count 0x0032 100 100 040 Old_age Always - 133 - 5 Reallocated_Sector_Ct 0x0033 199 199 140 Pre-fail Always - 1 - 7 Seek_Error_Rate 0x000b 200 200 051 Pre-fail Always - 0 - 9 Power_On_Hours 0x0032 092 092 000 Old_age Always - 6545 - 10 Spin_Retry_Count 0x0013 100 100 051 Pre-fail Always - 0 - 11 Calibration_Retry_Count 0x0013 100 100 051 Pre-fail Always - 0 - 12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 133 -194 Temperature_Celsius 0x0022 128 253 000 Old_age Always - 22 -196 Reallocated_Event_Count 0x0032 199 199 000 Old_age Always - 1 -197 Current_Pending_Sector 0x0012 200 200 000 Old_age Always - 13 -198 Offline_Uncorrectable 0x0012 200 200 000 Old_age Always - 0 -199 UDMA_CRC_Error_Count 0x000a 200 253 000 Old_age Always - 1 -200 Multi_Zone_Error_Rate 0x0009 200 155 051 Pre-fail Offline - 0 - -SMART Error Log Version: 1 -ATA Error Count: 50 (device log contains only the most recent five errors) - CR = Command Register [HEX] - FR = Features Register [HEX] - SC = Sector Count Register [HEX] - SN = Sector Number Register [HEX] - CL = Cylinder Low Register [HEX] - CH = Cylinder High Register [HEX] - DH = Device/Head Register [HEX] - DC = Device Command Register [HEX] - ER = Error register [HEX] - ST = Status register [HEX] -Timestamp = decimal seconds since the previous disk power-on. -Note: timestamp "wraps" after 2^32 msec = 49.710 days. - -Error 50 occurred at disk power-on lifetime: 1082 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 07 82 a9 ee e0 Error: - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 00 00 25 00 00 07 00 00 2825901.100 NOP [Abort queued commands] - 03 00 82 00 00 5f 67 00 2825901.100 CFA REQUEST EXTENDED ERROR CODE - 00 00 25 00 00 01 00 00 2825901.100 NOP [Abort queued commands] - 00 00 25 00 00 08 00 00 2825901.100 NOP [Abort queued commands] - 12 00 ee 00 00 5f a9 00 2825901.100 RECALIBRATE [RET-4] - -Error 49 occurred at disk power-on lifetime: 1082 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 07 82 a9 ee e0 Error: - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 00 00 25 00 00 07 00 00 2825899.350 NOP [Abort queued commands] - 12 00 ee 00 00 7f a9 00 2825899.350 RECALIBRATE [RET-4] - 00 00 25 00 00 08 00 00 2825899.350 NOP [Abort queued commands] - 00 00 25 00 00 08 00 00 2825899.350 NOP [Abort queued commands] - 12 00 ee 00 00 5f a9 00 2825899.350 RECALIBRATE [RET-4] - -Error 48 occurred at disk power-on lifetime: 1082 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 08 17 a9 ee e0 Error: - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 00 00 25 00 00 08 00 00 2825880.900 NOP [Abort queued commands] - 00 00 d6 00 00 77 ad 00 2825880.900 NOP [Abort queued commands] - 00 00 25 00 00 08 00 00 2825880.900 NOP [Abort queued commands] - 00 00 d0 00 00 5f 5c 00 2825880.900 NOP [Abort queued commands] - 00 00 35 00 00 08 00 00 2825880.900 NOP [Abort queued commands] - -Error 47 occurred at disk power-on lifetime: 1082 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 08 17 a9 ee e0 Error: - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 00 00 25 00 00 08 00 00 2825879.000 NOP [Abort queued commands] - 00 00 d6 00 00 77 ad 00 2825879.000 NOP [Abort queued commands] - 00 00 35 00 00 08 00 00 2825879.000 NOP [Abort queued commands] - 00 00 35 00 00 08 00 00 2825879.000 NOP [Abort queued commands] - 06 00 8a 00 00 4f 3b 00 2825879.000 [RESERVED] - -Error 46 occurred at disk power-on lifetime: 1082 hours - When the command that caused the error occurred, the device was doing SMART Offline or Self-test. - - After command completion occurred, registers were: - ER ST SC SN CL CH DH - -- -- -- -- -- -- -- - 40 51 08 c5 a8 ee e0 Error: - - Commands leading to the command that caused the error were: - CR FR SC SN CL CH DH DC Timestamp Command/Feature_Name - -- -- -- -- -- -- -- -- --------- -------------------- - 00 00 25 00 00 08 00 00 2825875.250 NOP [Abort queued commands] - 00 00 25 00 00 08 00 00 2825875.250 NOP [Abort queued commands] - 06 00 ba 00 00 f7 66 00 2825875.250 [RESERVED] - 00 00 35 00 00 10 00 00 2825875.250 NOP [Abort queued commands] - 06 00 ba 00 00 1f 66 00 2825875.250 [RESERVED] - -SMART Self-test log structure revision number 1 -Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error -# 1 Short offline Completed: unknown failure 90% 1077 0xfff00000 -# 2 Short offline Completed without error 00% 1053 - -# 3 Short offline Completed without error 00% 1030 - -# 4 Short offline Completed without error 00% 1007 - -# 5 Short offline Completed without error 00% 983 - -# 6 Extended offline Completed without error 00% 961 - -# 7 Short offline Completed without error 00% 938 - -# 8 Short offline Completed without error 00% 914 - -# 9 Short offline Completed without error 00% 891 - -#10 Short offline Completed without error 00% 868 - -#11 Short offline Completed without error 00% 844 - -#12 Short offline Completed without error 00% 821 - -#13 Extended offline Completed without error 00% 799 - -#14 Short offline Completed without error 00% 775 - -#15 Short offline Completed without error 00% 752 - -#16 Short offline Completed without error 00% 728 - -#17 Short offline Completed without error 00% 705 - -#18 Short offline Completed without error 00% 682 - -#19 Short offline Completed without error 00% 659 - -#20 Extended offline Completed without error 00% 637 - -#21 Short offline Completed without error 00% 613 - - diff --git a/www/examples/atapi_cdrw_smt_a.html b/www/examples/atapi_cdrw_smt_a.html deleted file mode 100644 index 3e6cea3184ec067f6462097c24d5d00c78abf359..0000000000000000000000000000000000000000 --- a/www/examples/atapi_cdrw_smt_a.html +++ /dev/null @@ -1,32 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>atapi_cdrw_smt_a</title> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-12 Copyright -(C) 2002-3 Bruce Allen</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is -http://smartmontools.sourceforge.net/</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device: ATAPI -CD-RW 48X16 Version: A.RZ</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device type: CD/DVD</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Thu May 15 -17:24:44 2003 EST</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device does not support SMART</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device does not support Error -Counter logging</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device does not support Self Test -logging</span> -</body> -</html> diff --git a/www/examples/ativ_36_smt_a.html b/www/examples/ativ_36_smt_a.html deleted file mode 100644 index c5dc6b2b326e1020fdd4e59f7aac524fb2b4c796..0000000000000000000000000000000000000000 --- a/www/examples/ativ_36_smt_a.html +++ /dev/null @@ -1,61 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>Atlas IV 36 WLS smartmontools output</title> -</head> -<body> -<span style="font-family: monospace;">Device: QUANTUM ATLAS IV 36 -WLS Version: 0A0A </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: 363930037828 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Sat May 3 -21:20:08 2003 EST </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device supports SMART and is -Disabled </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Enabled </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Sense: Ok! </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Current Drive -Temperature: 35 C </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log: </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -65535 -0 -0 -0 -0 -4.295 0 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -0 -0 -0 -0 -4.295 0 </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Non-medium error -count: 13</span> -</body> -</html> diff --git a/www/examples/bnch_DLT1.html b/www/examples/bnch_DLT1.html deleted file mode 100644 index efa6a371318df3b037a982309b3805b82d334752..0000000000000000000000000000000000000000 --- a/www/examples/bnch_DLT1.html +++ /dev/null @@ -1,67 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>benchmark tape systems DLT1</title> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-11 Copyright -(C) 2002-3 Bruce Allen </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is </span><a - class="moz-txt-link-freetext" - href="http://smartmontools.sourceforge.net/" - style="font-family: monospace;">http://smartmontools.sourceforge.net/</a><span - style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Device: BNCHMARK -DLT1 -Version: 391B </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: 0000052369<br> -Device type: tape</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Sun May 4 -11:53:27 2003 EST </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">device is NOT READY (media -absent, spun down, etc) </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">TapeAlert Supported </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">TapeAlert: Ok! </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log: </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -0 -0 -0 -0 -0 -0.000 0 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -0 -6 -6 -0 -5.920 0 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Warning: device does not support -Self Test Logging</span> -</body> -</html> diff --git a/www/examples/bnch_robot.html b/www/examples/bnch_robot.html deleted file mode 100644 index 5069b96191292ddc95c1c81cc18c20c685b3d7d5..0000000000000000000000000000000000000000 --- a/www/examples/bnch_robot.html +++ /dev/null @@ -1,64 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>Benchmark tape systems robot</title> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-11 Copyright -(C) 2002-3 Bruce Allen </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is </span><a - class="moz-txt-link-freetext" - href="http://smartmontools.sourceforge.net/" - style="font-family: monospace;">http://smartmontools.sourceforge.net/</a><span - style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Device: -STK -L20 -Version: 0207 </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: LLC02207812<br> -Device type: medium changer</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Sun May 4 -11:54:39 2003 EST </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Disabled or -Not Supported </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">TapeAlert Supported </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">TapeAlert Errors (C=Critical, -W=Warning, I=Informational): </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">[0x02] W: There is a problem with -the library mechanism. If problem persists, </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> call the library supplier -help line. </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">[0x0d] W: There is a potential -problem with the drive ejecting cartridges or </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> with the library mechanism -picking a cartridge from a slot. </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> 1. No action needs to be -taken at this time. </span><br style="font-family: monospace;"> -<span style="font-family: monospace;"> 2. If the problem persists, -call the library supplier help line. </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">[0x0e] W: There is a potential -problem with the library mechanism placing a </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> cartridge into a slot. </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> 1. No action needs to be -taken at this time. </span><br style="font-family: monospace;"> -<span style="font-family: monospace;"> 2. If the problem persists, -call the library supplier help line. </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">No Error counter log to report </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Warning: device does not support -Self Test Logging</span> -</body> -</html> diff --git a/www/examples/ddrs_39130_smt_a.html b/www/examples/ddrs_39130_smt_a.html deleted file mode 100644 index e920d71a1f8def59fe8d5930e2431dcfb3109511..0000000000000000000000000000000000000000 --- a/www/examples/ddrs_39130_smt_a.html +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>ddrs_39130_smt_a.html</title> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-12 Copyright -(C) 2002-3 Bruce Allen</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is -http://smartmontools.sourceforge.net/</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> - </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device: -IBM -DDRS-39130D Version: DC1B</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: QE702689</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device type: disk</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Thu May 15 -16:51:27 2003 EST</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device supports SMART and is -Enabled</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Disabled or -Not Supported</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Health Status: OK</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> - </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log:</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -0 -0 -0 -0 -0 -4.295 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -0 -0 -4 -4 -4.295 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">verify: -0 -0 -0 -0 -0 -0.072 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> - </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Non-medium error -count: 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device does not support Self Test -logging</span> -</body> -</html> diff --git a/www/examples/hp_c5713a_smt_a.html b/www/examples/hp_c5713a_smt_a.html deleted file mode 100644 index 4c4beea98338e0e74f5eb441caec307f1bb102e2..0000000000000000000000000000000000000000 --- a/www/examples/hp_c5713a_smt_a.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>HP DDS-4 drive smartmontools output</title> -</head> -<body> -<pre wrap="">smartctl version 5.1-11 Copyright (C) 2002-3 Bruce Allen<br>Home page is <a - class="moz-txt-link-freetext" - href="http://smartmontools.sourceforge.net/">http://smartmontools.sourceforge.net/</a><br><br>Device: HP C5713A Version: H910<br>Local Time is: Thu May 1 23:26:38 2003 EEST<br>Temperature Warning Disabled or Not Supported<br>TapeAlert Supported<br>TapeAlert: Ok!<br><br>Error counter log:<br> Errors Corrected Total Total Correction Gigabytes Total<br> delay: [rereads/ errors algorithm processed uncorrected<br> minor | major rewrites] corrected invocations [10^9 bytes] errors<br>read: 0 0 0 2 0 0.000 0<br>write: 0 0 0 0 0 0.000 0<br>Warning: device does not support Self Test Logging</pre> -</body> -</html> diff --git a/www/examples/mam3184_smt_a.html b/www/examples/mam3184_smt_a.html deleted file mode 100644 index b2896462e43f6c797e65f83180f7db7b6debc1d4..0000000000000000000000000000000000000000 --- a/www/examples/mam3184_smt_a.html +++ /dev/null @@ -1,170 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>mam3184_smt_a.html</title> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-12 Copyright -(C) 2002-3 Bruce Allen</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is -http://smartmontools.sourceforge.net/</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device: FUJITSU -MAM3184MP Version: 0106</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: UKS0P2300CK0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device type: disk</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Thu May 15 -15:35:10 2003 EST</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device supports SMART and is -Enabled</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Enabled</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Health Status: OK</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Current Drive -Temperature: 42 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Drive Trip -Temperature: 65 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Manufactured in week 10 of year -2002</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Current start stop -count: 280 times</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Recommended start stop -count: 10000 times</span><br style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log:</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -0 -0 -0 -0 -0 -510.626 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -13 -0 -0 -0 -769.950 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Non-medium error -count: 855</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Self-test log</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Num -Test -Status -segment LifeTime LBA_first_err [SK ASC ASQ]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Description -number (hours)</span><br style="font-family: monospace;"> -<span style="font-family: monospace;"># 1 Background -long -Completed -- -980 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 2 Background short -Completed -- -788 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 3 Background -long -Completed -- -768 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 4 Background short -Completed -- -665 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 5 Background -long -Completed -- -635 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 6 Foreground -long -Completed -- -635 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 7 Foreground -long Interrupted (bus reset ?) - -634 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 8 Foreground -long Interrupted (bus reset ?) - -634 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 9 Foreground -long Interrupted (bus reset ?) -- -1 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#10 Foreground short -Completed -- -1 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#11 Background short -Completed -- -1 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Long (extended) Self Test -duration: 837 seconds [13.9 minutes]</span><br> -<tt><br> -</tt> -</body> -</html> diff --git a/www/examples/mam3184_smt_health.html b/www/examples/mam3184_smt_health.html deleted file mode 100644 index 37a41fb18685bd2b8a5c35ece46f9b56664d442a..0000000000000000000000000000000000000000 --- a/www/examples/mam3184_smt_health.html +++ /dev/null @@ -1,35 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>mam3184_smt_health.html</title> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-12 Copyright -(C) 2002-3 Bruce Allen</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is -http://smartmontools.sourceforge.net/</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Health Status: FAILURE -PREDICTION THRESHOLD EXCEEDED (FALSE) [asc=5d,ascq=ff]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Current Drive -Temperature: 42 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Drive Trip -Temperature: 65 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Manufactured in week 10 of year -2002</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Current start stop -count: 280 times</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Recommended start stop -count: 10000 times</span><br> -<tt><br> -</tt> -</body> -</html> diff --git a/www/examples/map3735_smt_a.html b/www/examples/map3735_smt_a.html deleted file mode 100644 index 928904f1bd0e06b1a78b85815f93ae34c24bff38..0000000000000000000000000000000000000000 --- a/www/examples/map3735_smt_a.html +++ /dev/null @@ -1,86 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> - <title>Fujitsu MAP 3735 smartmontools output</title> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-10 Copyright -(C) 2002-3 Bruce Allen </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is </span><a - class="moz-txt-link-freetext" - href="http://smartmontools.sourceforge.net/" - style="font-family: monospace;">http://smartmontools.sourceforge.net/</a><span - style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Device: FUJITSU -MAP3735NP Version: 0105 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: UPG0P2A00491 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Sat May 3 -21:22:09 2003 EST </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device supports SMART and is -Disabled </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Disabled or -Not Supported </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Sense: Ok! </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Current Drive -Temperature: 39 C </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Drive Trip -Temperature: 65 C </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Manufactured in week 40 of year -2002 </span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Current start stop -count: 14 times </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Recommended start stop -count: 10000 times </span><br style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log: </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -0 -0 -0 -0 -0 -810.959 0 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -0 -0 -0 -0 -72.300 0 </span><br - style="font-family: monospace;"> -<br style="font-family: monospace;"> -<span style="font-family: monospace;">Non-medium error -count: 27 </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">No self-tests have been logged </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Long (extended) Self Test -duration: 2872 seconds [47.9 minutes]</span> -</body> -</html> diff --git a/www/examples/st318451_smt_a.html b/www/examples/st318451_smt_a.html deleted file mode 100644 index fcbadaa880c2b67ad2e9431b3080bd83bb194176..0000000000000000000000000000000000000000 --- a/www/examples/st318451_smt_a.html +++ /dev/null @@ -1,185 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - <title>st318451_smt_a</title> - <meta http-equiv="content-type" - content="text/html; charset=ISO-8859-1"> -</head> -<body> -<span style="font-family: monospace;">smartctl version 5.1-12 Copyright -(C) 2002-3 Bruce Allen</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Home page is -http://smartmontools.sourceforge.net/</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Device: SEAGATE -ST318451LW Version: 0003</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Serial number: -3CC01TTG000071033QEA</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device type: disk</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Local Time is: Thu May 15 -17:12:14 2003 EST</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Device supports SMART and is -Enabled</span><br style="font-family: monospace;"> -<span style="font-family: monospace;">Temperature Warning Enabled</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Health Status: OK</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Current Drive -Temperature: 34 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Drive Trip -Temperature: 65 C</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Error counter log:</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Errors Corrected Total -Total Correction -Gigabytes Total</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -delay: [rereads/ -errors algorithm -processed uncorrected</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -minor | major rewrites] corrected -invocations [10^9 bytes] errors</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">read: -21 -0 -0 -21 -21 -100.431 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">write: -0 -0 -0 -0 -0 -0.016 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">verify: -0 -0 -0 -0 -0 -0.010 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Non-medium error -count: 0</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">SMART Self-test log</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Num -Test -Status -segment LifeTime LBA_first_err [SK ASC ASQ]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> -Description -number (hours)</span><br style="font-family: monospace;"> -<span style="font-family: monospace;"># 1 Background -long -Completed -- -11 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 2 Background -long -Completed -- -11 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 3 Background short -Completed -- -11 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 4 Background short -Completed -- -10 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 5 Background short -Completed -- -6 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 6 Background -long -Completed -- -6 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 7 Background short -Completed -- -6 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 8 Background short -Completed -- -5 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"># 9 Background -long -Completed -- -3 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#10 Background short -Completed -- -3 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#11 Background short -Completed -- -2 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#12 Background short -Completed -- -0 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">#13 Background short -Completed -- -0 -- [- - -]</span><br - style="font-family: monospace;"> -<span style="font-family: monospace;"> </span><br - style="font-family: monospace;"> -<span style="font-family: monospace;">Long (extended) Self Test -duration: 587 seconds [9.8 minutes]</span><br> -<tt><br> -</tt> -</body> -</html> diff --git a/www/index.html b/www/index.html deleted file mode 100644 index 281ccec9b62ab7261281336d29997b2ee7f3e91d..0000000000000000000000000000000000000000 --- a/www/index.html +++ /dev/null @@ -1,1119 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> -<head> - <title>smartmontools Home Page (last updated $Date: 2004/08/15 17:24:55 $)</title> - <link rev="made" href="mailto:smartmontools-support@sourceforge.net" /> - <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> - <meta name="description" content="smartmontools Home Page" /> - <meta name="keywords" content="S.M.A.R.T., SMART, FreeBSD, Linux, NetBSD, Solaris, Windows, disk, monitor, monitoring" /> -</head> -<body> - -<!-- $Id: index.html,v 1.171 2004/08/15 17:24:55 ballen4705 Exp $ --> - -<div align="center"> - <img src="smart_logo.gif" border="0" width="105" height="59" alt="SMART LOGO" /> - <br /> - <h1><font color="#3333ff">smartmontools Home Page</font></h1> -</div> - -<p>Welcome! This is the home page for the smartmontools package.</p> - -<p> -<font color="#ff0000"> -NEWS FLASH:<br/> DARWIN support (ATA disks only) was added to -smartmontools by Geoff Keating on July 16, 2004, and is experimental. -The code may be downloaded from CVS following the directions below. -Please report problems or success to the smartmontools-support mailing -list. -</font> -</p> - -<p>The smartmontools package contains two utility programs -(<font color="#3333ff"><b>smartctl</b></font> and -<font color="#3333ff"><b>smartd</b></font>) to control and monitor storage -systems using the Self-Monitoring, Analysis and Reporting Technology -System (SMART) built into most modern ATA and SCSI hard -disks.  In many cases, these utilities will provide advanced warning -of disk degradation and failure.</p> - -<p>Smartmontools is derived from the <a -href="http://sourceforge.net/projects/smartsuite/">smartsuite -package</a>, and includes support for ATA/ATAPI-3 to -7 disks and SCSI -disk and tape devices. It should run on any modern Darwin, Linux, FreeBSD, -NetBSD, Solaris, or <a href="#windows">Windows</a> system.</p> - -<p>For printing convenience, everything except for the <a -href="#sampleoutput">example output</a> is on a single page.</p> - -<hr size="2" /> - -<ul> -<li><a href="http://www.linuxjournal.com/article.php?sid=6983"> -Monitoring Hard Disks with SMART (Linux Journal, January 2004, page 74)</a></li> -<li><a href="#howtodownload">How to download and install -smartmontools</a></li> -<li><a href="#PROBLEMS">Serious Problem Reports (system lockup, etc.)</a></li> -<li><a href="#FAQ">Frequently Asked Questions</a></li> -<li><a href="#scsi">SCSI disks and tapes (TapeAlert)</a></li> -<li><a href="#testinghelp">FireWire, USB, and SATA disks/tapes</a></li> -<li><a href="#differfromsmartsuite">How does smartmontools differ from -smartsuite?</a></li> -<li><a href="#references">Useful references on SMART and ATA/ATAPI-5, --6, and -7</a></li> -<li><a href="#sampleoutput">Example output from smartmontools</a> -<b>smartctl</b> utility</li> -<li><a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/">CVS -repository</a> and <a href="http://sourceforge.net/projects/smartmontools/">SourceForge's -Project Page</a></li> -<li>Mailing List <a href="http://lists.sourceforge.net/lists/listinfo/smartmontools-support">Information</a> -and <a href="http://sourceforge.net/mailarchive/forum.php?forum=smartmontools-support">Archives</a> -(Archive has <b>Search Box</b> in top left corner). <a href="#altmail">Alternative</a> (and usually up to date) archives.</li> -<li>Current <a href="man/smartctl.8.html">smartctl</a>, <a href="man/smartd.8.html">smartd</a>, and <a href="man/smartd.conf.5.html">smartd.conf</a> HTML man pages generated from CVS.</li> -</ul> - -<hr size="2" /> - -<b><a name="howtodownload"></a>How to download and install -smartmontools</b> - -<p>There are different ways to get and install -smartmontools.  You can use any of the procedures below -(the fourth is for Debian Linux only).  Just after "Method 6" below are -some instructions for trying out smartmontools once you have completed -the installation. The -<b><a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/INSTALL?rev=HEAD&content-type=text/vnd.viewcvs-markup">INSTALL</a></b> file contains additional information. -</p> -<b>First Method (Linux) - Install from the RPM file</b> -<ul> -<li>Download the latest binary RPM file (<tt>*.rpm</tt>) from <a href="http://sourceforge.net/project/showfiles.php?group_id=64297">here</a>.  -Don't get the SRPM file (<tt>*.src.rpm</tt>).</li> -<li>Install it using RPM.  <i>You must be root to do this</i>: -<pre>su root (enter root password) -rpm -ivh smartmontools-5.1-18.i386.rpm</pre> -For most users, this is all that is needed.</li> -<li>If you receive an error message, you have probably previously -installed the <tt>smartsuite</tt> package, or RedHat's -<tt>kernel-utils</tt> package, which provide older versions of the -<tt>smartd</tt> and <tt>smartctl</tt> utilities.  In this case you -should use the <tt>--nodeps</tt> or <tt>--force</tt> arguments of rpm to -replace these two utilities: -<pre>rpm -ivh --nodeps --force smartmontools-5.1-18.i386.rpm</pre></li> -<li>If you want to remove the package (<tt>rpm -e smartmontools</tt>) -and your system does not have <tt>chkconfig</tt> installed, you may need -to use: -<pre>rpm -e --noscripts smartmontools</pre></li> -</ul> - -<b>Second Method (Linux/Solaris/FreeBSD/NetBSD/Cygwin) - Install from the source tarball</b> -<ul> -<li>Download the latest source tarball from <a href="http://sourceforge.net/project/showfiles.php?group_id=64297">here</a>. -Note: you probably want the most recent release.</li> -<li>Uncompress the tarball: -<pre>tar zxvf smartmontools-5.20.tar.gz</pre></li> -<li>The previous step created a directory called <tt>smartmontools-5.20</tt> -containing the code.  Go to that directory, build, and install: -<pre>cd smartmontools-5.20 -./configure -make -make install -</pre></li> -<li> Note that the <tt>./configure</tt> step above is not possible for releases <=5.1-18, you -have to edit the Makefile by hand to change installation paths. For releases >=5.19, <tt>./configure</tt> -can take optional arguments. These optional arguments are fully explained in the -<a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/INSTALL?rev=HEAD&content-type=text/vnd.viewcvs-markup">INSTALL</a> -file. The most important one is <tt>--prefix</tt> to change the default installation directories.<p> -<i>Please note that the default installation location changed in versions >=5.31.</i> -If you don't pass any arguments to <tt>./configure</tt> all files will reside under -<i>/usr/local</i> to not interfere with files from your distribution. For more detailed -information please also refer to the -<a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/INSTALL?rev=HEAD&content-type=text/vnd.viewcvs-markup">INSTALL</a> -document. -</p> -</li> -<li>To compile from another directory (avoids overwriting virgin files from the smartmontools package) -replace <tt>./configure [options]</tt> by: -<pre> -mkdir objdir -cd objdir -../configure [options] -</pre></li> -<li>To install to another destination (useful for testing and to avoid overwriting an existing smartmontools installation) -replace <tt>make install</tt> by: -<pre> -make DESTDIR=/home/myself/smartmontools-test install -</pre> -Use a full path: <tt>~/smartmontools-test</tt> won't work. -</li> -<li>Unless the destination directory is your home directory (or a location that you have write permission) -only root can do <tt>make install</tt></li> -</ul> - -<b>Third Method (Darwin/FreeBSD/Linux/NetBSD/Solaris/Cygwin) - Install from the CVS repository</b> -<ul> -<li><p>One of the really cool things about CVS is that you can get -<i>any</i> version of the code you want, from the first release up the -the most current development version.  And it's trivial, because -each release is <u>tagged</u> with a name like -<tt>RELEASE_5_1_18</tt>.  You can see what the different names are -by looking at the <a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/"> -CVS repository</a>.  You'll see the tag names in the little scroll -window where it says "Show only files with tag".  All you need to -do to get the latest development code is -(but note that the development code may be unstable, and that the -documentation and code may be inconsistent):</p> - -<pre>cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools login (when prompted for a password, just press Enter) -cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools co sm5</pre></li> - -<li>To instead get the 5.1-16 release: - -<pre>cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/smartmontools co -r RELEASE_5_1_16 sm5</pre></li> - -<li><p>This will create a subdirectory called <tt>sm5/</tt> containing the -code.  Go to that directory, build, and install:</p> -<pre>cd sm5 -./autogen.sh -./configure -make -make install -</pre> - -<ul> -<li>See notes under <b>Second method - install from source tarball</b> for different options to <tt>./configure</tt> -and other useful remarks.</li> -<li>Skip <tt>./autogen.sh</tt> and <tt>./configure</tt> for tagged releases -<= 5.1-18 (RELEASE_5_X_Y, where X = 0 or 1 and Y = 0 to 18).</li> -<li>If you get the current sources (<tt>cvs co</tt> with no arguments or do <tt>cvs up --A</tt>) then you <i>will</i> need those two additional steps.</li> -</ul></li> - -<li>To update your sources to the 5.1-18 release: -<pre>cd sm5 -cvs up -r RELEASE_5_1_18</pre></li> - -<li>To update any tagged release to the latest development code: - -<pre>cd sm5 -cvs up -A</pre></li> -</ul> - -<b>Fourth Method (Debian Linux) - Install the Debian package</b> -<ul> -<li> -The latest version of the smartmontools package in <i>.deb</i> format is -available at the <a href="http://packages.debian.org/unstable/utils/smartmontools.html">Debian smartmontools -package page</a>. -This package is for the (unreleased) <a href="http://www.debian.org/releases/">unstable</a> -distribution.</li> -<li>If you're running Debian <a -href="http://www.debian.org/releases/stable/">stable</a> please download the -package from <a -href="http://honk.physik.uni-konstanz.de/~agx/linux-i386/debian/smartmontools/">here</a>.</li> -<li> -You can then install the package using: -<pre> -dpkg -i smartmontools_5.1.18-1.agx0_i386.deb -</pre> -But the preferred method is to add the following line to your -<tt>/etc/apt/sources.list</tt>: -<pre>deb http://honk.physik.uni-konstanz.de/~agx/linux-i386/debian smartmontools/ -</pre> -and type <pre> -apt-get update && apt-get install smartmontools -</pre> this will automatically download and install the package. -</li> -</ul> - - -<b><a name="CygwinInstall"></a> -Fifth Method (Windows with <a href="http://www.cygwin.com/">Cygwin</a> -installed) - Install the Cygwin package -</b> -<ul> -<li>To install it, use Cygwin's -<a href="http://www.cygwin.com/setup.exe">setup.exe</a>. -Add smartmontools download directory from any sourceforge mirror -(<b>http://<i>{belnet,easynews,heanet,switch,...}</i>.dl.sourceforge.net/sourceforge/smartmontools/</b>) -in <i>Choose Download Site(s)</i> -and follow as usual (requires Cygwin <b>1.5.7 or greater</b>). -</li> -<li><p>If you want to manually install it (not recommended -because, among others, you lose the ability to update and uninstall it), -download the latest Cygwin package (<tt>*.cygwin.tar.bz2</tt>) from -<a href="http://sourceforge.net/project/showfiles.php?group_id=64297">here</a>, -and type:</p> -<pre> -tar jxf smartmontools-5.32-1.cygwin.tar.bz2 -C / -</pre> -from a Cygwin shell. -</li> -</ul> - -<b><a name="WindowsInstall"></a> -Sixth Method (Windows) - Install the Windows package -</b> -<ul> -<li>Download the latest Windows package (<tt>*.win32.zip</tt>) from -<a href="http://sourceforge.net/project/showfiles.php?group_id=64297">here</a>. -</li> -<li><p>Unzip the files into a directory of your choice. -A directory in the PATH is recommended for the <tt>*.exe</tt> files.</p> -</li> -</ul> - - -<b>After installing it using Method 1, 2, 3, 4 or 5 above, you can read the -man pages, and try out the commands:</b> - -<pre> -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)</pre> - -<p>Note that the default location for the manual pages are -<tt>/usr/share/man/man5</tt> and <tt>/usr/share/man/man8</tt>.  If -"<tt>man</tt>" doesn't find them, then you may need to add -<tt>/usr/share/man</tt> to your <tt>MANPATH</tt> environment -variable.</p> - -<p>The Windows package (see Method 6 above) provides preformatted man pages -in <tt>*.html</tt> and <tt>*.txt</tt> format.</p> - -<hr size="2" /> - -<a name="PROBLEMS"></a><b>Serious Problem Reports</b> -<p>If a serious problem gets reported to us, it gets added to the <a -href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/WARNINGS?rev=HEAD&content-type=text/vnd.viewcvs-markup"> -WARNINGS</a> file in smartmontools. So far there are only a few problem systems listed.</p> - -<hr size="2" /> - -<a name="FAQ"></a><b>Frequently Asked Questions</b> - -<p>If your question is not here, please <a href="mailto:smartmontools-support@lists.sourceforge.net">email -me</a>.</p> - -<ul> -<li><b>Is the smartmontools File Download/Mail List/Mail Archive/CVS server broken?</b> - -<p>SourceForge is a free service, which supports a very large number of -users and projects. Please check the <a -href="http://sourceforge.net/docman/display_doc.php?docid=2352&group_id=1"> -SourceForge Site Status Page</a> to see the maintenance schedule and to -learn if SourceForge is experiencing unscheduled system outages or other -problems.</p> - -<p> -<a name="altmail"></a>Alternative mailing-list archives are provided by -<a href="http://gmane.org/find.php?list=smartmontools">Gmane</a> and MARC (<a -href="http://marc.theaimsgroup.com/?l=smartmontools-support">smartmontools-support</a> -and <a -href="http://marc.theaimsgroup.com/?l=smartmontools-database">smartmontools-database</a>).</p> - -</li> - -<li><b>What do I do if I have problems, or need support?  Suppose -I want to become a developer, or suggest some new extensions?</b> - -<p>First, search the support mailing list archives to see if your -question has been answered. Instructions are in the following -paragraph. If you don't find an answer there, then please send an -email to the <a -href="http://lists.sourceforge.net/mailman/listinfo/smartmontools-support">smartmontools-support -mailing list</a>. This is a moderated forum: you are not -required to subscribe to the list in order to post your question. -</p> - -<p>To search the email archives, first go to the <a -href="http://sourceforge.net/mailarchive/forum.php?forum=smartmontools-support"> -mailing list archive</a>. In the top left corner you will see a -search box: use <b>Mailing List</b> as the type of search. This tool -works very well.</p> - -<p>Note that from time to time SourceForge has mailing list problems -and you'll get a message telling you that <i>Either your mailing list -name was misspelled or your mailing list has not been archived yet. If -this list has just been created, please retry in 2-4 hours</i>. If -this happens, you'll have to try again later. Or use <a -href="#altmail">alternative</a> (and usually up to date) email -archives. -</p> - -</li> - -<li><b>What are the future plans for smartmontools?</b> - -<p>My plan is that smartmontools-5.x will support ATA/ATAPI-5 -disks.  Eventually, we'll do smartmontools-6.x to support -ATA/ATAPI-6 disks, smartmontools-7.x for the ATA/ATAPI-7 standard, and -so on.  The "x" will denote revision level, as bugs get found and -fixed, and as enhancements get added.  If it's possible to maintain -backwards compatibility, that would be nice, but I don't know if it will -be possible or practical.</p></li> - -<li><b>Why are you doing this?</b> - -<p>My research group at U. Wisconsin - Milwaukee runs a <a -href="http://www.lsc-group.phys.uwm.edu/beowulf/medusa/">beowulf -cluster</a> with 600 ATA-5 and -6 disks (300 IBM and 300 -Maxtor).  We have more than 50 TB of data stored on the -system.  I also help out with a <a -href="http://pandora.aei.mpg.de/merlin/"> cluster</a> at the Albert -Einstein Institute that has 540 IBM ATA-6 disks (65 TB -total). It's nice to have advanced warning when a disk is going to -fail.</p></li> - -<li><b>Where can I find distribution-specific bug reports?</b> -<p> -The smartmontools package supports a number of different operating -systems. Some of those operating systems are also distributed by -multiple sources, and some of these maintain a database of bug -reports. Here are links: -</p> - -<ul> -<li><a href="https://bugzilla.redhat.com/bugzilla/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=NEEDINFO&bug_status=MODIFIED&bug_status=CLOSED&field0-0-0=product&type0-0-0=substring&value0-0-0=smartctl&field0-0-1=component&type0-0-1=substring&value0-0-1=smartctl&field0-0-2=short_desc&type0-0-2=substring&value0-0-2=smartctl&field0-0-3=status_whiteboard&type0-0-3=substring&value0-0-3=smartctl&field0-0-4=product&type0-0-4=substring&value0-0-4=smartd&field0-0-5=component&type0-0-5=substring&value0-0-5=smartd&field0-0-6=short_desc&type0-0-6=substring&value0-0-6=smartd&field0-0-7=status_whiteboard&type0-0-7=substring&value0-0-7=smartd&field0-0-8=product&type0-0-8=substring&value0-0-8=smartsuite&field0-0-9=component&type0-0-9=substring&value0-0-9=smartsuite&field0-0-10=short_desc&type0-0-10=substring&value0-0-10=smartsuite&field0-0-11=status_whiteboard&type0-0-11=substring&value0-0-11=smartsuite&field0-0-12=product&type0-0-12=substring&value0-0-12=smartmontools&field0-0-13=component&type0-0-13=substring&value0-0-13=smartmontools&field0-0-14=short_desc&type0-0-14=substring&value0-0-14=smartmontools&field0-0-15=status_whiteboard&type0-0-15=substring&value0-0-15=smartmontools">Redhat/Fedora Bugzilla Database (Linux)</a> </li> -<li><a href="http://bugs.debian.org/cgi-bin/pkgreport.cgi?which=pkg&data=smartmontools&archive=no">Debian Bug Database (Linux)</a></li> -<li><a href="http://bugs.gentoo.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=product&type0-0-0=substring&value0-0-0=smartmontools&field0-0-1=component&type0-0-1=substring&value0-0-1=smartmontools&field0-0-2=short_desc&type0-0-2=substring&value0-0-2=smartmontools&field0-0-3=status_whiteboard&type0-0-3=substring&value0-0-3=smartmontools">Gentoo Bug Database (Linux)</a></li> -<li><a href="http://www.netbsd.org/cgi-bin/query-pr-list.pl?text=smartctl&state=open&state=feedback&state=analyzed&state=suspended">NetBSD smartctl bug database</a></li> -<li><a href="http://www.netbsd.org/cgi-bin/query-pr-list.pl?text=smartd&state=open&state=feedback&state=analyzed&state=suspended">NetBSD smartd bug database</a></li> -<li><a href="http://www.netbsd.org/cgi-bin/query-pr-list.pl?text=smartmontools&state=open&state=feedback&state=analyzed&state=suspended">NetBSD smartmontools bug database</a></li> -</ul> -<p> -If you can provide additional distribution or OS-specific bug-database links, please send an email to smartmontools-support. -</p></li> - -<li><b>I see some strange output from smartctl. What does it mean?</b> - -<p>The raw SMART attributes (temperature, power-on lifetime, and so -on) are stored in vendor-specific structures.  Sometime these are -strange.  Hitachi disks (at least some of them) store power-on -lifetime in minutes, rather than hours (see next question below).  IBM disks (at least some -of them) have three temperatures stored in the raw structure, not just -one.  And so on.  If you find strange output, or unknown -attributes, please send an email to <a href="http://lists.sourceforge.net/mailman/listinfo/smartmontools-support"> -smartmontools-support</a> and we'll help you try and figure it -out.</p></li> - -<li><b>What are the operating system requirements?</b> -<p> -Please see the first section of the <a -href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/INSTALL?view=markup">INSTALL</a> -file. -</p> -</li> - -<li><b>What Attributes does smartmontools not yet recognize?</b> - -<p>From Maxtor disks (99), (100), and (101). These are not used by -Maxtor in SMART revision 5. They will be used in SMART revision 6, -but the engineering group has not yet decided what to monitor with -these Attributes. -</p> -</li> - -<li><b>My Maxtor/Hitachi/Fujitsu disk is only a few days old, yet smartctl reports its age (Attribute 9) as thousands of hours!</b> - -<p>On recent disks, Maxtor has started to use Attribute 9 to -store the power-on disk lifetime in minutes rather than hours. In this case, use -the:<br/> -<tt>-v 9,minutes</tt><br/> -option to correctly display hours and minutes. -</p> -<p>Some models of Fujitsu disks use Attribute 9 to store -the power-on disk lifetime in seconds. In that case, use the:<br/> -<tt>-v 9,seconds</tt><br/> -option to correctly display hours, minutes and seconds.</p> -</li> - -<li><b>The power-on timer (Attribute 9 raw value) on my Maxtor disk acts strange.</b> - -<p>There are three related problems with Maxtor's SMART firmware: -</p> - -<p> -<b>1 - </b> On some Maxtor disks, the raw value of Attribute 9 (Power -On Time) is <i>supposed</i> to be minutes. But it advances at an -unpredictable rate, always more slowly than one count per minute. -This is because when the disk is in idle mode, the counter stops -advancing. This is only supposed to happen in standby mode. This -will be corrected in Maxtor product lines released after October 2004. -</p> - -<p> -<b>2 - </b> In Maxtor disks that use the raw value of Attribute 9 as a -minutes counter, only two bytes (of the six available) are used to -store the raw value. So it resets to zero once every 65536=2^16 -minutes, or about once every 1092 hours. This is fixed in all Maxtor -disks manufactured after July 2003, where the raw value was extended -to four bytes. -</p> - -<p> -<b>3 - </b> In Maxtor disks that use the raw value of Attribute 9 as a -minutes counter, the hour time-stamps in the self-test and ATA error -logs are calculated by right shifting 6 bits. This is equivalent to -dividing by 64 rather than by 60. As a result, the hour time stamps -in these logs advance 7% more slowly than they should. Thus, if you -do self-tests once per week at the same time, instead of the -time-stamps being 168 hours apart, they are 157 hours apart. This is -also fixed in all Maxtor disks manufactured after July 2003. -</p> -</li> - -<li><b>The time stamps in the self-test log of my Western Digital (WD) disk -don't correspond to the power-on time when the test was run</b> - -<p> -The self-test log timestamps in many WD disks roll back to zero every -1092 hours (65536 minutes). This problem is due to a WD firmware bug. -The power-on lifetime in hours is correctly stored in Attribute -9. However when the power-on lifetime is calculated for self-test log -entries, the lifetime in minutes is put into a 16-bit register then -divided by 60. The 16-bit register overflows and wraps around every -1092 hours. -</p> - -<p>For WD drives that exhibit this firmware bug, the relationship between -Attribute 9's raw value (H) and the time-stamps in the self-test log (h) are given by:<br/> -Let H = power on hours as shown by Attribute 9 (correct)<br/> -Let M = 60*H (power on minutes, correct)<br/> -Let m = M mod 65536 (incorrect value of power on minutes, shown in self-test log)<br/> -Let h = m/60 (incorrect value of power on hours) -</p> -</li> - -<li><b>The (normalized) WORST Attribute values of my Western Digital -(WD) disk are <u>larger</u> than the (normalized) CURRENT Attribute -values</b> -<p>Western Digital firmware initializes SMART Attributes 10, 11, and -199 after either 120 spin-ups or 8 power-on hours. Until that time, -they have the uninitialized value 253. -</p> -</li> - -<li><b>Where can I find manufacturer-specific disk-testing -utilities?</b> - -<p>A good listing of such utilities can be found <a -href="http://www.benchmarkhq.ru/english.html?/be_hdd2.html">here</a>. -Unfortunately most of these are for MS operating systems, but most can -be run from an MS-DOS boot disk. Note: if you do run one of these -utilities, and it identifies the meanings of any SMART Attributes that -are not known to smartmontools, please report them to the mailing list -above.</p> - -<p>These utilities have an important role to fill. If your disk has -bad sectors (for example, as revealed by running self-tests with -smartmontools) and the disk is not able to recover the data from those -sectors, then the disk will <i>not</i> automatically reallocate those -damaged sectors from its set of spare sectors, because -forcing the reallocation to take place may entail some loss of data. -Because the commands that force such reallocation are -<i>Vendor Specific</i>, most manufactuers provide a utility for this -purpose. It may cause data loss but can repair damaged sectors (at -least, until it runs out of replacement sectors). -</p> -</li> - -<li><b>When I run <tt>smartd</tt>, the SYSLOG <tt>/var/log/messages</tt> -contains messages like this:</b> -<pre>smartd: Reading Device /dev/sdv -modprobe: modprobe: Can't locate module block-major-65</pre> - -<p>This is because when <tt>smartd</tt> starts, if there is no -configuration file, it looks for all ATA and SCSI devices to monitor -(matching the pattern <tt>/dev/hd[a-t]</tt> or -<tt>/dev/sd[a-z]</tt>).  The log messages appear because your -system doesn't have most of these devices.</p> - -<p>The solution is simple: use the <tt>smartd</tt> configuration file -<tt>/etc/smartd.conf</tt> to specify which devices to monitor.</p></li> - -<li><b>What's the story on IBM SMART disks?</b> - -<p>Apparently some of the older SMART firmware on IBM disks can -interfere with the regular operation of the disk.  If you have this -problem, here are some links:<br/> -<a href="http://www.geocities.com/dtla_update/">Geocities Site</a>, -<a href="http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215">IBM Site #1</a>, -<a href="http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215">IBM Site #2</a><br/> -to an IBM Firmware Upgrade that fixes the problem. -</p></li> - -<li><b>How can I check that the package hasn't been tampered with?</b> - -<p>Since the <tt>smartmontools</tt> utilities run as root, you might -be concerned about something harmful being embedded within -them. Starting with release 5.19 of <tt>smartmontools</tt>, the .rpm -files and tarball have been GPG signed. The tarball's fingerprint is -given in a file on the release page with a name like -<tt>smartmontools-5.20.tar.gz.asc</tt>. Please verify these using -the <a href="SmartmontoolsSigningKey.txt">Smartmontools GPG Signing -Key</a> -</p></li> - -<li><b>Is there a bootable standalone CD or floppy that contains smartmontools?</b> - -<p>If you have a system that is showing signs of disk trouble (for -example, it's unbootable and the console is full of disk error -messages) it can be handy to have a version of smartmontools that can -be run off of a bootable CD or floppy to examine the disk's SMART data and run -self-tests. This is also useful if you want to run Captive Self-Tests -(the <b><tt>-<font size="+2">C</font></tt></b> option of -<b><tt>smartctl</tt></b> ) on disks that can not easily be unmounted, -such as those hosting the Operating System files. Or you can use -this to run <tt>smartctl</tt> on computers that don't use Linux as the -day-to-day operating system.</p> - -<p><a name="bootable"></a>Here is a list of such bootable CDs:</p> -<ul> -<li><a href="http://www.lnx-bbc.org/">LNX-BBC Bootable CD</a> </li> -<li><a href="http://www.stresslinux.org/">Stresslinux Bootable CD</a></li> -<li><a href="http://www.tux.org/pub/people/kent-robotti/looplinux/rip/">RIP (Recovery Is Possible) Bootable CD</a></li> -<li><a href="http://www.sysresccd.org/">SystemRescueCd</a></li> -<li><a href="http://www.gpstudio.com/stux/">STUX Bootable CD</a></li> -<!-- <li><a href="http://www.knopper.net/knoppix/">Knoppix Bootable CD</a></li> --> -</ul> -<p> -Please let me know if there are others, and I will add them to this -list. -</p> -</li> - -<li><b>Can I monitor ATA disks behind SCSI RAID controllers?</b> - -<p> -From release 5.1-18, smartmontools fully supports 3ware SCSI RAID -controllers that use ATA disks internally. To pass commands through -the 3ware controller, use the smartmontools <b>-d 3ware,N</b> option -or Directive. -</p> -<p> -3ware Linux device drivers (<tt>3w-xxxx</tt>) versions <b>1.02.00.036</b> -and earlier do not return the SMART HEALTH STATUS (smartmontools -<b>-H</b>) of the disks. In addition, the ENABLE AUTOMATIC OFFLINE and -ENABLE ATTRIBUTE AUTOSAVE commands (smartmontools <b>-o on</b> and -<b>-S on</b>) can not be passed through the driver to the disks. -Later driver versions support <i>all</i> of these commands. You may: -</p> -<ul> -<li>use version <b>1.02.00.037</b> or greater of the <tt>3w-xxxx</tt> driver, or</li> -<li><a href="3w-xxxx.txt">patch</a> earlier 3ware <tt>3w-xxxx</tt> drivers so that -these commands reach the disks, or</li> -<li> use an <b>unpatched</b> earlier <tt>3w-xxxx</tt> driver (which won't pass these -commands to the disks but will instead print -harmless warning messages to SYSLOG).</li> -</ul> -<p> -To see if your system's <tt>3w-xxxx</tt> driver has been patched, give the -command:<br/> -<tt>smartctl -H -S on -o on -d 3ware,? /dev/sd?</tt> -<br/> -If you -have an unpatched kernel, you'll see warning messages prompting you to -patch the kernel.</p> -<p> -The 3ware <tt>3w-xxxx</tt> version 1.02.00.037 driver first appeared -in kernel version 2.6.0-test5-bk11 on 24 September 2003 and in kernel -version 2.4.23-bk2 on 3 December 2003. It was officially released on -the 3ware web site on December 19, 2003 as part of their -driver/firmware/utility package version 7.7.0. -</p> - -<p> -Note (added 29 July 2004): starting with smartmontools (experimental) -release 5.33, one can also access SMART data from drives behind 3ware -controllers using the (character) devices /dev/twe0-15. This should -work correctly even with older versions of the 3w-xxxx driver. One can -also access SMART data from drives behind 3ware 9000-series -controllers (3w-9xxx driver) using the (character) devices -/dev/twa0-15. -</p> - -</li> - -<li><a name="windows"></a><b>Does it work on Windows?</b> - -<p>Yes, finally it does. A windows port of smartctl 5.26 by -<a href="http://sourceforge.net/users/chrfranke/">Christian Franke</a> -was first checked in 2004/02/23 on CVS branch -<a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/?only_with_tag=RELEASE_5_26_WIN32_BRANCH"> -RELEASE_5_26_WIN32_BRANCH</a> and has been merged to the CVS trunk later.</p> - -<p>The <a href="http://www.cygwin.com/">Cygwin</a> environment can be -used to built both Cygwin and Windows (using <a href="http://www.mingw.org/">MinGW</a>) -versions of smartctl and smartd. -Installation instructions for binary distributions can be found -<a href="#CygwinInstall">here</a> and <a href="#WindowsInstall">here</a>.</p> - -<p>Alternatively, you can also run it from a -<a href="#bootable">bootable CD</a></p> - -<p>Some code showing how to access SMART data under Windows 98, NT 4, -2000, and XP can be found <a -href="ftp://ftp.heise.de/pub/ct/listings/0207-218.zip">here</a>. -Additional information from Microsoft can be found <a -href="http://support.microsoft.com/default.aspx?scid=kb;en-us;Q208048">here</a>. -A related newsgroup thread (with pointers to additional documentation, -etc.) is <a -href="http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&th=18cdac9d90f6bda1&rnum=1">here</a>. -</p> -</li> - -<li><b>Why did the release version scheme change?</b> - -<p>It was non-standard. So with the move to GNU Autoconf and GNU -Automake it changed from 5.X-Y (where X and Y are one or more digits) -to 5.Y. Starting with the first release, and moving forward in time, the releases are -numbered as follows:<br/> -<tt> -5.0-1, -5.0-2, -..., -5.0-45, -5.1-1, -..., -5.1-18, -5.19, -5.20, -... -</tt> -</p> -</li> - -<li><a name="FAQ-database"></a><b>My ATA drive is not in the smartctl/smartd database. Does this break anything? How do I get it added?</b> -<p> - If your drive is not in the database, then the - <i>names</i> of the Attributes (displayed in the <tt>ID#</tt> column of - <tt>smartctl -A /dev/hd?</tt>) and the <i>format</i> of the the raw Attribute - values shown in the <tt>RAW_VALUE</tt> column may be incorrect. This - is mostly cosmetic: the essential drive health monitoring/testing - functionality of <b>smartmontools</b> does <i>not</i> depend upon the - database. -</p> - -<p> -<b> - If your drive is not in the database, pleaes check <a - href="http://sourceforge.net/project/showfiles.php?group_id=64297">here</a> - to be sure that you are using the latest smartmontools release. Each - new release has additional drives added to the database. Please do - not submit a new drive for the database without checking to see if it - is already in the database of the current smartmontools release - version. -</b> -</p> - -<p> -<b> If your drive is not in the database of the current release,</b> - to have it added to the database, first use the command:<br/> - <tt>smartctl -t short /dev/hd?</tt><br/> to run a short self-test on - the drive, and wait a few minutes for the test to complete. Then - email the entire output from:<br/> <tt>smartctl -a /dev/hd?</tt><br/> - to <a - href="https://lists.sourceforge.net/lists/listinfo/smartmontools-database">smartmontools-database</a> - as a plain-text email attachment (file type: ".txt"). The timestamp - in the self-test log will help us to determine whether Attribute 9 is - being used to store the lifetime in hours, minutes, or seconds. -</p> -<p> -If you need to use any of the vendor-specific display options - (<tt>-v</tt> options) with the drive, or if any of the Attributes are - behaving strangely, please include that information as well. -</p> -</li> - -<li><b>My ATA drive is failing its self-tests, but its SMART health status is 'PASS'. What's going on?</b> - -<p> -If your ATA drive supports self-tests, you should run them on a -regular basis, for example one per week: -<br/><tt>smartctl -t long /dev/hd?</tt><br/> -After the test has completed, you should examine the results with: -<br/><tt>smartctl -l selftest /dev/hd?</tt><br/> -</p> - -<p> -If the drive fails a self-test, but still has 'PASS' SMART health -status, this usually means that there is a corrupted sector on the -disk, which can not be read. If the disk were able to read that -sector of data, even once, then the disk firmware would mark the -sector as 'bad' and then allocate a spare sectors to replace it. But -if the disk can't read the sector even once, then it won't reallocate -the sector, in hopes of being able, at some time in the future, to -read the data from it. See <a -href="http://smartmontools.sourceforge.net/BadBlockHowTo.txt">BadBlockHowTo</a> -for instructions about how to force this sector to reallocate (Linux -only). -</p> -<p> -The disk still has passing health status because the firmware has not -found other signs of trouble, such as a failing servo. -</p> -<p> -Such disks can often be repaired by using the disk manufaturer's 'disk -evaluation and repair' utility. Beware: this may force reallocation -of the lost sector and thus corrupt or destroy any file system on the -disk. See <a -href="http://smartmontools.sourceforge.net/BadBlockHowTo.txt">BadBlockHowTo</a> -for generic Linux instructions. -</p> - -</li> - -<li><b>smartd is warning that my ATA disk has unreadable or uncorrectable or pending sectors. What's going on?</b> - -<p> -Disk drives store data in blocks (sectors) of 512 bytes. Each 512 -bytes has additional bytes appended to it (usually 40 to 60) which are -used internally by the disk firmware for error checking/detection and -correction. These are called ECC bytes. -</p> -<p> -Sometimes the data in a sector gets corrupted. This can happen -because a speck of dust scratched the disk, or because the disk was -powered down while writing data to that sector, or for other reasons. -Usually the ECC bytes can be used to correct the corrupted data. -However if the ECC bytes are inconsistent or can't be used to correct -the bad data, then the 512 bytes of data are lost. Such a sector is -called unreadable or uncorrectable. -</p> -<p> -If your disk has an unreadable sector, this means that some of your -data can't be retrieved. You can force the disk to replace the -unreadable sector with a spare good sector, but only at the price of -losing the 512 bytes of data forever. -</p> -<p> -Disks with uncorrectable sectors can often be repaired by using the -disk manufaturer's 'disk evaluation and repair' utility (see previous -FAQ entry). Beware: this may force reallocation of the lost sector -and thus corrupt or destroy any file system on the disk. See <a -href="http://smartmontools.sourceforge.net/BadBlockHowTo.txt">BadBlockHowTo</a> -for generic Linux instructions. -</p> -<p> -Normally when an uncorrectable sector is found, the disk puts this -onto a 'pending sector list' to indicate that it should be replaced -with a spare good sector. However this replacement won't take place -until either the disk can read the data on the bad sector, or is -commanded to write new data to that bad sector. -</p> - -</li> - - -<li><b>My computer's BIOS has a SMART enable/disable setting. What -does it do, and how should I set it?</b> -<p> -Some type of BIOS can check the SMART health status of a disk at -bootup: the equivalent of '<tt>smartctl -H /dev/hd?</tt>'. This one-time check on -bootup is done if the BIOS SMART setting is set to 'ENABLE', and is -not done if the setting is set to 'DISABLE'. -</p> - -<p> -If this one-time check is done, and the disk's health status is found -to be 'FAIL', then typically the BIOS will display an error message -and refuse to boot the machine. -</p> - -<p> -For the proper functioning of smartmontools, either BIOS setting may -be used. -</p> -</li> - - -<li><b>My Fedora Core Linux system displays the startup message: smartd [FAILED]</b> -<p> -Fedora Core is distributed with a smartd configuration file -/etc/smartd.conf that monitors the first IDE disk /dev/hda. If this -device does not exist (or lacks SMART capability) you will get the -error message above. Look in SYSLOG (/var/log/messages) for -additional details about what is going wrong. -</p> -<p> -The solution: If your system has only SCSI disks, or has IDE disk(s) -on a non-primary controller, just edit /etc/smartd.conf to reflect the -correct location of the drive(s). Please also read the 'smartd.conf' -man page for additional information. -</p> -</li> - -<li><b>Attribute 194 (Temperature Celsius) behaves strangely on my Seagate disk</b> -<p> -Some Seagate disks store the current temperature Celsius in both the -RAW and NORMALIZED Attribute 194 values, and the maximum lifetime -temperature in Celsius in the WORST value. Since cooler is better, -this means that in this case, <i>lower</i> NORMALIZED Attribute values -are farther from failure, and that over time the WORST Attribute -values get <i>larger</i>, not <i>smaller</i> (as with other -Attributes). -</p> -</li> - -<li><b>What's this smartctl message mean?: Warning: ATA error count 9 inconsistent with error log pointer 5</b> -<p> -The ATA error log is stored in a circular buffer, and the ATA -specifications are unambiguous about how the entries should be -ordered. This warning message means that the disk's firmware does not -strictly obey the ATA specification regarding the ordering of the -error log entries in the circular buffer. Smartmontools will correct -for this oversight, so this warning message can be safely ignored by -users. (On the other hand, firmware engineers: please read the ATA -specs more closely then fix your code!). -</p> -</li> -</ul> - -<hr size="2" /><a name="scsi"></a><b>SCSI disks and tapes -(TapeAlert)</b> -<p>Smartmontools for SCSI disks and tapes (including medium changers) is -discussed on a separate <a href="smartmontools_scsi.html">page</a>. -</p> - -<hr size="2" /><a name="testinghelp"></a><b>FireWire, USB, and SATA -disks/systems</b> -<p>As for USB and FireWire (ieee1394) disks and tape drives, the news -is not good. They appear to Linux as SCSI devices but their -implementations do not usually support those SCSI commands needed by -smartmontools. The ieee1394 consortium recently certified the <span - style="font-style: italic;">first</span> external enclosure (containing -a ATA disk and a protocol bridge) as being compliant to the relevant -standards. Such devices have already been on the market for about 3 -years and they tend to only support the bare minimum of commands -needed for device operation (i.e. SMART support is an unsupported -extra).<br /> -</p> -<p>Smartmontools should work correctly with SATA drives under both -Linux 2.4 and 2.6 kernels, <i>if</i> you use the standard IDE drivers -in <tt>drivers/ide</tt>. If you use the new <tt>libata</tt> drivers, -it won't work correctly because <tt>libata</tt> doesn't yet support -the needed ATA-passthrough ioctl() calls. Jeff Garzik, the -<tt>libata</tt> developer, says that this support will be added to -libata in the future. When this happens, we'll add support to -smartmontools for a new SATA/libata device type <tt>'-d sata'</tt>. -Typically, to force an SATA disk to run using the standard -(non-libata) drivers, you must use the BIOS to select "legacy mode" -for the controller. If the IDE driver doesn't support your particular -SATA controller, or the controller doesn't have a legacy interface, -then only libata can be used. Unless the hard disk controller on the -system motherboard is Intel, VIA or nVidia, standard IDE drivers may -not work -</p> - -<hr size="2" /><a name="differfromsmartsuite"></a><b>How does -smartmontools differ from smartsuite?</b> - -<p>The smartsuite code was originally developed as a Senior Thesis by -Michael Cornwell at the Concurrent Systems Laboratory (now part of the -<a href="http://ssrc.soe.ucsc.edu/">Storage Systems Research -Center</a>), Jack Baskin School of Engineering, University of -California, Santa Cruz. -You can find some information about the original smartsuite project here: -<a href="http://www.ucsc.edu/news_events/press_releases/archive/99-00/09-99/smart_software.htm">Press Release 1</a>, -<a href="http://www.santa-cruz.com/archive/1999/September/22/local/stories/5local.htm">Press Release 2</a>, -<a href="http://www.ucsc.edu/currents/99-00/09-27/smart.html">Press Release 3</a>. -</p> - -<p> -<a href="http://csl.cse.ucsc.edu/smart.shtml">According to UCSC</a> -smartsuite is no longer maintained; the last release was in 2001. -</p> - -<p>Smartmontools was derived directly from smartsuite.  It differs -from smartsuite in that it supports the ATA/ATAPI-5 standard.  So -for example <tt>smartctl</tt> from smartsuite has no facility for -printing the SMART self-test logs, and doesn't print timestamp -information in the most usable way.  The <tt>smartctl</tt> utility -in smartmontools has added functionality for this (<tt>-q, -l selftest,-S, --T, -v and -m</tt> options), updated documentation, and also fixes small -technical bugs in smartsuite. [One example: smartsuite does not actually use the -ATA SMART RETURN STATUS command to find out the health status of a disk. It instead tries to infer this from the -SMART Attribute values.]  See the -<a href="http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?rev=HEAD&content-type=text/plain">CHANGELOG</a> -file in CVS for a summary of what's been done.  The <tt>smartd</tt> -utility differs from the smartsuite <tt>smartd</tt> in major ways.  -First, it prints somewhat more informative error messages to the syslog. -  Second, on startup it looks for a configuration file -<tt>/etc/smartd.conf</tt>, and if <tt>smartd</tt> finds this file, it -monitors the list of devices therein, rather than querying all IDE and -SCSI devices on your system.  (If the configuration file does not -exist, then it does query all IDE and SCSI devices.)  Also, it's -a well-behaved daemon and doesn't leave open file descriptors and other -detrius behind.  In addition, the <tt>smartmontools</tt> version of -<tt>smartd</tt> can be instructed (via Directives in the configuration -file) to monitor for changes in a number of different disk properties: -the SMART status, failure or prefailure attributes going below -threshold, new errors appearing in the ATA Error Log or the SMART -Self-Test Log, and so on. <tt>smartd</tt> can also send an email warning or run a -user-specified executable if it detects a problem with the disk. -</p> - -<p>The other principle difference is that smartmontools is an -OpenSource development project, meaning that we keep the files in CVS, -and that other developers who wish to contribute can commit changes to -the archive. If you would like to contribute, please write to to <a -href="http://lists.sourceforge.net/mailman/listinfo/smartmontools-support">smartmontools-support</a>.</p> - -<p>But the bottom line is that the code in smartmontools is derived -directly from smartsuite and is similar.  The smartsuite package -can be found <a href="http://sourceforge.net/projects/smartsuite/">here</a>.</p> - -<hr size="2" /><a name="references"></a><b><big>Useful references on -SMART and the ATA/ATAPI standards</big></b> - -<p><big>If you are having trouble understanding the output of smartctl -or smartd, please first read the manual pages installed on your -system:</big></p> - -<pre> -man 8 smartctl -man 8 smartd -man 5 smartd.conf -</pre> - -<p> -Here are on-line versions of the smartmontools man pages:<br/> <a -href="man/smartctl.8.html">smartctl manual page</a><br/> <a -href="man/smartd.8.html">smartd manual page</a><br/> <a -href="man/smartd.conf.5.html">smartd.conf manual page</a><br/> Note -that these are the manual pages for the <b><i>current version</i></b> -of smartmontools in the developers CVS repository; they might not -correspond to the (possibly older) version of smartmontools installed -on <i>your</i> system. So the manual pages installed on your system -should be regarded as definitive for your installation.</p> - -<p><big>If you'd like to know more about SMART, then the following -references may be helpful:</big></p> - -<ul> -<li><a href="http://www.linuxjournal.com/article.php?sid=6983">Monitoring Hard Disks with SMART (Linux Journal, Jan 2004)</a></li> - <li>The <a href="http://www.t13.org/project/d1321r1c.pdf"> ATAPI/ATA-5 -Revision 1 specification</a> (start with Section 8.41)</li> - <li>The <a href="http://www.t13.org/docs2002/d1410r3b.pdf"> ATAPI/ATA-6 -Revision 3b specification</a></li> - <li>The ATAPI/ATA-7 specification (Draft 4b) - <a href="http://www.t13.org/docs2004/d1532v1r4b%20ATA-ATAPI-7.pdf">Volume 1 (has SMART documentation)</a>, - <a href="http://www.t13.org/docs2004/d1532v2r4b%20ATA-ATAPI-7.pdf">Volume 2</a>, - <a href="http://www.t13.org/docs2004/d1532v3r4b%20ATA-ATAPI-7.pdf">Volume 3</a></li> - <li><a href="http://www.t13.org/#FTP_site">Other revisions -of the ATAPI/ATA Specs</a></li> -<li>SCSI References: -<ul> - <li>The <a href="http://www.t10.org">homepage of the T10 project</a>.</li> - <li>The <a href="ftp://ftp.t10.org/t10/drafts/s2/">SCSI-2 draft</a> by the T10 project.</li> - <li>See also other subdirectories <a href="ftp://ftp.t10.org/t10/drafts/">here</a>.</li> -</ul> -</li> -<li> - The original SMART specification is SFF-8035i from the <a href="http://www.sffcommittee.com/ns/"> - Small Form Factors (SFF) Committee</a>.  - <ul> - <li> - Here is the SFF <a href="ftp://ftp.seagate.com/sff/INF-8035.TXT"> "link"</a> - (they have "expired" the document). - </li> - <li> - Version 1.0 of <a href="ftp://ftp3.ds.pg.gda.pl/people/macro/S.M.A.R.T./SFF-8035i.pdf"> - SFF-8035i "Self-Monitoring, Analysis and Reporting Technology (S.M.A.R.T.)". </a> - </li> - <li> - Revision 2.0 of <a href="ftp://ftp3.ds.pg.gda.pl/people/macro/S.M.A.R.T./8035R2_0.PDF"> - SFF-8035i "Self-Monitoring, Analysis and Reporting Technology (S.M.A.R.T.)". </a> - </li> - <li> - Revision 1.4 of <a href="ftp://ftp3.ds.pg.gda.pl/people/macro/S.M.A.R.T./8055.PDF"> - SFF-8055i "S.M.A.R.T. Applications Guide for the ATA and SCSI Interfaces" </a> - </li> - </ul> -</li> -<li>From the <a href="http://cmrr.ucsd.edu/smart/">UCSD SMART Project</a>: -<ul> - <li><a href="http://cmrr.ucsd.edu/smart/tech_papr/HamerlySmartPaper.pdf">Bayesian -Approaches to Failure Prediction for Disk Drives</a></li> - <li><a href="http://cmrr.ucsd.edu/smart/tech_papr/SmtPapTransReliFinalWeb.pdf">Improved -Disk-Drive Failure Warnings</a></li> - </ul> - </li> - <li>From the Seagate Corporation: - <ul> - <li><a href="http://www.seagate.com/newsinfo/docs/disc/drive_reliability.pdf" target="_blank">Estimating Drive Reliability in Desktop Computers and -Consumer Electronics Systems</a></li> - <li><a href="http://www.seagate.com/docs/pdf/whitepaper/enhanced_smart.pdf" target="_blank">Enhanced SMART - Get SMART For Reliability</a></li> - <li><a href="http://www.seagate.com/docs/pdf/whitepaper/smart_u8.pdf" target="_blank">Playing it SMART</a></li> - <li><a href="http://www.seagate.com/docs/pdf/whitepaper/Enhanced_DST_Tech_Paper.pdf" target="_blank">Enhanced Drive Self-Test</a></li> - </ul> - </li> - <li><u>Specifying Reliability in the Disk Drive Industry: No More -MTBF's</u>, Jon G. Elerath (IBM Storage Systems Division) in -<i>Proceedings of the IEEE 2000 Annual Reliability and Maintainability -Symposium, pg 194, 0-7803-5848-1/00/$10.00.</i></li> - <li><a href="http://freepgs.com/smart">Zbigniew Chlondowski's SMART Information Site.</a> -This includes a useful list of <a href="http://freepgs.com/smart/attributes.php">Attributes and their meanings.</a> -</li> -</ul> - -<hr size="2" /><a name="sampleoutput"></a><b>Example output -from smartmontools smartctl utility:</b> - -<ul> - <li><a href="examples/MAXTOR-0.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM</li> - <li><a href="examples/MAXTOR-1.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (has failing SMART status - reallocated sector count)</li> - <li><a href="examples/MAXTOR-2.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (has had failing SMART test in the past. Look at the Seek Error Rate)</li> - <li><a href="examples/MAXTOR-7.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (has failing SMART status, some failed self-tests)</li> - <li><a href="examples/MAXTOR-8.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (has failing SMART status - calibration retry count)</li> - <li><a href="examples/MAXTOR-9.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (has failing SMART status - calibration retry count)</li> - <li><a href="examples/MAXTOR-10.txt">MAXTOR 4K080H4</a> 80 GB 5400 RPM (failing self-tests. Note Current_Pending_Sector raw value and Uncorrectable (UNC) read errors)</li> - <li><a href="examples/MAXTOR-3.txt">MAXTOR 6L080J4</a> 80 GB 7200 RPM</li> - <li><a href="examples/MAXTOR-4.txt">MAXTOR 6L080J4</a> 80 GB 7200 RPM</li> - <li><a href="examples/Maxtor-5.txt">Maxtor 98196H8</a> 80 GB 5400 RPM</li> - <li><a href="examples/MAXTOR-6.txt">Maxtor 4R080J0</a> Note: Attribute 9 (lifetime) stored in minutes!</li> - <li><a href="examples/IC35L120AVVA07-0-0.txt">IBM IC35L120AVVA07 (GXP 120 series)</a> 120 GB 7200 RPM (note 3 temperatures)</li> - <li><a href="examples/IC35L120AVVA07-0-1.txt">IBM IC35L120AVVA07 (GXP 120 series)</a> 120 GB 7200 RPM (note 3 temperatures)</li> - <li><a href="examples/IC35L120AVV207-0.txt">IBM IC35L120AVV207 (GXP 180 series)</a> 120 GB 7200 RPM (note 3 temperatures)</li> - <li><a href="examples/IC35L120AVV207-1.txt">IBM IC35L120AVV207 (GXP 180 series)</a> (failing SMART status and self-tests)</li> - <li><a href="examples/HITACHI_DK23BA-20-0.txt">HITACHI_DK23BA-20</a> Hitachi 20 GB Laptop Disk</li> - <li><a href="examples/HITACHI_DK23AA-12B.txt">HITACHI_DK23AA-12B</a> Really sick failing Hitachi Laptop Disk</li> - <li><a href="examples/TOSHIBA-0.txt">TOSHIBA MK2018GAS</a> Toshiba 20 GB Laptop Disk</li> - <li><a href="examples/TOSHIBA-MK6021GAS.txt">TOSHIBA MK6021GAS</a> Toshiba 60 GB Laptop Disk (note 3 temperatures)</li> - <li><a href="examples/FUJITSU1.txt">Fujitsu MHR2040AT</a> Fujitsu Laptop Disk (has failing SMART status - write error count)</li> - <li><a href="examples/FUJITSU_MHR2020AT.txt">Fujitsu MHR2020AT</a> Fujitsu Laptop Disk (has failing SMART status and self-tests)</li> - <li><a href="examples/WD2500JB.txt">Western Digital WD2500JB</a>Western Digital Disk (failing SMART status and self-tests)</li> -</ul> - -<hr size="2" /> - -Maintained by: <a href="mailto:smartmontools-support@lists.sourceforge.net">Bruce Allen</a><br /> -Copyright (C) 2002-4 Bruce Allen<br /> -Last updated: <tt>$Date: 2004/08/15 17:24:55 $</tt><br /> -CVS tag: <tt>$Id: index.html,v 1.171 2004/08/15 17:24:55 ballen4705 Exp $</tt> - -<hr size="2" /> - -<div align="center">Hosted by</div> - -<div align="center"><a href="http://sourceforge.net/"><img style="border:0;width=:88px;height:31px" - src="http://sourceforge.net/sflogo.php?group_id=64297&type=5" alt="SourceForge.net" /></a></div> - -<br /> - -<div align="center"><a href="http://validator.w3.org/check/referer"><img style="border:0;width=:88px;height:31px" - src="http://www.w3.org/Icons/valid-xhtml10.png" alt="Valid XHTML 1.0!" /></a></div> - -<br /> - -<div align="center"><a href="http://validator.w3.org/check?uri=http%3A%2F%2Fsmartmontools.sourceforge.net"> -Validate XHTML 1.0 Transitional.</a></div> - -<br /> - -<div align="center"><a href="http://validator.w3.org/checklink?uri=http%3A%2F%2Fsmartmontools.sourceforge.net&hide_type=all&depth=&check=Check">Check/Validate all links on this page.</a></div> - -</body> -</html> diff --git a/www/script b/www/script deleted file mode 100755 index fa7cd8c224367b6aba467f81fc960da4efc80375..0000000000000000000000000000000000000000 --- a/www/script +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/bash - -# This is a script to wrap smartctl output into http:// displayable form -# It requires a filename as input, and produces an file with a .html extension as output - -if [ $# -ne 1 ] ; then - echo This script requires one a file as input - exit 1 -fi - -model=`grep "Device Model" $1 | awk '{print $3}' ` - -# see if file name in use -let i=0 -while [ -f $model-$i.html ] ; do - let i+=1 -done - -filename=$model-$i -echo -e "<pre><tt>\n" > $filename.html -cat $1 >> $filename.html -echo -e "</tt></pre>\n" >> $filename.html - -echo created file $filename.html diff --git a/www/smart_logo.gif b/www/smart_logo.gif deleted file mode 100644 index 16a179c824bb4205d117f371eec0500eaf4d4c50..0000000000000000000000000000000000000000 Binary files a/www/smart_logo.gif and /dev/null differ diff --git a/www/smartmontools_scsi.xml b/www/smartmontools_scsi.xml deleted file mode 100644 index c2ee2a2d91d2c7ea6771d5086e00be0659e6c5b4..0000000000000000000000000000000000000000 --- a/www/smartmontools_scsi.xml +++ /dev/null @@ -1,1089 +0,0 @@ -<?xml version='1.0' encoding='ISO-8859-1'?> -<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" > - -<!-- -This is DocBook XML that can be rendered into a single HTML page with a -command like 'xmlto html-nochunks <this_file_name>'. It can -also be rendered into multi-page HTML (drop the "-nochunks") or pdf, -ps, txt, etc. ---> - -<article id="index"> - <articleinfo> - <title>Smartmontools for SCSI devices</title> - <author> - <firstname>Douglas</firstname> - <surname>Gilbert</surname> - <affiliation> - <address> - <email>dgilbert at interlog dot com</email> - </address> - </affiliation> - </author> - <authorinitials>dpg</authorinitials> - <pubdate>2004-05-06</pubdate> - - <revhistory> - <revision> - <revnumber>1.2</revnumber> - <date>2004-05-06</date> - <authorinitials>dpg</authorinitials> - <revremark> - reorganise, details in appendix, version 5.31 - </revremark> - </revision> - <revision> - <revnumber>1.1</revnumber> - <date>2003-10-13</date> - <authorinitials>dpg</authorinitials> - <revremark> - freebsd, timestamp - </revremark> - </revision> - <revision> - <revnumber>1.0</revnumber> - <date>2003-05-26</date> - <authorinitials>dpg</authorinitials> - <revremark> - first cut - </revremark> - </revision> - </revhistory> - - <copyright> - <year>2003</year> - <year>2004</year> - <holder>Douglas Gilbert</holder> - </copyright> - - <legalnotice> - <para> - Permission is granted to copy, distribute and/or modify this document - under the terms of the GNU Free Documentation License, Version 1.1 - or any later version published by the Free Software Foundation; - with no Invariant Sections, with no Front-Cover Texts, and with - no Back-Cover Texts. - </para> - <para> - For an online copy of the license see - <ulink url="http://www.fsf.org/copyleft/fdl.html"> - <literal>www.fsf.org/copyleft/fdl.html</literal></ulink>. - </para> - - </legalnotice> - - <abstract> - <para> - This article describes how smartmontools interacts with SCSI - storage devices (including tapes). Smartmontools is a SMART - utility toolset. <acronym>SMART</acronym> is an acronym for - Self-Monitoring, Analysis and Reporting Technology. Smartmontools - is available for the these operating systems: Linux, FreeBSD, NetBSD, - Solaris and Windows. - </para> - </abstract> - </articleinfo> - -<!-- -<toc></toc> ---> - - <sect1 id="intro"> - <title>Introduction</title> -<para> -Smartmontools controls and monitors storage devices using the -Self-Monitoring, Analysis and Reporting Technology -(<acronym>SMART</acronym>) system. This toolset was originally built -for Linux and has been ported to FreeBSD, NetBSD, Solaris and -Windows. -This article describes how smartmontools interacts with SCSI devices. -Passing reference is also made to devices that use the SCSI command -set such as USB mass storage devices and IEEE1394 devices that use -the "sbp2" protocol. -</para> -<para> -The primary web site for smartmontools is at -<ulink url="http://smartmontools.sourceforge.net"> -<literal>smartmontools.sourceforge.net</literal></ulink> from which the -latest versions (both source and binaries) can be obtained. Smartmontools -grew out of the now dormant <emphasis>smartsuite</emphasis> project which -is still available on its sourceforge site. The smartmontools main page -concentrates on ATA devices. -This article supplies some SCSI specific information for -those users of smartmontools that wish to monitor SCSI storage devices. -</para> -<para> -This document outlines the features found in smartmontools -version 5.31 that are relevant to SCSI disks and tape drives. -This document was last altered on 6th May 2004. -</para> -</sect1> - -<sect1 id="overv"> - <title>Overview of Smartmontools</title> -<para> -Smartmontools is made up of two executable programs, a configuration file -and online documentation (on Unix systems in the form of "man" pages). -The two executable programs are: -<itemizedlist> -<listitem><para><command>smartctl</command>: a command line utility -</para></listitem> -<listitem><para><command>smartd</command>: a daemon program providing a -monitoring service -</para></listitem> -</itemizedlist> -</para> -<para> -SCSI disks and tape drives allow self tests of their media, often monitor -the temperature of the device, maintain error counters and report when -various failure prediction thresholds are exceeded. To view the information -available try a command like: <command>smartctl -a /dev/sda</command>. If -<acronym>SMART</acronym> reporting has not been turned on for this disk -then use this command -first: <command>smartctl -s on /dev/sda</command>. [For operating systems -other than Linux replace <filename>/dev/sda</filename> with a SCSI disk -device name.] -</para> -<para> -The <command>smartd</command> daemon program is a service typically started -when a machine boots up. In can monitor multiple disks (both ATA and SCSI). -In Unix systems its configuration file can -be found <filename>/etc/smartd.conf</filename>. It sends alerts to the -system logs and can be configured to email system administrators when -pending failures are reported. -</para> -</sect1> - -<sect1 id="oses"> - <title>Operating Systems</title> -<para> -Smartmontools was originally written for Linux. Since then it has been -ported to various other Unix based system and Windows. The names of -SCSI disk and tape devices vary. Here is a summary: - -<table frame="all"><title>SCSI device names in various systems</title> -<tgroup cols="4" align="left" colsep="1" rowsep="1"> -<thead> -<row> -<entry/> -<entry>disks</entry> -<entry>tapes</entry> -<entry>Notes</entry> -</row> -</thead> -<tbody> -<row> -<entry><command>Linux</command></entry> -<entry><filename>/dev/sd[a-z]</filename></entry> -<entry><filename>/dev/[n]st[0-9]</filename></entry> -</row> -<row> -<entry><command>FreeBSD</command></entry> -<entry><filename>/dev/da[0-9]</filename></entry> -<entry><filename>/dev/[n|e]sa[0-9]</filename></entry> -</row> -<row> -<entry><command>NetBSD</command></entry> -<entry><filename>/dev/sd[0-9]</filename></entry> -<entry><filename>/dev/enrst[0-9]</filename></entry> -</row> -<row> -<entry><command>Solaris</command></entry> -<entry><filename>/dev/rdsk/c?t?d?s?</filename></entry> -<entry><filename>/dev/rmt/*</filename></entry> -</row> -<row> -<entry><command>Windows</command></entry> -<entry><filename>/dev/scsi[0-9][0-f]</filename></entry> -<entry><filename>/dev/scsi[0-9][0-f]</filename></entry> -<entry>ASPI adapter: 0-9, ID: 0-15, <filename>/dev/</filename> optional -</entry> -</row> -</tbody> -</tgroup> -</table> -</para> -<para> -The above list is a simplification of course. In Linux there can be multiple -drive letters followed by a partition number (1 to 15). Smartmontools will -ignore the partition number if it is given and query the underlying device. -In Linux the SCSI tape device name can be "nst" and a letter can be -appended to the device name, both decorations are ignored by smartmontools -as it accesses the underlying tape drive. Also in Linux, SCSI devices can -be accessed via their generic name which is of the form -<filename>/dev/sg[0-9]</filename>. -</para> -<para> -Linux also has an optional Solaris like -naming scheme for SCSI device (scsidev), devfs (mainly used in the lk 2.4 -series) and udev (its replacement in the lk 2.6 series). In short, device -naming is a complex area and smartmontools does its best to find -and identify (i.e. whether ATA or SCSI) a device depending on its name. In -some cases smartmontools needs guidance from the user and this can be given -by the '-d ata|scsi|3ware' option in the <command>smartctl</command> -utility and in <command>smartd</command> daemon's configuration file. -</para> -</sect1> - -<sect1 id="scsidisk"> - <title>SCSI disks</title> -<para> -What is a SCSI disk? A SCSI disk is a storage device that "talks" the SCSI -command set. An ATA disk is a storage device that "talks" the ATA -command set. That seems pretty clear. However by the time an operating -system sees the device the situation can be more complicated. -</para> -<para> -The ATA command set is used over native ATA transports which are -parallel ATA (PATA) up to 133 MB/sec and serial ATA (SATA) up to 1.5 Gbps -(approximately 150 MB/sec). In the past -when ATA disks needed to use some other transport (e.g. USB and IEEE1394) -the SCSI command set was sent over the foreign transport. So in this -case the operating system sees a device "talking" the SCSI command set -but the device is really an ATA disk. Many current disk external enclosures -contains ATA disks yet seen from the operating systems view point are -USB mass storage devices talking the SCSI command set. -</para> -<para> -The SCSI command set is used over various transports: the SCSI Parallel -Interface (SPI), Fibre Channel (FCP), Serial Attached SCSI (SAS), -IEEE1394 (SBP) and USB (mass storage). Many of these transports can -convey multiple command sets (i.e. not just the SCSI command set). The -forthcoming SAS transport is interesting as it can convey both the SCSI -and ATA command sets. There is also the case of a RAID made up of ATA -disks which communicates to host operating system with the SCSI command -set (e.g. 3ware RAID controller). -</para> -<para> -So what does all this mean for smartmontools? In most cases the answer is -not good news. Devices such as USB external disk enclosures translate -incoming (from the host) SCSI commands to their ATA equivalents and process -responses as required. This translation is limited typically to a small -number of SCSI commands (e.g. READ and WRITE) but <emphasis>not</emphasis> -those commands needed by smartmontools. The author does not know of any -SCSI_over_USB devices that support Smartmontools. The 3ware RAID (6000, 7000 -and 8000 series Escalade) controllers are supported -on several operating systems with special code. -<footnote><para> -The 3ware RAID solution tunnels the ATA commands needed for -smartmontools (together with a disk number) through a vendor specific -SCSI command. -</para></footnote> -</para> -</sect1> - -<sect1 id="smart"> - <title>SMART</title> -<para> -<acronym>SMART</acronym> never attained the status -of "standard" and its original documents have been withdrawn. Its catchy -name lives on, especially on vendors' web sites and obviously in the -name of this toolset. Luckily the good ideas in <acronym>SMART</acronym> -have been incorporated into the ATA and SCSI standards albeit in -slightly different forms. -</para> -<para> -Initially <acronym>SMART</acronym> began on SCSI disks as vendor -specific extensions. Gradually the <acronym>SMART</acronym> functionality has -moved into the standards (often by other names) and vendors are improving -their standards' compliance. [In the vendors' defence some of the -"standards" are drafts and are yet to be ratified.] -Some SCSI disk vendors have product manuals (available on the net) -that cover the parts of the SCSI command set -that their disk supports. Some of these manuals fill in details that are -left deliberately vague in the the standards. -<footnote><para> -For example: Seagate's "Cheetah 15K.3 Product Manual, Rev F" contains -sections on <acronym>SMART</acronym>, -thermal monitor, and drive self test (section 5.2.7 to 5.2.9). It also -lists the supported mode pages with their default and changeable values. -</para></footnote> -</para> -<para> -SCSI standards (found at <ulink url="http://www.t10.org"> -<literal>www.t10.org</literal></ulink>) only make one footnote -reference to the term <acronym>SMART</acronym>. -Instead the awkward term "Informational Exceptions" is used. -For SCSI tapes the term "TapeAlert" is used. -</para> -</sect1> - -<sect1 id="smartctl"> - <title>smartctl command line utility</title> -<para> -The <command>smartctl</command> command line utility gets -<acronym>SMART</acronym> information from the nominated device. In some -cases <acronym>SMART</acronym> information held by the nominated device -can be modified by the <command>smartctl</command> command. The command -has many options that can be viewed by the long usage message output be -either of these invocations: <command>smartctl -h</command> or -<command>smartctl --help</command>. Those options that are only -available to ATA disks (i.e. not available to SCSI disks or tape drives) -are marked with "[ATA]". So called "man" page documentation is also -available online. -</para> -<para> -The following options are currently available for SCSI disks and tape -drives unless otherwise noted: -<itemizedlist> -<listitem><para><command>-a | --all</command>: equivalent to the -combination <command>-i -H -A -l error -l selftest</command> options -invoked in that order. -</para></listitem> -<listitem><para><command>-A | --attributes</command>: outputs the -current device temperature, trip temperature and data from the -start-stop log page. Outputs some vendor specific information if -available. -</para></listitem> -<listitem><para><command>-C | --captive</command>: used in conjunction -with <command>-t short</command> or <command>-t long</command> options to -do short or long self tests in the foreground. [Has no effect on tape -drives.] -</para></listitem> -<listitem><para><command>-d TYPE | --device=TYPE</command> where TYPE -is "ata", "scsi" or "3ware. Overrides utility's guess about the class -of the device which is based on the form of the nominated device's name. -</para></listitem> -<listitem><para><command>-h | --help</command>: outputs lengthy usage -message and exits without any other action. -</para></listitem> -<listitem><para><command>-H | --health</command>: outputs single device -health metric determined by the device manufacturer. This will be "OK" -or a failure message. -</para></listitem> -<listitem><para><command>-i | --info</command>: outputs device -identification information (derived from a SCSI INQUIRY command) and -whether the device supports <acronym>SMART</acronym> (and temperature -warnings) and if those facilities are currently enabled. -</para></listitem> -<listitem><para><command>-l TYPE | --log=TYPE</command> where TYPE is -either "selftest" or "error". Outputs either the selftest log or the -error log. -</para></listitem> -<listitem><para><command>-q TYPE | --quietmode=TYPE</command> where TYPE is -either "silent" or "errorsonly". When the type is silent then nothing is -output to the console but the exit status is set (so it is suitable for -scripts). For "errorsonly" only errors are output to the console. The -exit status is always set. [See the smartctl man page.] -</para></listitem> -<listitem><para><command>-r TYPE | --report=TYPE</command> where TYPE is -either "ioctl[,<n>]" or "scsiioctl[,<n>]". Turns on low level -debugging of issued commands and responses. These commands are issued -through a system command called an "ioctl" in Unix. The debug can be for -all issued commands (i.e. "ioctl") or only SCSI commands ("scsiioctl"). -Optionally the TYPE can have a comma and a number post pended to increase -the volume of debug. See this <link linkend="ctldebug">section</link> for -more details. -</para></listitem> -<listitem><para><command>-s VALUE | --smart=VALUE</command> where VALUE is -either "on" or "off". Enables or disables <acronym>SMART</acronym> -monitoring (and temperature warnings). -</para></listitem> -<listitem><para><command>-S VALUE | --saveauto=VALUE</command> where VALUE -is either "on" or "off". Controls whether the error log values are -preserved across device power cycles. -</para></listitem> -<listitem><para><command>-t TEST | --test=TEST</command> where TEST -is either "offline", "short" or "long". Despite its name "offline" is -a short foreground test that all SCSI devices should support. A "short" -self test is typically 2 minutes or less. A "long" self test will be -considerably longer that 2 minutes, depending on the size of the media. -</para></listitem> -<listitem><para><command>-V | --version</command>: outputs the smartctl -version number (including the cvs version of all its source files) -and build information then exits without any other action. -</para></listitem> -<listitem><para><command>-X | --abort</command>: will terminate a -background short or long self test. Usually the self test log notes -that a self test has been aborted. [Has no effect on tape drives.] -</para></listitem> -</itemizedlist> -</para> -<para> -After the options <command>smartctl</command> expects a device name. -This device name is not required for the '--help' or '--version' options. -If no options are given and a valid device name is given then the copyright -notice is output and the program exits. If the device name is invalid -then that is reported. Only one device name can be given. -</para> -<para> -Examples of various invocations of <command>smartctl</command> on a -SCSI disk follow: -<programlisting> -# smartctl -i /dev/sda -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -Device: SEAGATE ST318451LW Version: 0003 -Serial number: xxxxxxxxxx -Device type: disk -Local Time is: Sat May 1 21:17:14 2004 EST -Device supports SMART and is Enabled -Temperature Warning Enabled -</programlisting> -</para> -<para> -<programlisting> -# smartctl -H /dev/sda -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -SMART Health Status: OK -</programlisting> -<programlisting> -# smartctl -A /dev/sda -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -Current Drive Temperature: 33 C -Drive Trip Temperature: 65 C -Vendor (Seagate) cache information - Blocks sent to initiator = 177230717 - Blocks received from initiator = 11929237 - Blocks read from cache and sent to initiator = 28677864 - Number of read and write commands whose size <= segment size = 2454038 - Number of read and write commands whose size > segment size = 1388 -Vendor (Seagate) factory information - number of hours powered up = 107.90 - number of minutes until next internal SMART test = 104 -</programlisting> -</para> -</sect1> - -<sect1 id="selftest"> - <title>Self Tests</title> -<para> -Rather than wait for thresholds to be triggered, an administrator can -request a self test or program one to happen periodically (e.g. at 3 a.m. -every night or perhaps weekly) with <command>smartd</command>. All SCSI -disks and tape drives should support a <emphasis>default</emphasis> self -test since it is mandatory. This can -be invoked with the <command>smartctl -t offline <device></command> -command. Despite the term "offline" this is actually a foreground test -of less than 2 minutes. On completion the default self test yields any -errors detected and makes no entry into the self test log. -</para> -<para> -The other self tests that are optionally supported by the device are listed -here with the <command>smartctl</command> invocation in brackets: -<itemizedlist> -<listitem><para> -background short [<command>smartctl -t short <device></command>] -</para></listitem> -<listitem><para> -background extended [<command>smartctl -t long <device></command>] -</para></listitem> -<listitem><para> -foreground short [<command>smartctl -C -t short <device></command>] -</para></listitem> -<listitem><para> -foreground extended [<command>smartctl -C -t long <device></command>] -</para></listitem> -</itemizedlist> -Short self tests should take less than two minutes to complete. The extended -self tests have been known to take more than one hour for disks that are over -100 GBytes in size. Care should be taken with foreground tests on disks -with mounted file systems as the OS may not take kindly to an hour delay -on a simple READ command. -<footnote><para> -Linux has an additional problem with the foreground extended self tests: -it will attempt to time out the command after 10 seconds. This will appear -in the self test log page as an aborted self test. This problem is fixed -in lk 2.4.22 and the lk 2.6 series (by extending the -timeout to 2 hours). To be on the safe side use the background extended -test instead. Also some disks silently ignore foreground self -tests (e.g. Seagate Cheetah 15K.1). -</para></footnote> -</para> -<para> -Background self tests can be aborted with the <command>smartctl -X -<device> </command> command. The self test log will note that an -abort was requested. -</para> -<para> -Self tests other than the default self test cause an entry to be placed -in the self test results log page. The 20 most recent self tests are -held. The self test results can be viewed with the -<command>smartctl -l selftest <device></command> command. All tests -output the accumulated power on hours when the test was performed and -the success or otherwise (e.g. the self test was aborted by the user's -request) of the test. Unsuccessful self tests output a self test segment -number (vendor specific), the logical block address of the first failure -(if appropriate) and a sense_key,asc,ascq triple (see appendix). Following -the self test result table is the expected duration of an uninterrupted -extended self test (when that figure is provided by the device). -</para> -<para> -Here is an example of a self test log: -<programlisting> -# smartctl -l selftest /dev/sda -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -SMART Self-test log -Num Test Status segment LifeTime LBA_first_err [SK ASC ASQ] - Description number (hours) -# 1 Background short Completed - 30 - [- - -] -# 2 Background long Completed - 18 - [- - -] -# 3 Background long Completed - 11 - [- - -] -# 4 Background long Completed - 11 - [- - -] -# 5 Background short Completed - 11 - [- - -] -# 6 Background short Completed - 10 - [- - -] -# 7 Background short Completed - 6 - [- - -] -# 8 Background long Completed - 6 - [- - -] -# 9 Background short Completed - 6 - [- - -] -#10 Background short Completed - 5 - [- - -] -#11 Background long Completed - 3 - [- - -] -#12 Background short Completed - 3 - [- - -] -#13 Background short Completed - 2 - [- - -] -#14 Background short Completed - 0 - [- - -] -#15 Background short Completed - 0 - [- - -] -#16 Background short Completed - 0 - [- - -] -#17 Background short Completed - 0 - [- - -] -#18 Background short Completed - 0 - [- - -] -#19 Background short Completed - 0 - [- - -] - -Long (extended) Self Test duration: 587 seconds [9.8 minutes] -</programlisting> -</para> -</sect1> - -<sect1 id="errorlog"> - <title>Error Logs</title> -<para> -The <command>smartctl -l error <device></command> command displays -the error counters maintained in the device's log pages. Here is an -example of an error log: -<programlisting> -# smartctl -l error /dev/sda -smartctl version 5.31 Copyright (C) 2002-4 Bruce Allen -Home page is http://smartmontools.sourceforge.net/ - -Error counter log: - Errors Corrected Total Total Correction Gigabytes Total - delay: [rereads/ errors algorithm processed uncorrected - minor | major rewrites] corrected invocations [10^9 bytes] errors -read: 2213 0 0 2213 2213 257.214 0 -write: 0 0 0 0 0 29.212 0 -verify: 0 0 0 0 0 0.010 0 - -Non-medium error count: 0 -</programlisting> -The displayed error logs (if available) are displayed on separate lines: -<itemizedlist> -<listitem><para> -write error counters -</para></listitem> -<listitem><para> -read error counters -</para></listitem> -<listitem><para> -verify error counters (only displayed if non-zero) -</para></listitem> -<listitem><para> -non-medium error counter (only a single number displayed) -</para></listitem> -</itemizedlist> -Each of the write, read and verify error counter logs has various -parameters codes. They are itemized below with the smartctl column -name followed, in brackets, with SCSI standard's description: -<itemizedlist> -<listitem><para> -Error Corrected delay: minor [Errors corrected without substantial delay] -</para></listitem> -<listitem><para> -Error Corrected delay: major [Errors corrected with possible delays] -</para></listitem> -<listitem><para> -Total rereads/rewrites [Total (e.g. rewrites and rereads)] -</para></listitem> -<listitem><para> -Total errors corrected [Total errors corrected] -</para></listitem> -<listitem><para> -Correction algorithm invocations [Total times correction algorithm processed] -</para></listitem> -<listitem><para> -Gigabytes processed {10^9} [Total bytes processed] -</para></listitem> -<listitem><para> -Total uncorrected errors [Total uncorrected errors] -</para></listitem> -</itemizedlist> -</para> -<para> -The SCSI standard then goes on to caution that the -<emphasis>exact</emphasis> definitions of the error counters is not -part of the standard (i.e. they are vendor specific). Unfortunately -the current batch of SCSI disk manufacturers' product manuals have -little or no additional information concerning log pages. -The disk product manuals do imply that the disk firmware collects -these counter values and periodically commit them to persistent -storage (disk or non-volatile RAM). -<footnote><para> -This is why some models spring to life after minutes of inactivity and -perform some operation even though there are no external commands -pending. -</para></footnote> -They also imply that their firmware is monitoring these error counters -and if they exceed some threshold (e.g. in a certain time interval) -then the firmware will report a thresholds exceeded. -</para> -</sect1> - -<sect1 id="smartd"> - <title>smartd daemon</title> -<para> -<command>smartd</command> is a daemon for monitoring disks (both ATA and -SCSI). It is recommended that tape drives and medium changers are monitored -in a more manual fashion with the <command>smartctl</command> command -as discussed in <xref linkend="tapes"/>. -</para> -<para> -The configuration file for <command>smartd</command> -is called <filename>/etc/smartd.conf</filename> and has a man page (as does -the <command>smartd</command> command). The controlling daemon script -is placed in the normal place for a distribution, typically -<filename>/etc/rc.d/init.d/smartd</filename>. -</para> -<para> -<command>smartd</command> polls the devices it has recognized when it -was started. By default it polls every 30 minutes. It reports any adverse -finding and noteworthy occurrences (e.g. disk drive temperature changes) -to a log file (<filename>/var/log/messages</filename>). <command>smartd -</command> can be configured to take other actions, for example send -email to a system administrator. -</para> -<para> -SCSI disks can be discovered by <command>smartd</command> via a scan of -device nodes (for linux: <filename>/dev/sda</filename> through to -<filename>/dev/sdz</filename>) by placing the word "DEVICESCAN" in -<filename>/etc/smartd.conf</filename> file. Alternatively the -"DEVICESCAN" word can be removed (or commented out) and SCSI devices -named explicitly: -<programlisting> -/dev/sda -d scsi -/dev/sdb -d scsi -</programlisting> -The "-d scsi" argument overrides what <command>smartd</command> would -guess as the device class (i.e. "ata", "scsi" or "3ware"). -</para> -</sect1> - -<sect1 id="tapes"> - <title>TapeAlert</title> -<para> -TapeAlert (or "tape alerts") is closely related to the -<acronym>SMART</acronym> infrastructure provided for SCSI disks. -TapeAlert is specialized for tape and medium changer devices. An example of -a TapeAlert is an indication that the tape drive heads need to be cleaned. -</para> -<para> -Pending TapeAlert errors can be read from the TapeAlert log page -(using <command>smartctl</command>). This can be done even when -<acronym>SMART</acronym> -monitoring is disabled (e.g. after <command>smartctl -s off <tape_device -></command>). In fact, the best way to use the TapeAlert mechanism is -to poll the flags (with <command>smartctl</command>) at relevant times when -using the tape, for example: -<itemizedlist> -<listitem><para> -when starting a new job using the tape drive -</para></listitem> -<listitem><para> -after an unrecoverable error -</para></listitem> -<listitem><para> -at the end of using each tape (and before it is unloaded) -</para></listitem> -</itemizedlist> -</para> -<para> -The TapeAlert information is divided into three severity classes: -Critical, Warning, and Information. The critical messages require -urgent user intervention. Both critical and warning errors may lead to -loss of data. Some of the errors are related to the medium and others -to the tape drive itself. This is why the TapeAlert information should be -checked when the tape is in use and not polled periodically (i.e. the -<command>smartd</command> daemon with its periodic polling is not -particularly useful for TapeAlert mechanism). -</para> -<para> -Different sets of flags are defined for tape drives and media -changers. Most of the flags are optional and the set of flags -supported depends on the device. TapeAlert is being included into the -SCSI-3 standards. Many SCSI-2 drives support TapeAlert but the -implementation may not fully conform to the SCSI-3 draft definition -used by smartmontools. -</para> -<para> -It is important that only one application -(or OS driver) is monitoring tape alerts since reading the TapeAlert log -page deactivates all flags after they are read. -<footnote><para> -In a multi initiator environment (e.g. several computers sharing the same -tape jukebox) there should only be one application monitoring tape alerts -per initiator. -</para></footnote> -Currently the Linux SCSI tape drivers (st and osst) do not check the -TapeAlert log page. In Linux, a medium changer device (i.e. the robot in -a tape jukebox) is accessed via its SCSI generic (sg) device name. -</para> -<para> -Code and information on the TapeAlert mechanism have been provided by -Kai Mäkisara <email>Kai.Makisara at kolumbus dot fi</email>. -</para> -</sect1> - -<sect1 id="examples"> - <title>Examples</title> -<para> -Here is some output from the <command>smartctl</command> -command. Mostly it is for the '--all' option. -<itemizedlist> -<listitem><para> -StorageTek LT20 tape 'jukebox': the -<ulink url="examples/bnch_DLT1.html"> -<literal>tape reading mechanism</literal></ulink> -and the -<ulink url="examples/bnch_robot.html"> -<literal>medium changer</literal></ulink> (robot). -Note the TapeAlert warnings in the medium changer output. -</para></listitem> -<listitem><para> -HP DDS-4 -<ulink url="examples/hp_c5713a_smt_a.html"> -<literal>tape</literal></ulink> -drive. -</para></listitem> -<listitem><para> -Generic ATAPI CD-RW -<ulink url="examples/atapi_cdrw_smt_a.html"> -<literal>cd writer</literal></ulink> is an example of a device that -does not support <acronym>SMART</acronym>. -</para></listitem> -<listitem><para> -IBM DDRS 39130 -<ulink url="examples/ddrs_39130_smt_a.html"> -<literal>disk</literal></ulink> - manufactured in 1998. -</para></listitem> -<listitem><para> -Fujitsu MAM3184MP 18 GigaByte -<ulink url="examples/mam3184_smt_a.html"> -<literal>disk</literal></ulink> when all is well. Here is the output from -the <command>smartctl -H</command> command after the IEC Test bit has been -set (with the <command>smartctl -s on -r ioctl,3</command> command) on the -same Fujitsu <ulink url="examples/mam3184_smt_health.html"> -<literal>disk</literal></ulink> . -</para></listitem> -<listitem><para> -Fujitsu MAP3735NP 73 GigaByte -<ulink url="examples/map3735_smt_a.html"> -<literal>disk</literal></ulink> -</para></listitem> -<listitem><para> -Quantum ATLAS IV 36 WLS, 36 GigaByte -<ulink url="examples/ativ_36_smt_a.html"> -<literal>disk</literal></ulink> -</para></listitem> -<listitem><para> -Seagate Cheetah ST318451LW 18 GigaByte -<ulink url="examples/st318451_smt_a.html"> -<literal>disk</literal></ulink>. It would seem that the total count of bytes -written is reset every time the disk is power cycled. However the total -count of bytes read seems to accumulate over power cycles. -</para></listitem> -</itemizedlist> - -</para> -</sect1> - -<sect1 id="raid"> - <title>RAID</title> -<para> -It is unlikely that a hardware RAID controller will directly support -smartmontools. A SCSI RAID controller is a virtual target device that -essentially remaps the SCSI commands it receives to the physical disks on its -internal buses. The physical disks in a "SCSI" RAID could be ATA or sATA -disks, in this case a SCSI bus is used between the host computer and an -external RAID controller since LVD SCSI buses (SPI-2,3 and 4) can run -up to 25 metres (plus other protocol related issues). -</para> -<para> -Some SCSI RAIDs equipped internally with SCSI disks allow access to the -physical disks via logical unit numbers (LUNs) greater than 0. The SCSI RAID -controller itself takes a LUN equal to 0. In this case smartmontools could -be applied to the LUNs greater than 0 that refer to physical disks. -</para> -<para> -Some SCSI RAIDs equipped internally ATA disks have a mechanism that -allows ATA commands to be tunnelled to the ATA disks. The 3ware 6000 -and 7000 series Escalade controllers are examples. In this case, -special provision has been made in smartmontools (starting with -release 5.1-16) to tunnel the ATA command required through to the -physical disks. This is done by using the <command>-d 3ware,N</command> -option/Directive. See the <command>smartctl</command> -and <command>smartd</command> man pages for details. -</para> -</sect1> - -<appendix id="Details"> - <title>Details</title> -<sect1 id="stand"> - <title>Standards</title> -<para> -One of the first surprises working with SCSI devices and smartmontools -is that the SCSI standards (found at <ulink url="http://www.t10.org"> -<literal>www.t10.org</literal></ulink>) -do <emphasis>not</emphasis> use -the term <acronym>SMART</acronym>. Instead the awkward term "Informational -Exceptions" (IE) is used. -</para> -<para> -The original SCSI standard (over 20 years old now) and the SCSI-2 standard -were monolithic documents. In SCSI-3 and beyond the SCSI standards have -been sub-divided and three categories of interest are the: -<itemizedlist> -<listitem><para>architectural model [SAM-3]</para></listitem> -<listitem><para>command sets [SPC-3, SBC-2, SSC-2, SMC-2, etc] -</para></listitem> -<listitem><para>transports [SPI-4, SBP-2, FCP-3, SAS, etc]</para></listitem> -</itemizedlist> -The architectural model while interesting says nothing specific about -Informational Exceptions or related topics. With respect to the transports -the term <emphasis>SCSI</emphasis> has often been synonymous with one -of the SCSI Parallel Interface transports (e.g. SPI-4 which is often know -as "Ultra320") however this is unhelpful. For the purpose of smartmontools -the SCSI command sets are more interesting. The main reference is the -SCSI Primary Commands (SPC-3) document, specifically these sections: -<itemizedlist> -<listitem><para>self test operations; SEND DIAGNOSTIC command (which is -the mechanism for requesting self tests) -</para></listitem> -<listitem><para>MODE SENSE and MODE SELECT commands (both 6 and 10 byte -variants); Mode parameters [the Informational Exceptions Control (IEC) mode -page and the Control mode page] -</para></listitem> -<listitem><para>LOG SENSE and LOG SELECT commands; -Log parameters [these log pages: Informational exceptions, -read/write/verify error counters, non medium error count, temperature, -start-stop cycle counter and the self test results] -</para></listitem> -</itemizedlist> -The SCSI Block Commands (SBC-2) document covers random access storage -devices such as disks (but excluding CD/DVD readers and writers which are -covered by MMC-3) while the SCSI Streaming Commands (SSC-2) document covers -tape systems. The SBC-2 standard does not contain any additional -information (compared with SPC-3) about Informational Exceptions. -The SSC-2 standard covers TapeAlert (section 4.2.15), some extra facilities in -the IEC mode page (see the mode parameters section) and some additional -log pages. Medium changers, typically the "robots" in jukebox tape systems, -often support the TapeAlert mechanism and are described in the SMC-2 standard. -</para> -</sect1> - -<sect1 id="infoexc"> - <title>Informational Exceptions</title> -<para> -So what are Informational Exceptions in the SCSI context? They are a -set of vendor specific parameters that the device firmware monitors and -if a "failure prediction threshold" is exceeded then an exception is -reported. A user is also able to set thresholds on error counters and -have an exception reported if a condition is met. Additionally most -modern disks monitor their temperature and will issue a warning if -a temperature threshold is exceeded. -</para> -<para> -The "failure prediction threshold" exception reporting and the temperature -warning are separately controlled (in byte 2 of the Informational Exceptions -Control (IEC) mode page). -<footnote><para> -Henceforth the term <emphasis>Informational Exceptions</emphasis> -(or IE) will include both Informational Exceptions and the -temperature (or "enclosure degraded") warnings. -</para></footnote> -In smartmontools the -<command>smartctl -s on <device></command> command turns on IE. -There are various reasons why this may not (fully) work (e.g. IEC mode -page not available or not changeable) so this command queries the device -again after it has attempted the change and reports the state. -The <command>smartctl -s off <device></command> command turns off -IE reporting. -<footnote><para> -IE have a (minor) performance impact on a disk. There are various other -settings in the IEC mode page (e.g. PERF, EBF and LOGERR) that address -this. The standard gives a lot of latitude to the vendor in implementing -these additional flags. This finer level of control may be added to -smartmontools if the need arises. -</para></footnote> -</para> -<sect2 id="iereport"> - <title>IE reporting</title> -<para> -Informational Exceptions are reported via the standard SCSI status -reporting mechanism of an additional sense code (asc) and an additional -sense code qualifier (ascq) pair. A selection of these pairs and the -associated message (there is full list in the SPC-3 document) is listed -here: -<programlisting> -asc ascq message -------------------------------------------------------- -0xb 0x1 Warning - specified temperature exceeded -0x5d 0x0 Failure prediction threshold exceeded -0x5d 0x2 Media failure prediction threshold exceeded -0x5d 0x10 Hardware impending failure general hard drive failure -0x5d 0x11 Hardware impending failure drive error rate too high -0x5d 0x56 Spindle impending failure start unit times too high -0x5d 0xff Failure prediction threshold exceeded (false) -</programlisting> -The last entry in the above table results from setting the TEST bit and -is for exercising the reporting mechanism rather than the indication -of an actual error. -See this <link linkend="testbit">footnote</link> for more information. -</para> -<para> -One difficulty is that the device firmware may detect these conditions -independently of any command executing. Even if it detects an informational -exception during a command it needs to be careful sending IE error -notifications back with a command especially if that command succeeded -(Linux will not handle this too well in the 2.4 kernel series). -There is asynchronous event notification (AEN) in SCSI but it is not -reliably supported across all transports. So smartmontools relies -on a poll from the <command>smartd</command> daemon (the default -is every 30 minutes) to detect informational exceptions. -</para> -<para> -The additional sense code and its qualifier are part of what is termed as -the <emphasis>sense buffer</emphasis> which is the response to a -REQUEST SENSE command. The sense key is also found in the sense buffer. -Synchronous SCSI commands that fail return a single byte status code of -CHECK CONDITION. An OS kernel would see this error/warning status and -then check the sense buffer (by doing a REQUEST SENSE or by other means) -and decide how to continue. From smartmontools's point of view, its -<command>smartd</command> daemon would like to process Informational -Exceptions without interference from the OS. This is done by setting up -the IEC mode page's MRIE field set to 6. This instructs the SCSI -device to hold a pending exception until an unsolicited REQUEST SENSE is -sent. If an exception is pending then the sense key will be "NO SENSE" -and the asc, ascq pair will be set accordingly. In the case of no pending -exception the asc,ascq pair will both be zero. The pending exception is -also visible in the IE log page, if that is supported. So -<command>smartd</command> can check the device during its normal polling -cycle. -</para> -<para> -Pending informational exceptions can also be checked by running -<command>smartctl -H <device></command>. A message of -"SMART Health Status: OK" indicates that there is no pending IE. -<footnote><para> -<anchor id="testbit"/> -One might worry whether the <command>smartd</command> daemon is properly set -up or if the device really will issue IE when the need arises. The mechanism -can be tested by setting the TEST bit in the IEC mode page. That is -done by this command: <command>smartctl -r ioctl,3 -s on <device> -</command> [ignore the extra debugging output that "-r ioctl,3" causes]. A -special asc/ascq pair is reserved for testing (0x5d,0xff) -and the standard associates with it this awkward message: "Failure prediction -threshold exceeded (false)". A call to -<command>smartctl -H <device></command> or waiting until the next -<command>smartd</command> poll should produce that message if the mechanism -is working. The IEC mode page TEST bit can be turned off (i.e. back to normal -IE) with <command>smartctl -s on <device></command>. The output -after the TEST bit has been activated is shown in the -Examples section for the Fujitsu MAM3184 disk. -</para></footnote> -</para> -</sect2> -</sect1> - -<sect1 id="ctldebug"> - <title>smartctl debug</title> -<para> -Debug information for <command>smartctl</command> is output when -the <command>-r ioctl</command> or the <command>-r scsiioctl</command> -option is used. More debug is output when the <command>-r ioctl,<n> -</command> form is used (where "n" is a number greater or equal to 1). Both -<command>-r ioctl</command> and <command>r scsiioctl,1</command> select -the same amount of SCSI debug information. The debug levels currently -defined are: -<itemizedlist> -<listitem><para> -1 - output SCSI commands sent to the device and the status received from -the device -</para></listitem> -<listitem><para> -2 - additionally, output the first 64 bytes of data sent to or received from -the device -</para></listitem> -<listitem><para> -3 - additionally, set the IEC mode page TEST bit if accompanying the '-s on' -option -</para></listitem> -</itemizedlist> -See this <link linkend="testbit">footnote</link> for more information about the -use of the IEC mode page TEST bit. -</para> -<para> -One shortcoming of the Informational Exception data provided by -SCSI devices (at least as defined in the current standard) is that -no LOG SENSE page tells the user how many hours the device has been -in use for. The device needs to track its "age" for applying timestamps -to self test results (seen in the "Lifetime (hours)" column of the -<command>smartctl -l selftest</command> command) if they are supported. -So one way to circumvent this shortcoming is to do dummy self -tests. Hence do a <command>smartctl -t short</command> command and then -wait 2 minutes to see the result in the self test log in which the most -recent self test row (i.e. the first) will have the current lifetime of -the device. -</para> -</sect1> - -<sect1 id="links"> - <title>Links</title> -<para> -Here are some links to related projects and packages: -<itemizedlist> -<listitem><para> -<anchor id="t10"/> -primary reference site for SCSI architecture, command sets and transports -<ulink url="http://www.t10.org"> -<literal>www.t10.org</literal></ulink>. -<footnote><para> -The documents found on the t10 site are actually <emphasis>draft</emphasis> -standards. Once they are ratified they become available from ANSI for -a fee. The t10 site maintains the last draft prior to ratification and -the most recent draft of yet to be ratified standards. -</para></footnote> -</para></listitem> -<listitem><para> -<anchor id="scsirastools"/> -SCSI raid monitoring tools plus a firmware update utility and other low level -tools <ulink url="http://scsirastools.sourceforge.net"> -<literal>scsirastools.sourceforge.net</literal></ulink> . -</para></listitem> -<listitem><para> -<anchor id="sg3utils"/> -A package of SCSI low level tools for Linux called sg3_utils can be found -on this page <ulink url="http://www.torque.net/sg"> -<literal>www.torque.net/sg</literal></ulink> (the most recent version -is sg3_utils-1.06). Allows command level access to SCSI devices. -</para></listitem> -<listitem><para> -<anchor id="howto"/> -There is a HOWTO on the Linux SCSI subsystem in the 2.4 series here: -<ulink url="http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO"> -<literal>www.tldp.org/HOWTO/SCSI-2.4-HOWTO</literal></ulink>. -</para></listitem> -</itemizedlist> -</para> - -<para> -CVS $Id: smartmontools_scsi.xml,v 1.9 2004/05/05 23:00:24 dpgilbert Exp $ -</para> -</sect1> -</appendix> - -</article> -