--- /dev/null
+$Id: AUTHORS,v 1.15 2004/11/11 17:56:07 ydario 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>
+David Snyder <dasnyderx@yahoo.com>
+Sergey Svishchev <svs@ropnet.ru>
+Phil Williams <phil@subbacultcha.demon.co.uk>
+Richard Zybert <richard.zybert@zybert.co.uk>
+Yuri Dario <mc6530@mclink.it>
--- /dev/null
+CHANGELOG for smartmontools
+
+$Id: CHANGELOG,v 1.537 2006/04/12 16:11:44 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
+[YD] Yuri Dario
+[CD] Casper 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
+[DS] David Snyder
+[SS] Sergey Svishchev
+[PW] Phil Williams
+[LW] Leon Woestenberg
+[RZ] Richard Zybert
+
+NOTES FOR FUTURE RELEASES: see TODO file.
+
+<DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
+
+smartmontools 5.36 Stable Release
+
+ [BA] Linux: smartd/smartctl issue syntax hints to user if 3ware
+ disk controller present with EITHER 3ware OR AMCC vendor
+ name, and user syntax incorrect.
+
+ [BA] Update copyright dates to 2006.
+
+ [DG] [SCSI] Loosen sanity check on Seagate/Hitachi factory information
+ log page so it is not skipped on recent Seagate SCSI disks.
+
+ [CF] Added command 'smartd -q showtests' to list test schedules.
+
+ [CF] Added command 'smartctl -P showall MODEL [FIRMWARE]' to list
+ database entries for specific drives and firmware.
+
+ [PW] Automatically set -v 9,minutes and -v 194,unknown for Maxtor
+ DiamondMax D540X-4G drives.
+
+ [DG] [SCSI] suppress various outputs when data fails sanity checks.
+ Correct 'last n error events' log page indexing.
+
+ [DG] [SCSI] changed smartctl exit status to reflect any problems in
+ the most recent 20 self test logs [Leandro Santi]
+
+ [DG] [SCSI] Fix process return value when scsiGetSmartData() fails
+ in smartctl [Leandro Santi]
+
+ [BA] Updated docs and error message to reflect Linux libata
+ support for smartmontools starting with the 2.6.15 kernel
+ series. Also init script support for the 'tinysofa' release.
+
+ [DG] [SCSI] Mask dpofua bit when changing mode pages. Fix failure
+ of 'smartctl -l error'.
+
+ [EM] Fixed a problem with FreeBSD and 3Ware 'twe' devices
+
+ [CF] Fixed a regexp in knowndrives table, added regexp syntax check
+ via 'smartctl -P showall'.
+
+ [CF] Cygwin & Windows: Fixed memory leak in function calling
+ IOCTL_IDE_PASS_THROUGH. Thanks to Fred Schmidt for the problem
+ report.
+
+ [CF] Cygwin: added cygrunsrv support and commands "install", "remove"
+ and "status" to smartd.initd.
+
+ [SS] Fix runtime problems on big-engian NetBSD platforms (patch provided
+ by Martin Husemann)
+
+ [CF] Cygwin smartd: Open smartd.conf in textmode to allow use of
+ Windows editors.
+
+ [CF] Cygwin smartd: Added option '--service' to allow smartd running
+ as windows service via cygrunsrv. Useful in conjunction with new
+ syslogd support added in Cygwin 1.5.15.
+
+ [CF] Windows: Added patch to avoid output of non-ascii timezone names.
+
+ [EM] Incorporate various patches to provide TWE support and support for
+ multiple 3Ware cards, Power Check Support, and FreeBSD 6.x support.
+ Thanks to Rudolf Cejka, Frank Behrens, and Jung-uk Kim.
+
+ [DG] Silence gcc 4.0.1 compile warning concerning the difference in
+ "signedness" in pointer assignments. Changes to SCSI code
+ and os_linux.c .
+
+ [PW] Additions to knowndrives table: added missing drive from Quantum
+ Fireball Plus LM series, added QUANTUM BIGFOOT TS10.0A, added
+ ExcelStor J680 and J880, added Western Digital Caviar RE Serial ATA
+ series, added missing drives from Western Digital Caviar SE series,
+ added Seagate Momentus 4200.2 series, added missing drives from
+ Maxtor DiamondMax 10 series, added Fujitsu MHG and MHH series, and
+ added Hitachi Travelstar 5K100 series.
+
+ [PW] Additions to knowndrives table: added Fujitsu MHU2100AT, added
+ Fujitsu M1623TAU, added missing drives from Seagate Barracuda
+ 7200.8 series, added Seagate Momentus 5400.2 series, and added
+ QUANTUM FIREBALL CR8.4A.
+
+ [PW] Additions to knowndrives table: added missing drive from Maxtor
+ MaxLine II series, added Maxtor DiamondMax 2880 Ultra ATA series,
+ added Maxtor DiamondMax 17 VL series, added Hitachi Deskstar 7K80
+ series, and added Hitachi Deskstar 7K400 series.
+
+ [CF] Windows: Fixed unsupported 'smartctl -X' on Win2000/XP by using
+ IOCTL_IDE_PASS_THROUGH instead.
+
+smartmontools 5.34 Stable Release [NOTE: never officially released]
+
+ [CF] Cygwin & Windows smartd: Increased SCSI DEVICESCAN range
+ from ASPI adapter 0-3 to 0-9. Added diagnostic messages.
+
+ [CF] Windows smartd: Added ability to run .bat files via '-M exec'
+ directive.
+
+ [CF] Cygwin smartd: Added FreeConsole() after fork() to avoid hang
+ of terminated shell console window.
+
+ [DG] [SCSI] Add code so 'smartctl -A' outputs the number of elements
+ in the grown defect list. When this number is increasing a
+ disk has problems. N.B. Similar logic should be added to smartd.
+
+ [CF] Windows smartd: Fixed event handling to allow start of another
+ smartd process when service is already running. Useful for testing
+ service configuration changes in debug mode.
+
+ [PW] Added following drives to knowndrives table: Western Digital Raptor
+ family, Seagate Barracuda 7200.8 family, Maxtor DiamondMax 2160
+ Ultra ATA and DiamondMax 10 families, Hitachi Travelstar E7K60
+ family, Seagate Medalist 17240, 13030, 10231, 8420, and 4310,
+ TOSHIBA MK4018GAP and MK6022GAX, ExcelStor Technology J360, and
+ Western Digital Caviar AC14300.
+
+ [PW] Added missing Fujitsu MHTxxxxAT and Seagate Barracuda 7200.7 drives
+ to knowndrives table.
+
+ [PW] Added QUANTUM FIREBALLP LM10.2 to knowndrives table. Thanks to
+ Mike Fleetwood for submitting the patch.
+
+ [KS] Solaris/SPARC: fixed not to disable automatic offline test and
+ automatic save attributes incorrectly. Thanks to Roy Badami.
+
+ [BA] Linux: smartd init script now recognizes 'trustix' distro.
+
+ [DG] [SCSI] Medium and hardware errors were slipping through
+ unreported. Fix linux SCSI sense reporting via SG_IO ioctl.
+
+ [DG] [SCSI] Change lba of first failure in selftest output to
+ decimal (was hex) to conform with ATA output.
+
+ [GK] smartd: Detect most self-test failures even if the hour counter
+ has wrapped.
+
+ [BA] smartctl: list 'marvell' as option if user give invalid
+ -d argument
+
+ [CF] Windows: fixed SCSI timeout handling to allow long timeouts
+ for selftests.
+
+ [CF] Fixed buffer overflow issues in printone() and safe_vsnprintf()
+ which results in crash on -V option (at least on Windows).
+
+ [DG] [SCSI] Add explicit timeouts to INQUIRY and REQUEST SENSE (that
+ were missed in an earlier patch). Could have impacted freebsd.
+
+ [DG] When linux detects a sata_via_libata disk suggest that user try
+ '-d ata' (rather then '-d libata). Anticipate kernel change.
+
+ [YD] Added OS/2 and eComStation platform support.
+
+ [PW] Added Seagate U4 family, Fujitsu MHJ and MHK families, Seagate
+ Barracuda 5400.1, QUANTUM FIREBALLP KX27.3, QUANTUM FIREBALLP KA10.1,
+ and ExcelStor J340 to knowndrives table.
+
+ [DG] [SCSI] After report of Hitachi IC35L073UCDY10 disks locking up
+ on log page 0x7 (last n error events), check log page (and some
+ others) is supported (via log page 0x0) before probing.
+
+ [CF] Added safe_v?snprintf() for platforms using v?snprintf()
+ with non standard behaviour on overflow (Windows, old Linux)
+
+ [CF] smartd: Added message if check power mode spins up disk.
+
+ [CF] Windows: Added support for READ_LOG on WinNT4 using undocumented
+ pseudo SCSI command via IOCTL_SCSI_PASS_THROUGH.
+
+ [CF] smartd: Added ',q' option for '-n' directive to suppress 'skipping
+ checks' log message. This prevents a laptop disk from spinning up
+ due to this message. Thanks to Rob MacLachlan and Manfred Schwarb
+ for pointing out problem & solution.
+
+ [CF] Windows: Added function get_os_version_str() to show OS flavor in
+ copyright message.
+
+ [CF] Windows: Added function ata_identify_is_cached() to check for outdated
+ SMART enabled bit in identify data.
+
+ [CF] Windows: Added fix to prevent linkage of smartd specific win32 modules
+ to smartctl.
+
+ [PW] Added Fujitsu MPG3153AH, Hitachi Endurastar J4K20/N4K20 (formerly
+ DK23FA-20J), Seagate Momentus family, and Maxtor Fireball 3 family
+ to knowndrives table.
+
+ [PW] Added missing Maxtor DiamondMax 16, Seagate Barracuda ATA IV, and
+ Western Digital Caviar WDxxxAA/WDxxxBA drives to knowndrives table.
+
+ [CF] Windows: Added ATA check power mode for smartd -n directive.
+
+ [CF] Windows: Fixed use of new service status flag which causes hang
+ of smartd service on WinNT4.
+
+ [CF] Windows: Fixed error checking of IOCTL_IDE_PASS_THROUGH (used
+ for READ_LOG on 2000/XP). Added some diagnostic messages on
+ -r ataioctl[,2]. Thanks to Manfred Schwarb for bug report and testing.
+
+ [BA] Fixed code bug that made it impossible to enable SMART on
+ disks with failing health status. This would happen if the
+ os_*.c author made STATUS and STATUS_CHECK work the same way.
+ I have corrected this at a higher level; we now handle the
+ case where STATUS and STATUS_CHECK are identical without
+ issues.
+
+ [LW] Make os_linux.c/marvell_command_interface() always return 0 on STATUS.
+ Needed for a disk having bad SMART status.
+
+ [CF] smartctl: Added drive family printing.
+
+ [CF] autogen.sh: Allow automake 1.9, added message if automake
+ version is unknown.
+
+ [BA] smartctl: use locale-specific separators for printing disk
+ capacity. Also use AC_CHECK_HEADERS not AC_CHECK_HEADER in
+ configure.in.
+
+ [BA] clean-up of #include structure so that -V options to smartd
+ and smartctl work correctly. Please, don't #include header
+ files into other header files.
+
+smartmontools 5.33 Experimental Release
+
+ [BA] smartctl: ATA disks, if SMART ATTRIBUTE THRESHOLDS page has ID
+ errors with some Attributes having NULL IDs, print Attribute
+ info anyway (but issuing a warning to the user).
+
+ [DG] [SCSI] Decode Last n error events log page; decode track following
+ and positioning errors [Hitachi]
+
+ [EM] FreeBSD: another tweak, __packed__ introduced in Version 5.0040
+
+ [EM] Cleaner tweak of fixes for FreeBSD 4.x.
+
+ [EM] Fix compilation errors under FreeBSD 4.x, as it is still using
+ and old GCC
+
+ [EM] Remove 3ware/FreeBSD specific files and just include pieces we need
+
+ [DG] Add logic in smartd to detect 3ware, Marvell controllers and SATA
+ disks behind an ATA-SCSI simulator (in Linux). If specific device
+ types are not given and they are picked in a general SCSI device
+ scan then warn and skip.
+
+ [GG] insert correct path to smartd into smartd's init script
+
+ [BA] Changed all default paths in documentation to reflect /usr/local as
+ default path prefix. This affects on-line man pages, primarily.
+
+ [DS] Added support for OpenBSD
+
+ [BA] Added another environment variable SMART_FULLMESSAGE set by
+ the smartd mailing feature, and modified examplescripts/Example1
+ to illustrate it.
+
+ [BA] Fixed potentially misleading messages of the form:
+ XXX failed: success
+
+ [DG] emit warning if SATA disk detected using libata in Linux; then exit
+
+ [PW] Added Seagate U10 family, Hitachi Travelstar 7K60, Fujitsu MHR2020AT,
+ and QUANTUM FIREBALLP AS20.5 to knowndrives table.
+
+ [DG] Detect 3ware and Marvell controllers from SCSI INQUIRY vendor string
+ and suggest usage of appropriate '-d' argument in smartctl.
+
+ [LW] Tested the RELEASE_5_33_WITH_MARVELL_SUPPORT branch on
+ actual Marvell 88SX5041 hardware, with success.
+ Merged into HEAD.
+
+ [BA] Fixed nasty DEVICESCAN bug
+
+ [BA] Checked in RELEASE_5_33_WITH_MARVELL_SUPPORT branch with
+ some Marvell support.
+
+ [BA] Additional modifications of Ed's controller scheme. Fixed
+ broken 3ware support under linux, problems with scanning
+ devices in smartd, and other small problems.
+
+ [CF] Added make targets to build formatted man pages (htmlman, txtman),
+ Windows distribution (dist-win32) and MSVC6 config.h (config-vc6).
+
+ [EM] Minor change to FreeBSD inclusion of 'twe' include files. Add
+ code to check if they exising in /usr/include/sys to use those
+ in preference to ones added here
+
+ [EM] Very preliminary support attempt for 3Ware controllers under
+ FreeBSD. Also, switched 'escalade_type/escalade_port' to
+ 'controler_type/controller_port' and moved away from
+ 'tryata/tryscsi' to using new 'controller*' variables to
+ determine which controller type (ATA/SCSI/3Ware) to use.
+
+ [GK] Added initscript support for Darwin.
+
+ [CF] Windows smartd: Added ability to run smartd as a windows service,
+ including new commands "smartd install ..." and "smartd remove"
+ to install and remove the service registry entry.
+
+ [BA] smartd: warn user if -s regexp regular expression contains
+ characters other than 0123456789.*()|+?[-]{}:=SLCO since such
+ characters are 'suspicous' and may indicate a poorly formed
+ regexp. Extended regular expression gurus: can this list be
+ reduced somewhat?
+
+ [CF] Fixed bug in Windows smartd: Missing close of config file when
+ configuration is reloaded by smartd daemon.
+
+ [CF] Windows smartd: Added mail warning feature using the "Blat"
+ (http://blat.sourceforge.net/) mailer as a default.
+
+ [PW] Added Maxtor DiamondMax Plus 5120 Ultra ATA 33 series and TOSHIBA
+ MK3017GAP to knowndrives table.
+
+ [CF] Added fixes to build smartmontools on old Linux systems
+ (libc < 6, Kernel 2.0.x).
+
+ [BA] Added ATA minor version identity strings for latest ATA specification
+ updates: ATA/ATAPI-7 T13 1532D revision 4a and ATA/ATAPI-6 published,
+ ANSI INCITS 361-2002
+
+ [PW] Added Hitachi Travelstar 5K80 family and Fujitsu MHTxxxxAH family to
+ knowndrives table.
+
+ [EM] Fix up compilation under FreeBSD < 5.x
+
+ [PW] Added QUANTUM FIREBALL EX3.2A and missing Western Digital Caviar SE
+ drives to knowndrives table.
+
+ [BA] Modified Hitachi Travelstar 80GN family regexp in drive database.
+ Thanks to [GK/CF] for problem & solution.
+
+ [GK] Added os_darwin.[ch]
+
+ [PW] Added the following drives to the knowndrives table: IBM Travelstar
+ 48GH, 30GN, and 15GN family; IBM Deskstar 37GP and 34GXP family;
+ Western Digital WDC WD272AA; Maxtor DiamondMax D540X-4D family;
+ TOSHIBA MK2016GAP, MK2018GAP, MK2018GAS, MK2023GAS; and
+ QUANTUM FIREBALL ST3.2A
+
+ [BA] smartd/smarctl now print build HOST/OS information as part
+ of startup slogan. This should make it slightly easier to
+ read bug reports from users.
+
+ [RZ] Fixed the DEVICESCAN to do what it was supposed to do - give
+ error message unless scanning is in progress.
+
+ [BA] Update documentation to describe 3ware character devices. Better
+ error detection for missing/malfunctioning devices behind 3ware
+ controllers. Now pack 3ware ioctl structures explicitly.
+
+ [BA] For ATA devices that support LBA mode, print capacity as part
+ of smartctl --info
+
+ [RZ] Made DEVICESCAN quiet about non-existing devices unless debug
+ is on.
+
+ [DG] treat "unit attention" SCSI warning as try again in some contexts
+ (test unit ready and mode sense)
+
+ [BA] on drives that store max/min rather than min/max, get order
+ correct in printing temp.
+
+ [BA] fixed typo in 'smartctl -h' output. Thanks to Gabor Z. Papp.
+
+ [BA] linux: clean-up to 3ware/AMCC support; dynamically create
+ or fix /dev/tw[ae][0-15] device node entries if they don't
+ exist or are incorrect. One can now use the character devices
+ /dev/twe[0-15] OR /dev/sd? for 3ware 6000/7000/8000 series
+ cards. One must use /dev/twa[0-15] for 3ware 9000 series cards.
+ Note that selective self-tests now work via /dev/tw[ae] devices.
+ Next step: documentation.
+
+ [BA] linux: experimental "support" for 3ware/AMCC 9000 series
+ controllers that use the 3w-9xxx driver. This will be in a
+ state of flux for a few days. Note that this requires the
+ character interface /dev/twa[0-15].
+
+ [DG] linux: extend general SCSI OS interface to use the SG_IO ioctl. If
+ not available, use the older SCSI_IOCTL_SEND_COMMAND ioctl.
+
+ [KS] Solaris/x86: fixed system identification problem in configure
+ script. Thanks to Stuart Swales.
+
+smartmontools 5.32
+
+ [BA] Update link to revised/updated IBM Deskstar Firmware
+
+ [CF] Cygwin & Windows: Added missing ASPI manager initialization
+ with GetASPI32SupportInfo(). Thanks to Nikolai SAOUKH for pointing
+ this out and providing a patch.
+
+ [BA] modified smartd init script to work on whitebox (thanks to
+ Michael Falzon)
+
+ [BA] removed (reverted) additional Attribute definitions from
+ http://smart.friko.pl/attributes.php. All (or most?) of these
+ appear to be return code values for the WD Digital Life Guard Utility.
+
+ [PW] Added Seagate Medalist 17242, 13032, 10232, 8422, and 4312 to
+ knowndrives table. Added missing Seagate U Series 5 drives.
+
+ [PW] Added the following QUANTUM models to knowndrives table:
+ FIREBALL EX6.4A, FIREBALLP AS10.2, FIREBALLP AS40.0, FIREBALL CR4.3A,
+ FIREBALLP LM15, FIREBALLP LM30, and FIREBALLlct20 30
+
+ [PW] Added missing Western Digital Protege drives to knowndrives table.
+
+ [PW] Added Maxtor DiamondMax 40 ATA 66 series and DiamondMax 40 VL Ultra
+ ATA 100 series to knowndrives table.
+
+ [PW] Added the following Hitachi/IBM drives to knowndrives table:
+ HITACHI_DK14FA-20B, Travelstar 40GNX series, Travelstar 4LP series,
+ and Travelstar DK23XXB series. Added the missing Travelstar 80GN
+ drives.
+
+ [PW] Added Fujitsu MPB series and MPG series to knowndrives table. Added
+ the missing Fujitsu MHSxxxxAT drives.
+
+ [KS] Solaris: added workaround for dynamic change of time-zone.
+
+ [KS] Solaris: fixed problem that autogen.sh cannot detect absence of
+ auto* tools.
+
+ [BA] smartd: added time-zone bug information to man page.
+ Reverted CF code for _WIN32 case.
+
+ [CF] Cygwin & Windows: Added better error messages on IDE/ATA device
+ open error.
+
+ [BA] added additional Attribute definitions from
+ http://smart.friko.pl/attributes.php
+
+ [BA] smartd: reworked TimeZone bug workaround so it is only invoked
+ for glibc. Note: this might not be right -- a similar bug may
+ exist in other platform's libcs.
+
+ [DG] SCSI smartmontools documentation updated [2004/5/6]. See:
+ http://smartmontools.sourceforge.net/smartmontools_scsi.html
+
+ [CF] Windows: Fixed reset of TZ=GMT in glibc timezone bug workaround.
+
+smartmontools 5.31
+
+ [DG] move SCSI device temperature and start-stop log page output
+ (smartctl) into --attributes section (was in --info section).
+
+ [GG] change default installation location to /usr/local
+
+ [CF] Cygwin smartd: Fixed crash on access of SCSI devices after fork().
+
+ [PW] Added TOSHIBA MK4018GAS and the following Maxtor drive families
+ to knowndrives table: DiamondMax D540X-4G, Fireball 541DX,
+ DiamondMax 3400 Ultra ATA, DiamondMax Plus 6800 Ultra ATA 66.
+
+ [PW] Added missing Maxtor DiamondMax 16, DiamondMax D540X-4K, and
+ DiamondMax Plus 45 Ulta ATA 100 drives to knowndrives table.
+
+ [PW] Added ExcelStor J240, Hitachi Travelstar 80GN family, Fujitsu
+ MHTxxxxAT family, and IBM Deskstar 25GP and 22GXP families to
+ knowndrives table.
+
+ [CF] Cygwin smartd: Added workaround for missing SIGQUIT via keyboard:
+ To exit smartd in debug mode, type CONTROL-C twice.
+
+ [BA] smartctl: printing of the selective self-test log is now
+ controlled by a new option: -l selective
+
+ [BA] Added entries for Samsung firmware versions -25 to -39 based
+ on latest info about firmware bug fixes.
+
+ [PW] Added Seagate U Series X family, Seagate U8 family, and Seagate
+ Medalist 8641 family to knowndrives table.
+
+ [CF] smartd: Added exit values 5/6 for missing/unreadable config file.
+
+ [BA] smartd: now monitor the Current Pending Sector count (Attribute 197)
+ and the Offline Pending Sector Count (Attribute 198). Log a
+ warning (and send an email, if so configured) if the raw count
+ is nonzero. These are controlled by new Directives: -C and -U.
+ Currently they are enabled by default.
+
+ [CF] Added option -c FILE, --configfile=FILE to smartd to specify
+ an alternate configuration FILE or '-' for standard input.
+
+ [KS] configure.in now searches for -lnsl and -lsocket for Solaris.
+
+ [CF] Win32/native smartd: Added thread to combine several syslog output
+ lines into one single event log entry.
+
+ [CF] Win32 smartd: Added DEVICESCAN for SCSI/ASPI devices.
+
+ [GG] Use gethostbyname() the get the DNS domain since getdomainname()
+ returns the NIS domain when sending mails from smartd.
+
+ [GG] smartd.init.in: pass smartd_opts to smartd on startup, read distribution
+ specific configuration files if found
+
+ [SS] smartctl: added NetBSD support for Selective Self-tests.
+
+ [BA] smartd.conf example configuration file now has all examples
+ commented out except for 'DEVICESCAN'.
+
+ [CF] Win32/native smartd: Added ability to display warning "emails"
+ as message box by "-m msgbox" directive. With "-m sysmsgbox",
+ a system modal (always on top) message box is shown.
+
+ [BA] smartctl: printing of self-test log for disks that support
+ Selective self-testing now shows the status of the (optional)
+ read-scan after the selective self test. Also, changed format
+ in printing self-test log to print failing LBA in base 10 not
+ base 16 (more compatible with kernel error messages). Also,
+ in printing SMART error log, print timestamps in format
+ days+hours+minutes+seconds.
+
+ [CF] Win32 smartd: Added ability to log to stdout/stderr
+ (-l local1/2). Toggling debug console still works
+ if stdout is redirected.
+
+ [BA] smartctl: selective self-test log, print current status
+ in a more detailed way. Allow writing of selective self-test
+ log provided that no other self-test is underway.
+
+ [BA] Linux: eliminated dependency on kernel tree hdreg.h.
+
+ [BA] smartctl: -l selftest option now prints Selective self-test
+ log in addition to the normal self-test log.
+ Added additional options (-t pending, -t afterselect) to
+ control remaining Selective Self-test capabilities. Tested
+ with several Maxtor disks. Modified error message printing
+ so that munged option messages print at the end not the
+ start of output.
+
+ [CF] Added daemon support to Win32 native version of smartd.
+ The daemon can be controlled by commands similar to initd
+ scripts: "smartd status|stop|reload|restart|sigusr1|sigusr2".
+
+ [CF] Added minor support for option "-l local[0-7]" to Win32 native
+ (not Cygwin) version of smartd. If specified, the log output
+ is written to file "./smartd[1-7]?.log" instead of event log.
+
+ [BA] Added Selective Self-test to smartctl (-t selective,M-N).
+ Currently only supported under Linux; Solaris, NetBSD, FreeBSD
+ and Windows developers must add WRITE LOG functionality to
+ os_*.c
+
+ [BA] Added workaround for an annoying glibc bug: if you change
+ timezones, (eg, flying with a laptop from USA to Europe)
+ localtime() does not notice this in a running
+ executable, so time that appears in the system log (syslog!)
+ will be incorrect. See
+ http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48184
+ for additional examples of this bug.
+
+ [DG] Set explicit timeouts for SCSI commands (most default to 6 seconds).
+ Previously a 0 second timeout was meant to be interpreted as a
+ default timeout but the FreeBSD port had a problem in this area.
+
+ [CF] Fixed un-thread-safe exit signal handler for Win32
+
+ [BA] Fixed un-thread-safe exit signal handler pointed out
+ by CF.
+
+ [BA] Changed configure script to eliminate warnings under
+ Solaris from sys/int_type.h conflicts with int64.h
+ Added header files for umask to smartd.c.
+
+ [BA] Man page format change from Werner LEMBERG. " " changed to \&
+
+ [CF] Added os_win32/syslogevt.* event message file tool for Win32
+ smartd (native+cygwin). May also be useful for other cygwin
+ programs writing to syslog().
+
+ [CF] Added Win32 version of smartd
+
+ [CF] Merged RELEASE_5_26_WIN32_BRANCH
+
+ [BA] Made some changes to man page markup suggested by
+ Richard Verhoeven to work around bugs in man2html.
+ Tested not to break anything under Linux and Solaris.
+
+ [CF] Moved PrintOut() from utility.c to smart{ctl,d}.c to avoid
+ syslog() output of smartctl.
+
+ [BA] Grew worried that some time-zone names could be very long (eg,
+ Mitteleuropaische Zeit) and put date string lengths into a
+ single macro in utility.c
+
+ [EM] Updated os_freebsd.c to handle older versions of FreeBSD in a
+ more appropriate/obvious fashion.
+
+ [EM] Modified autogen.sh as FreeBSD installs automake 1.7 as
+ 'automake17' and NOT 'automake-1.7'
+
+smartmontools 5.30
+
+ [PW] Added QUANTUM FIREBALLlct15 30, QUANTUM FIREBALLlct20 40, and
+ Maxtor 6Y060P0 (DiamondMax Plus 9 60GB) to knowndrives table.
+
+ [PW] Added Maxtor MaXLine II family to knowndrives table (thanks to
+ Brett Russ for submitting the patch).
+
+ [BA] Added remaining read/write commands to detailed list of
+ error log commands that have text descriptions of problem
+ printed. For commands that support it, print number of failed
+ sectors at problem LBA.
+
+ [BA] Made SuSE section of smartd init script more SuSE 9 compatible.
+ Thanks to Hans-Peter Jansen.
+
+ [CF] Windows smartd: Added IDE/ATA device scan
+ Added windows device names to smartctl.8.in, smartd.8.in
+
+ [BA] smartctl/smartd: user-provided '-F samsung' and '-F samsung2'
+ command line options/Directives did NOT over-ride preset values
+ unless user specified '-P ignore'. Now they will always over-ride
+ preset values from the database.
+
+ [BA] Added error decoding for a few more READ and WRITE commands.
+
+ [PW] Added Maxtor MaXLine Plus II, Western Digital Caviar SE (Serial ATA)
+ series, Hitachi Deskstar 7K250 series, and Ultra ATA 66 models of
+ the Maxtor DiamondMax Plus 40 series to knowndrives table.
+
+ [BA] Added Maxtor Diamondmax 250 GB drives to database. Note that
+ these model numbers are not listed in Maxtor documentation, but
+ they exist.
+
+ [BA] Removed the 'contact developers' phrase from the Samsung disk
+ warning messages.
+
+ [PW] Added TOSHIBA MK2017GAP, IBM Deskstar 14GXP and 16GP series,
+ Fujitsu MPC series, Seagate Barracuda ATA III family, and missing
+ Seagate Barracuda U Series drives to knowndrives table
+
+ [BA] smartd: wrong loglevel for message: Configuration file
+ /etc/smartd.conf parsed. Changed to LOG_INFO from LOG_CRIT.
+ Thanks to Emmanuel CHANTREAU for the report.
+
+ [CF] Checked in development version of windows code base.
+
+smartmontools 5.29 (note: there was NO 5.28 release)
+
+ [BA] smartd: configure script did not set correct directory to search for
+ smartd.conf based on --prefix argument to ./configure. Thanks to
+ GG for identifying the problem and fix.
+
+ [BA] make clean now removes man pages (generated from *.in) files as well
+ as object files.
+
+ [EM] Correct copying of sense data in FreeBSD SCSI implementation. Thanks
+ to Sergey Svishchev for noticing the bug.
+
+ [BA] On solaris, wrong warning message if no ATA support. Warning message
+ concerns 3ware controller, not ATA.
+
+ [SS] Added SCSI support for NetBSD.
+
+ [BA] on big-endian linux machines, fixed interpretation of HDIO_GET_IDENTITY
+ to correctly identify ATAPI bit (was byte swapped). This should
+ eliminate some SYSLOG noise if user queries a packet device (eg, CD
+ ROM or DVD reader).
+
+ [PW] Removed warning for IBM Deskstar 40GV & 75GXP series drives with
+ A5AA/A6AA firmware. Thanks to Gerald Schnabel.
+
+ [PW] Added Toshiba TOS MK3019GAXB SUN30G to knowndrives table
+
+ [PW] Added Western Digital Caviar AC12500, AC24300, AC25100, AC36400,
+ and AC38400 to knowndrives table
+
+ [BA] When printing ATA error log, print the LBA at which READ
+ or WRITE commands failed.
+
+ [BA] Changed syntax of error message in smartctl
+
+ [BA] Added versioning info (-V options to smartd/smartctl) for
+ Solaris ATA module.
+
+smartmontools 5.27
+
+ [KS] Added ATA/IDE support for Solaris/SPARC (ATA/IDE not yet for
+ Solaris/x86).
+
+ [BA] 3ware controllers: documented that one can monitor any of the
+ physical disks from any of the 3ware /dev/sd? logical devices.
+ Better warnings if querying a disk that does not exist.
+
+ [PW] Added Hitachi Travelstar DK23DA series, Maxtor DiamondMax Plus 40
+ series, Western Digital Caviar WDxxxAA, WDxxxBA, and WDxxxAB series
+ to knowndrives table
+
+ [BA] missing 'pragma pack' on ATA IDENTIFY DEVICE structure may have
+ caused odd or incorrect results on 64-bit machines.
+
+ [BA] smartctl/smartd allow inspection of self-test and error logs even
+ if disk firmware claims that these don't exist. This is needed
+ for some Maxtor disks whose firmware does not indicate log support
+ even though the disk DOES support it.
+
+ [BA] Improved porting instructions and documentation in os_generic.c
+
+ [PW] Add Western Digital Caviar WD136AA and SAMSUNG SP40A2H (RR100-07
+ firmware) to knowndrives table.
+
+ [EM] FreeBSD: remove extra definition of FreeNonZero
+
+ [BA] smartctl: the -q silent option was printing output for some
+ error conditions. Fixed. Will rename relevant variables to help
+ avoid these errors in the future.
+
+ [SS] NetBSD port added.
+
+ [BA] more sensible error messages for devfs and devfs-like systems.
+ Instead of saying that the DIRECTORY does not exist, say that
+ the DEVICE does not exist.
+
+ [BA] smartd: added -n Directive, to prevent disk spin-up depending
+ upon the power mode (SLEEP, STANDBY, or IDLE).
+
+ [PW] Added Maxtor DiamondMax 20 VL series, Fujitsu MPF series,
+ Maxtor DiamondMax 36 series, Maxtor DiamondMax 4320 series, and
+ Maxtor DiamondMax 536DX series to knowndrives table.
+
+ [BA] many warning messages now give the file name AND VERSION
+
+ [BA] smartd: when the user provides multiple address recipients
+ to the '-m' Directive in a comma-delineated list, the commas
+ are stripped out before passing the list of addresses to the
+ mailer program. (Thanks to Calin A. Culianu for pointing this out
+ and providing a patch.)
+
+ [BA] smartd: when the '-M exec path' Directive is used, any stdout OR
+ stderr output from the executable "path" is assumed to indicate a
+ problem, and is echoed to SYSLOG.
+
+ [BA] Added all missing IBM/Hitachi Deskstar 180GXP models to knowndrives
+ table.
+
+ [PW] Added some missing IBM/Hitachi Deskstar 120GXP models to knowndrives
+ table.
+
+ [PW] Added IBM Travelstar 14GS to knowndrives table.
+
+ [PW] Modified knowndrives table to match entire Hitachi Travelstar
+ DK23BA and DK23EA series of drives (thanks to Norikatsu Shigemura
+ for submitting the patch).
+
+ [PW] Added some missing Fujitsu MPE series drives to knowndrives table.
+
+ [PW] Added TOSHIBA MK4019GAX, TOSHIBA MK6409MAV, and QUANTUM
+ FIREBALLlct15 20 to knowndrives table.
+
+ [EM] Fixup example command output for FreeBSD
+
+ [PW] Added Maxtor DiamondMax 80 family to knowndrives table.
+
+ [EM] Catch up FreeBSD code to switch PROJECTHOME to PACKAGE_HOMEPAGE
+ macros.
+
+ [BA] smartd: now watches stdout/stderr when trying to run mail, mailx
+ or mail warning script, and reports any output to SYSLOG. This
+ gives a clearer error message if something is wrong.
+
+ [BA] smartd: Solaris init script modified to accomodate grep that
+ lacks '-q' quiet option. Also check for running process to kill
+ on stop.
+
+ [PW] Added some missing Seagate Barracuda 7200.7 and 7200.7 Plus drives
+ to knowndrives table.
+
+ [PW] Added Maxtor DiamondMax Plus 60 family and Seagate U Series 5 20413
+ to knowndrives table.
+
+ [BA] smartd: under Solaris, made default mailer be 'mailx' not
+ 'mail', since Solaris 'mail' does not accept a '-s' argument.
+ A workaround for Solaris users of earlier versions is to
+ have '-M exec /bin/mailx' in their smartd.conf config file.
+
+ [DG] some SCSI controllers don't like odd length transfers so make
+ sure LOG SENSE transfers are rounded up to an even number when
+ and odd length is reported (i.e. there is a double fetch, the
+ first to find the length, the second gets the data)
+
+ [BA] smartd man pages: under Solaris, correct section numbers in the
+ 'See also' section.
+
+ [KS/BA] smartd man page: describe how to set Solaris syslog.conf
+ file to catch all messages. Give correct Solaris SYSLOG default
+ path /var/adm/messages in man pages.
+
+ [BA] smartd: incorporated Debian startup script submitted by user.
+
+ [BA] smartctl: modified printing of self-test log entry number. Seagate
+ firmware can leave 'holes' in the self-test log while a test is
+ actually running. We now print entry numbers consistently in this
+ case, not assuming that entries are contiguous.
+
+ [PW] Added QUANTUM FIREBALL CX10.2A and Western Digital Caviar AC23200L
+ to knowndrives table.
+
+ [PW] Added QUANTUM FIREBALLlct20 20 to knowndrives table.
+
+ [PW] Added Maxtor DiamondMax Plus D740X family to knowndrives table.
+
+ [PW] Added IBM Travelstar 32GH, 30GT, and 20GN family to knowndrives
+ table.
+
+ [BA] Slackware init script modified to search for /etc/slackware-version
+ rather than /etc/slackware-release.
+
+ [PW] Added Seagate Barracuda ATA II family and TOSHIBA MK4019GAXB to
+ knowndrives table.
+
+ [GG] explain howto use autoreconf in autogen.sh
+
+ [KS] Makefile.am/configure.in: changed manual page sections for
+ Solaris.
+
+ [BA] smartd: reduced number of scheduled self-test messages if
+ test already run in current hour.
+
+ [PW] Added Maxtor DiamondMax Plus 8 family to knowndrives table.
+
+ [BA] linux: check for linux/hdreg.h. If it's there, use it. If
+ not, provide the necessary definitions ourselves.
+
+ [PW] Removed warning for IBM Deskstar 40GV & 75GXP series drives
+ with TXAOA5AA firmware
+
+ [PW] Added IBM Travelstar 25GS, 18GT, and 12GN family to knowndrives
+ table.
+
+ [PW] Added IBM/Hitachi Travelstar 60GH & 40GN family to knowndrives
+ table.
+
+ [BA] smartd: made '-s' Directive more efficient. Now store
+ compiled regex, and re-use. If device lacks certain self-test
+ capabilities, track it and don't try again.
+
+ [BA] smartd: made memory allocation for device lists completely
+ dynamic (eliminating compile-time maximum length constants).
+
+ [PW] Removed warning for SAMSUNG SP0802N with TK100-23 firmware
+
+ [PW] Added Seagate Barracuda ATA IV family to knowndrives table.
+
+ [BA] smartd: reduce per-device memory footprint by making
+ mail-warning info dynamically allocated. Also remove
+ potential memory leak if use has -m Directive twice and
+ keeps reloading the config file (highly unlikely this would
+ ever be noticed!)
+
+ [DG] smartd: added SCSI scheduled self-tests (Background
+ short or extended).
+
+ [BA] smartd: can now run scheduled offline immediate and
+ self-tests. See man page and -s Directive for details.
+
+ [GG] don't include manpages in make-dist-tarball.
+
+ [BA] smartctl: on-line examples given with -h are now correct
+ for solaris and linux, but wrong for freebsd. Ed?
+
+ [BA] smartd: man page now explains device scanning for solaris as
+ well as linux and freebsd.
+
+ [BA] smartd/smartctl: man pages now report correct CVS tag release
+ date, and executables '-V' options reports more build info.
+
+smartmontools 5.26
+
+ [BA] Improved user messages that appear from 'make install'
+
+ [PW] Removed warning for SAMSUNG SP1213N with firmware TL100-23
+
+ [BA] incorporated SuSE init script from user.
+
+ [DG] if SCSI device is read only, then open it read only.
+
+ [BA] when compiled on non-supported system (NOT linux, freebsd or solaris) then
+ the run-time error messages now clearly say 'your system is not supported'
+ and give clear directions.
+
+ [BA] ./configure script now works correctly on SuSE linux boxes
+
+ [BA] minor improvements to man pages
+
+ [BA] simplified detection of packet (ATAPI, CD) devices.
+
+ [BA] init script (redhat, mandrake, yellowdog) now uses correct
+ strings for translation and is slightly more standard.
+
+ [DG] smartctl: output scsi Seagate vendor pages for disks (not tapes)
+
+smartmontools 5.25
+
+Note: there was no '5.24' release. From this point on, even numbered
+releases will be 'stable' ones and odd numbered releases will be
+unstable/testing/development ones.
+
+ [DG] smartd/smartctl: changed scsiClearControlGLTSD() to
+ scsiSetControlGLTSD() with an 'enabled' argument so '-S on'
+ and '-S off' work for SCSI devices (if changing GLTSD supported).
+
+ [BA] smartd/smartctl: wired in scsiClearControlGLTSD(). Could still
+ use a corresponding Set function. Left stubs for this purpose.
+
+ [DG] scsicmds: added scsiClearControlGLTSD() [still to be wired in]
+
+ [BA] smartctl: make SCSI -T options behave the same way as the
+ ATA ones.
+
+ [DG] smartctl: output scsi transport protocol if available
+
+ [DG] scsi: stop device scan in smartd and smartctl if badly formed
+ mode response [heuristic to filter out USB devices before we
+ (potentially) lock them up].
+
+ [BA] smartd: deviceclose()->CloseDevice(). Got rid of SCSIDEVELOPMENT
+ macro-enabled code. Added -W to list of gcc specific options to
+ always enable. Made code clean for -W warnings.
+
+ [PW] Added Maxtor DiamondMax VL 30 family to knowndrives table.
+
+ [DG] scsi: add warning (when '-l error' active) if Control mode page
+ GLTSD bit is set (global disable of saving log counters)
+
+ [DG] scsi: remember mode sense cmd length. Output trip temperature
+ from IE lpage (IBM extension) when unavailable from temp lpage.
+
+ [BA] smartd: for both SCSI and ATA now warns user if either
+ the number of self-test errors OR timestamp of most
+ recent self-test error have increased.
+
+ [DG] smartctl: output Seagate scsi Cache and Factory log pages (if
+ available) when vendor attributes chosen
+
+ [DG] smartd: add scsiCountFailedSelfTests() function.
+
+ [DG] Do more sanity checking of scsi log page responses.
+
+ [BA] smartd: now warns user if number of self-test errors has
+ increased for SCSI devices.
+
+ [BA] smartd: warn user if number of ATA self-test errors increases
+ (as before) OR if hour time stamp of most recent self-test
+ error changes.
+
+ [DG] More checks for well formed mode page responses. This has the side
+ effect of stopping scans on bad SCSI implementations (e.g. some
+ USB disks) prior to sending commands (typically log sense) that
+ locks them up.
+
+ [PW] Added Western Digital Caviar family and Caviar SE family to
+ knowndrives table.
+
+ [BA] smartd: added -l daemon (which is the default value if -l
+ is not used).
+
+ [PW] Added Seagate Barracuda ATA V family to knowndrives table.
+
+ [BA] smartd: added additional command line argument -l FACILITY
+ or --logfacility FACILITY. This can be used to redirect
+ messages from smartd to a different file than the one used
+ by other system daemons.
+
+ [PW] Added Seagate Barracuda 7200.7, Western Digital Protege WD400EB,
+ and Western Digital Caviar AC38400 to knowndrives table.
+
+ [BA] smartd: scanning should now also work correctly for
+ devfs WITHOUT traditional links /dev/hd[a-t] or /dev/sd[a-z].
+
+ [PW] Added Maxtor 4W040H3, Seagate Barracuda 7200.7 Plus,
+ IBM Deskstar 120GXP (40GB), Seagate U Series 20410,
+ Fujitsu MHM2100AT, MHL2300AT, MHM2150AT, and IBM-DARA-212000
+ to knowndrives table.
+
+ [PW] Added remaining Maxtor DiamondMax Plus 9 models to knowndrives
+ table.
+
+ [EM] smartd: If no matches found, then return 0, rather than an error
+ indication, as it just means no devices of the given type exist.
+ Adjust FreeBSD scan code to mirror Linux version.
+
+ [BA] smartd: made device scan code simpler and more robust. If
+ too many devices detected, warn user but scan as many
+ as possible. If error in scanning, warn user but don't
+ die right away.
+
+ [EM] smartd: To keep as consistent as possible, migrate FreeBSD
+ devicescan code to also use glob(3). Also verified clean
+ compile on a 4.7 FreeBSD system.
+
+ [BA] smartd: Modified device scan code to use glob(3). Previously
+ it appeared to have trouble when scanning devices on an XFS
+ file system, and used non-public interface to directory
+ entries. Problems were also reported when /dev/ was on an
+ ext2/3 file system, but there was a JFS partition on the same
+ disk.
+
+ [BA] Clearer error messages when device scanning finds no suitable
+ devices.
+
+ [EM] FreeBSD: Fixup code to allow for proper compilation under
+ -STABLE branch.
+
+smartmontools 5.23
+
+ [BA] smartd: didn't close file descriptors of ATA packet devices
+ that are scanned. Fixed.
+
+ [BA] Added reload/report targets to the smartmontools init script.
+ reload: reloads config file
+ report: send SIGUSR1 to check devices now
+
+smartmontools 5.22
+
+ [EM] Fix compile issues for FreeBSD < 5-CURRENT.
+
+ [PW] Added Fujitsu MHM2200AT to knowndrives table.
+
+ [BA] To help catch bugs, clear ATA error structures before all
+ ioctl calls. Disable code that attempted to time-out on SCSI
+ devices when they hung (doesn't work).
+
+ [BA] Documented STATUS/ERROR flags added by [PW] below.
+
+ [BA] Improved algorithm to recognize ATA packet devices. Should
+ no longer generate SYSLOG kernel noise when user tries either
+ smartd or smartctl on packet device (CD-ROM or DVD). Clearer
+ warning messages from smartd when scanning ATA packet device.
+
+ [PW] Added TOSHIBA MK4025GAS to knowndrives table.
+
+ [PW] Added a textual interpretation of the status and error registers
+ in the SMART error log (ATA). The interpretation is
+ command-dependent and currently only eight commands are supported
+ (those which produced errors in the error logs that I happen to
+ have seen).
+
+ [BA] added memory allocation tracking to solaris code.
+ Fixed solaris signal handling (reset handler to default
+ after first call to handler) by using sigset. Added
+ HAVE_SIGSET to configure.in
+
+ [CD] solaris port: added SCSI functionality to solaris
+ stubs.
+
+ [BA] smartd: attempt to address bug report about smartd
+ hanging on USB devices when scanning:
+ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=107615
+ Set a timeout of SCSITIMEOUT (nominally 7 seconds) before
+ giving up.
+
+ [EM] smartd: DEVICESCAN will follow links in a devfs filesystem and
+ make sure the end point is a disc. Update documentation, added
+ note about FreeBSD scanning
+
+ [BA] smartd: DEVICESCAN also looks for block devices in
+ /dev. Updated documentation. Now scans for up to
+ 20 ATA devices /dev/hda-t rather than previous 12
+ /dev/hda-l.
+
+ [EM] smartd: mirror the FreeBSD DEVICESCAN logic for Linux,
+ so that smartd now scans only devices found in /dev/. Also,
+ make utility memory functions take a line number and file so
+ that we report errors with the correct location.
+
+ [GG] add a note about Debian bug #208964 to WARNINGS.
+
+ [BA] smartctl: -T verypermissive option broken. Use
+ -T verpermissive until the next release, please.
+
+ [BA] Syntax mods so that code also compiles on Solaris using
+ Sun Workshop compiler. Need -xmemalign 1i -xCC flags
+ for cc.
+
+smartmontools 5.21
+
+ [DK] Changed configure.in so -Wall is only included if gcc
+ is used (this is a gcc specific flag) and -fsignedchar
+ is not used at all (this is a gcc specific compiler
+ flag).
+
+ [BA] Modifications so that code now compiles under solaris. Now
+ all that's needed (:-) is to fill in os_solaris.[hc]. Added
+ os_generic.[hc] as guide to future ports. Fixed -D option
+ of smartd (no file name). Modified -h opt of smartd/smartctl
+ to work properly with solaris getopt().
+
+ [EM] Update MAN pages with notes that 3ware drives are NOT supported
+ under FreeBSD. Cleanup FreeBSD warning message handling.
+
+ [EM] FreeBSD only: Fix first user found bug....I guess I was making
+ the wrong assumption on how to convert ATA devnames to
+ channel/unit numbers.
+
+ [EM] Allow for option --enable-sample to append '.sample' to installed
+ smartd.conf and rc script files. Also, let rc script shell setting
+ be determined by configure
+
+ [EM] Minor autoconf update to include -lcam for FreeBSD
+
+ [EM] Add conditional logic to allow FreeBSD to compile pre-ATAng.
+ -- note, not tested
+ Add some documentation to INSTALL for FreeBSD.
+
+ [EM] Implement SCSI CAM support for FreeBSD. NOTE: I am not an expert
+ in the use of CAM. It seems to work for me, but I may be doing
+ something horribly wrong, so please exercise caution.
+
+ [EM] Switch over to using 'atexit' rather than 'on_exit' routine. This also
+ meant we needed to save the exit status elsewhere so our 'Goodbye'
+ routine could examine it.
+
+ [EM] Move the DEVICESCAN code to os specific files. Also moved some of the
+ smartd Memory functions to utility.c to make available to smartctl.
+
+ [EM] Code janitor work on os_freebsd.c.
+
+ [EM] Added os_freebsd.[hc] code. Additional code janitor
+ work.
+
+ [BA] Code janitor working, moving OS dependent code into
+ os_linux.[hc].
+
+ [GG] conditionally compile os_{freebsd,linux}.o depending on
+ host architecture
+
+ [PW] Print estimated completion time for tests
+
+ [BA] Added -F samsung2 flag to correct firmware byte swap.
+ All samsung drives with *-23 firmware revision string.
+
+smartmontools 5.20
+
+ [GG] Fixed broken Makefile.am (zero length smartd.conf.5
+ was being created), fix broken uninstall/distcheck targets
+
+ [FM] Improved Slackware init script added to /etc/smartd.initd
+
+smartmontools 5.19 [NOTE CHANGE OF RELEASE NUMBERING]
+
+ [BA] smartctl: added '-T verypermissive' option which is
+ equivalent to giving '-T permissive' many times.
+
+ [BA] Try harder to identify from IDENTIFY DEVICE structure
+ if SMART supported/enabled. smartd now does a more
+ thorough job of trying to assess this before sending
+ a SMART status command to find out for sure.
+
+ [BA] smartctl: it's now possible to override the program's
+ guess of the device type (ATA or SCSI) with -d option.
+
+ [BA] try hard to avoid sending IDENTIFY DEVICE to packet
+ devices (CDROMS). They can't do SMART, and this generates
+ annoying syslog messages. At the same time, identify type
+ of Packet device.
+
+ [BA] smartctl: Can now use permissive option more
+ than once, to control how far to go before giving up.
+
+ [BA] smartd: if user asked to monitor either error or self-test
+ logs (-l error or -l selftest) WITHOUT monitoring any of the
+ Attribute values, code will SEGV. For 5.1-18 and earlier,
+ a good workaround is to enable Auto offline (-o on).
+
+ [BA] smartctl: If enable auto offline command given, update auto
+ offline status before printing capabilities.
+
+ [GG] Make autotools build the default, remove autotools.diff
+
+ [GG] Add auto{conf,make} support, not enabled by default.
+
+ [BA] Eliminated #include <linux/hdreg.h> from code. This
+ should simplify porting to solaris, FreeBSD, etc. The
+ only linux-specific code is now isolated to three routines,
+ one for SCSI, one for Escalade, one for ATA.
+
+smartmontools 5.1-18
+
+ [BA] smartd: fixed serious bug - Attributes not monitored unless
+ user told smartd to ignore at least one of them!
+
+smartmontools 5.1-17
+
+ [BA] Default runlevels for smartd changed from 3 and 5 to
+ 2, 3, 4, and 5.
+
+ [BA] Removed as much dynamic memory allocation as possible from
+ configuration file parsing. Reloading config file, even in
+ presence of syntax errors etc. should not cause memory leaks.
+
+ [PW] It is no longer permissible for the integer part (if any) of
+ arguments to --report and --device to be followed by non-digits.
+ For example, the "foo" in --report=ioctl,2foo was previously
+ ignored, but now causes an error.
+
+ [BA] smartd: added -q/--quit command line option to specify
+ under what circumstances smartd should exit. The old
+ -c/--checkonce option is now obsoleted by this more
+ general-purpose option.
+
+ [BA] smartd now responds to a HUP signal by re-reading its
+ configuration file /etc/smartd.conf. If there are
+ errors in this file, then the configuration file is
+ ignored and smartd continues to monitor the devices that
+ it was monitoring prior to receiving the HUP signal.
+
+ [BA] Now correctly get SMART status from disks behind 3ware
+ controllers, thanks to Adam Radford. Need 3w-xxxx driver
+ version 1.02.00.037 or later. Previously the smartmontools
+ SMART status always returned "OK" for 3ware controllers.
+
+ [BA] Additional work on dynamic memory allocation/deallocation.
+ This should have no effect on smartctl, but clears that way
+ for smartd to dynamically add and remove entries. It should
+ also now be easier to modify smartd to re-read its config
+ file on HUP (which is easy) without leaking memory (which is
+ harder). The philosophy is that memory for data structures in
+ smartd is now allocated only on demand, the first time it
+ is needed.
+
+ [BA] smartd: finished cleanup. Now use create/rm functions for
+ cfgentries and dynamic memory allocation almost everywhere.
+ Philosophy: aggresively try and provoke SEGV to help find
+ bad code.
+
+ [BA] Added SAMSUNG SV0412H to knowndrives table.
+
+ [BA] smartd: if DEVICESCAN used then knowndrives table might not set
+ the -v attributes correctly -- may have been the same for all
+ the drives. Cleaned up some data structures and memory
+ allocation to try and ensure segvs if such problems are
+ introduced again.
+
+ [BA] Now allow -S on and -o on for the 3ware device type. For these
+ commands to be passed through, the stock 3ware 3w-xxxx driver
+ must be patched (8 lines). I'll post a patch on the smartmontools
+ home page after it's been tested by a few other people and 3ware
+ have had a chance to look it over.
+
+smartmontools-5.1-16
+
+ [BA] smartd - can now monitor ATA drives behind 3ware controllers.
+
+ [BA] smartd - changed some FATAL out of memory error messages from
+ syslog level LOG_INFO to LOG_CRIT.
+
+ [BA] smartctl - added code to look at ATA drives behind 3ware RAID
+ controllers using the 3w-xxxx driver. Note that for technical
+ reasons related to the 3w-xxxx driver, the "Enable Autosave",
+ "Enable Automatic Offline" commands are not implemented.
+ I will add this to smartd shortly.
+
+ [BA] smartd - modified sleep loop, so that smartd no longer comes
+ on the run queue every second. Instead, unless interrupted,
+ it sleeps until the next polling time, when it wakes up. Now
+ smartd also tries to wake up at exactly the right
+ intervals (nominally 30 min) even if the user has been sending
+ signals to it.
+
+ [GG] add Fujitsu MHN2300AT to vendoropts_9_seconds.
+
+ [EB] Fujitsu change in knowndrives ... match the whole MPD and
+ MPE series for vendoropts_9_seconds.
+
+ [BA] smartd bug, might cause segv if a device can not be opened. Was
+ due to missing comma in char* list. Consequence is that email
+ failure messages might have had the wrong Subject: heading for
+ errorcount, FAILEDhealthcheck, FAILEDreadsmartdata, FAILEDreadsmarterrorlog,
+ FAILEDreadsmartsefltestlog, FAILEDopendevice were all displaced by
+ one. And FAILEDopendevice might have caused a segv if -m was being
+ used as a smartd Directive.
+
+smartmontools-5.1-15
+
+ [BA] Cleaned up smartmontools.spec so that upgrading, removing
+ and other such operations correctly preserve running behavior
+ and booting behavior of smartd.
+
+ [BA] Improved formatting of ATA Error Log printout, and added
+ listing of names of commands that caused the error. Added
+ obsolete ATA-4 SMART feature commands to table, along with
+ obsolete SFF-8035i SMART feature command.
+
+ [PW] Added atacmdnames.[hc], which turn command register &
+ feature register pairs into ATA command names.
+
+ [BA] Added conveyance self-test. Some code added for selective
+ self-tests, but #ifdefed out.
+
+ [BA] Modified smartd exit status and log levels. If smartd is
+ "cleanly" terminated, for example with SIGTERM, then its
+ exit messages are now logged at LOG_INFO not LOG_CRIT
+
+ [BA] Added Attribute IDs (Fujitsu) 0xCA - 0xCE. This is decimal
+ 202-206. Added -v switches for interpretation of Attributes
+ 192, 198 and 201.
+
+ [BA] Made smartmontools work with any endian order machine for:
+ - SMART selftest log
+ - SMART ATA error log
+ - SMART Attributes values
+ - SMART Attributes thesholds
+ - IDENTIFY DEVICE information
+ - LOG DIRECTORY
+ Smartmontools is now free of endian bias and works correctly
+ on both little- and big-endian hardware. This has been tested by
+ three independent PPC users on a variety of ATA and SCSI hardware.
+
+ [DG] Check that certain SCSI command responses are well formed. If
+ IEC mode page response is not well formed exit smartctl. This
+ is to protect aacraid. smartd should ignore a aacraid device.
+
+smartmontools-5.1-14
+
+ [BA] smartctl: added column to -A output to show if Attributes are
+ updated only during off-line testing or also during normal
+ operation.
+
+smartmontools-5.1-13
+
+ [BA] smartd: attempt to enable/disable automatic offline testing even
+ if the disk appears not to support it. Now the same logic
+ as smartctl.
+
+ [BA] Added definition of Attribute 201, soft read error rate.
+
+ [BA] Added IBM/Hitachi IC35L120AVV207-1 (GXP-180) and corresponding
+ 8MB Cache GXP-120 to drive database.
+
+ [BA] smartd: if DEVICESCAN Directive used in smartd.conf, and
+ -I, -R or -r Directives used in conjunction with this, got
+ segv errors. Fixed by correcting memory allocation calls.
+
+ [BA] smartd: enable automatic offline testing was broken due
+ to cut-and-paste error that disabled it instead of
+ enabling it. Thanks to Maciej W. Rozycki for pointing
+ out the problem and solution.
+
+ [BA] Fixed "spelling" of some Attribute names to replace spaces
+ in names by underscores. (Fixed field width easier for awk
+ style parsing.)
+
+ [BA,GF] Added mods submitted by [GF] to support Attribute 193 being
+ load/unload cycles. Add -v 193,loadunload option, useful for
+ Hitachi drive DK23EA-30, and add this drive to knowndrive.c
+ Add meaning of attribute 250 : Read error retry rate
+
+smartmontools-5.1-12
+
+ [BA] Added another entry for Samsung drives to knowndrive table.
+
+ [DG] Refine SCSI log sense command to do a double fetch in most cases
+ (but not for the TapeAlert log page). Fix TapeAlert and Self Test
+ log page response truncation.
+
+ [PW] Added 'removable' argument to -d Directive for smartd. This indicates
+ that smartd should continue (rather than exit) if the device does not
+ appear to be present.
+
+ [BA] Modified smartmontools.spec [Man pages location] and
+ smartd.initd [Extra space kills chkconfig!] for Redhat 6.x
+ compatibility (thanks to Gerald Schnabel).
+
+smartmontools-5.1-11
+
+ [EB] Add another Fujitsu disk to knowndrives.c
+
+ [GG] match for scsi/ and ide/ in case of devfs to exclude false postives
+
+ [BA] If SCSI device listed in /etc/smartd.conf fails to open or do
+ SMART stuff correctly, or not enough space
+ to list all SCSI devices, fail with error unless
+ -DSCSIDEVELOPMENT set during compile-time.
+
+ [BA] Added automatic recognition of /dev/i* (example: /dev/ide/...)
+ as an ATA device.
+
+ [DG] Add "Device type: [disk | tape | medium changer | ...] line to
+ smartctl -i output for SCSI devices.
+
+ [PW] Fixed bug in smartd where test email would be sent regularly (for
+ example, daily if the user had specified -M daily) instead of just
+ once on startup.
+
+ [KM] More TapeAlert work. Added translations for media changer
+ alerts. TapeAlert support reported according to the log page
+ presence. ModeSense not attempted for non-ready tapes (all
+ drives do not support this after all). Get peripheral type from
+ Inquiry even if drive info is not printed. Add QUIETON()
+ QUIETOFF() to TapeAlert log check.
+
+ [BA] Stupid bug in atacmds.c minor_str[] affected ataVersionInfo().
+ Two missing commas meant that minor_str[] had two few elements,
+ leading to output like this:
+ Device Model: Maxtor 6Y120L0
+ Serial Number: Y40BF74E
+ Firmware Version: YAR41VW0
+ Device is: Not in smartctl database [for details use: -P showall]
+ ATA Version is: 7
+ ATA Standard is: 9,minutes
+ ^^^^^^^^^
+ Missing commas inserted.
+
+ [BA] Fixed smartd bug. On device registration, if ATA device did
+ not support SMART error or self-test logs but user had asked to
+ monitor them, an attempt would be made to read them anyway,
+ possibly generating "Drive Seek" errors. We now check that
+ the self-test and error logs are supported before trying to
+ access them the first time.
+
+ [GG/BA] Fixed bug where if SMART ATA error log not supported,
+ command was tried anyway. Changed some error printing to use
+ print handlers.
+
+ [GG] Makefile modifications to ease packaging
+
+ [DG] Did work for TapeAlerts (SCSI). Now can detect /dev/nst0 as a
+ SCSI device. Also open SCSI devices O_NONBLOCK so they don't
+ hang on open awaiting media. The ATA side should worry about
+ this also: during a DEVICESCAN a cd/dvd device without media
+ will hang. Added some TapeAlert code suggested by Kai Makisara.
+
+smartmontools-5.1-10
+
+ [PW] Extended the -F option/Directive to potentially fix other firmware
+ bugs in addition to the Samsung byte-order bug. Long option name is
+ now --firmwarebug and the option/Directive accepts an argument
+ indicating the type of firmware bug to fix.
+
+ [BA] Fixed a bug that prevented the enable automatic off-line
+ test feature from enabling. It also prevented the enable Attribute
+ autosave from working. See CVS entry for additional details.
+
+ [PW] Modified the -r/--report option (smartctl and smartd) to allow the
+ user to specify the debug level as a positive integer.
+
+ [BA] Added --log directory option to smartctl. If the disk
+ supports the general-purpose logging feature set (ATA-6/7)
+ then this option enables the Log Directory to be printed.
+ This Log Directory shows which device logs are available, and
+ their lengths in sectors.
+
+ [PW] Added -P/--presets option to smartctl and -P Directive to smartd.
+
+ [GG] Introduce different exit codes indicating the type of problem
+ encountered for smartd.
+
+ [DG] Add non-medium error count to '-l error' and extended self test
+ duration to '-l selftest'. Get scsi IEs and temperature changes
+ working in smartd. Step over various scsi disk problems rather
+ than abort smartd startup.
+
+ [DG] Support -l error for SCSI disks (and tapes). Output error counter
+ log pages.
+
+ [BA] Added -F/--fixbyteorder option to smartctl. This allows us to read
+ SMART data from some disks that have byte-reversed two- and four-
+ byte quantities in their SMART data structures.
+
+ [BA] Fixed serious bug: the -v options in smartd.conf were all put
+ together and used together, not drive-by-drive.
+
+ [PW] Added knowndrives.h and knowndrives.c. The knowndrives array
+ supersedes the drivewarnings array.
+
+ [GG] add {-p,--pidfile} option to smartd to write a PID file on
+ startup. Update the manpage accordingly.
+
+ [DG] Fix scsi smartd problem detecting SMART support. More cleaning
+ and fix (and rename) scsiTestUnitReady(). More scsi renaming.
+
+ [BA] Fixed smartd so that if a disk that is explictily listed is not
+ found, then smartd will exit with nonzero status BEFORE forking.
+ If a disk can't be registered, this will also be detected before
+ forking, so that init scripts can react correctly.
+
+ [BA] Replaced all linux-specific ioctl() calls in atacmds.c with
+ a generic handler smartcommandhandler(). Now the only routine
+ that needs to be implemented for a given OS is os_specific_handler().
+ Also implemented the --report ataioctl. This provides
+ two levels of reporting. Using the option once gives a summary
+ report of device IOCTL transactions. Using the option twice give
+ additional info (a printout of ALL device raw 512 byte SMART
+ data structures). This is useful for debugging.
+
+ [DG] more scsi cleanup. Output scsi device serial number (VPD page
+ 0x80) if available as part of '-i'. Implement '-t offline' as
+ default self test (only self test older disks support).
+
+ [BA] Changed crit to info in loglevel of smartd complaint to syslog
+ if DEVICESCAN enabled and device not found.
+
+ [BA] Added -v 194,10xCelsius option/Directive. Raw Attribute number
+ 194 is ten times the disk temperature in Celsius.
+
+ [DG] scsicmds.[hc] + scsiprint.c: clean up indentation, remove tabs.
+ Introduce new intermediate interface based on "struct scsi_cmnd_io"
+ to isolate SCSI generic commands + responses from Linux details;
+ should help port to FreeBSD of SCSI part of smartmontools.
+ Make SCSI command builders more parametric.
+
+smartmontools-5.1-9
+
+ [BA] smartctl: if HDIO_DRIVE_TASK ioctl() is not implemented (no
+ kernel support, then try to assess drive health by examining
+ Attribute values/thresholds directly.
+
+ [BA] smartd/smartctl: added -v 200,writeerrorcount option/Directive
+ for Fujitsu disks.
+
+ [BA] smartd: Now send email if any of the SMART commands fails,
+ or if open()ing the device fails. This is often noted
+ as a common disk failure mode.
+
+ [BA] smartd/smartctl: Added -v N,raw8 -v N,raw16 and -v N,raw48
+ Directives/Options for printing Raw Attributes in different
+ Formats.
+
+ [BA] smartd: Added -r ID and -R ID for reporting/tracking Raw
+ values of Attributes.
+
+ [BA] smartd/smartctl: Changed printing of spin-up-time attribute
+ raw value to reflect current/average as per IBM standard.
+
+ [BA] smartd/smartctl: Added -v 9,seconds option for disks which
+ use Attribute 9 for power-on lifetime in seconds.
+
+ [BA] smartctl: Added a warning message so that users of some IBM
+ disks are warned to update their firmware. Note: we may want
+ to add a command-line flag to disable the warning messages.
+ I have done this in a general way, using regexp, so that we
+ can add warnings about any type of disk that we wish...
+
+smartmontools-5.1-7
+
+ [BA] smartd: Created a subdirectory examplescripts/ of source
+ directory that contains executable scripts for the -M exec PATH
+ Directive of smartd.
+
+smartmontools-5.1-5
+
+ [BA] smartd: DEVICESCAN in /etc/smartd.conf
+ can now be followed by all the same Directives as a regular
+ device name like /dev/hda takes. This allows one to use
+ (for example):
+ DEVICESCAN -m root@example.com
+ in the /etc/smartd.conf file.
+
+ [BA] smartd: Added -c (--checkonce) command-line option. This checks
+ all devices once, then exits. The exit status can be
+ used to learn if devices were detected, and if smartd is
+ functioning correctly. This is primarily for Distribution
+ scripters.
+
+ [BA] smartd: Implemented -M exec Directive for
+ smartd.conf. This makes it possible to run an
+ arbitrary script or mailing program with the
+ -m option.
+
+ [PW] smartd: Modified -M Directive so that it can be given
+ multiple times. Added -M exec Directive.
+
+smartmontools-5.1-4
+
+ [BA] Fixed bug in smartctl pointed out by Pierre Gentile.
+ -d scsi didn't work because tryata and tryscsi were
+ reversed -- now works on /devfs SCSI devices.
+
+ [BA] Fixed bug in smartctl pointed out by Gregory Goddard
+ <ggoddard@ufl.edu>. Manual says that bit 6 of return
+ value turned on if errors found in smart error log. But
+ this wasn't implemented.
+
+smartmontools-5.1-3
+
+ [BA] Modified printing format for 9,minutes to read
+ Xh+Ym not X h + Y m, so that fields are fixed width.
+
+ [BA] Added Attribute 240 "head flying hours"
+
+smartmontools-5.1.1
+
+ [BA] As requested, local time/date now printed by smartctl -i
+
+ [PW] Added "help" argument to -v for smartctl
+
+ [PW] Added -D, --showdirectives option to smartd
+
+ [DG] add '-l selftest' capability for SCSI devices (update smartctl.8)
+
+ [BA] smartd,smartctl: added additional Attribute modification option
+ -v 220,temp and -v 9,temp.
+
+ [PW] Renamed smartd option -X to -d
+
+START OF SMARTMONTOOLS 5.1 series
+
+smartmontools-5.0.50
+
+ [PW] Changed smartd.conf Directives -- see man page
+
+ [BA/DG] Fixed uncommented comment in smartd.conf
+
+ [DG] Correct 'Recommended start stop count' for SCSI devices
+
+ [PW] Replaced smartd.conf directive -C with smartd option -i
+
+ [PW] Changed options for smartctl -- see man page.
+
+ [BA] Use strerror() to generate system call error messages.
+
+ [BA] smartd: fflush() all open streams before fork().
+
+ [BA] smartctl, smartd simplified internal handling of checksums
+ for simpler porting and less code.
+
+smartmontools-5.0.49
+
+ [PW] smartd --debugmode changed to --debug
+
+ [BA] smartd/smartctl added attribute 230 Head Amplitude from
+ IBM DPTA-353750.
+
+ [PW] Added list of proposed new options for smartctl to README.
+
+ [PW] smartd: ParseOpts() now uses getopt_long() if HAVE_GETOPT_LONG is
+ defined and uses getopt() otherwise. This is controlled by CPPFLAGS in
+ the Makefile.
+
+ [BA] smartd: Fixed a couple of error messages done with perror()
+ to redirect them as needed.
+
+smartmontools-5.0.48
+
+ [BA] smartctl: The -O option to enable an Immediate off-line test
+ did not print out the correct time that the test would take to
+ complete. This is because the test timer is volatile and not
+ fixed. This has been fixed, and the smartctl.8 man page has been
+ updated to explain how to track the Immediate offline test as it
+ progresses, and to further emphasize the differences between the
+ off-line immediate test and the self-tests.
+
+ [BA] smartd/smartctl: Added new attribute (200) Multi_Zone_Error_Rate
+
+ [BA] smartctl: modified so that arguments could have either a single -
+ as in -ea or multiple ones as in -e -a. Improved warning message for
+ device not opened, and fixed error in redirection of error output of
+ HD identity command.
+
+ [PW] smartd: added support for long options. All short options are still
+ supported; see manpage for available long options.
+
+ [BA] smartctl. When raw Attribute value was 2^31 or larger, did
+ not print correctly.
+
+smartmontools-5.0.46
+
+ [BA] smartd: added smartd.conf Directives -T and -s. The -T Directive
+ enables/disables Automatic Offline Testing. The -s Directive
+ enables/disables Attribute Autosave. Documentation and
+ example configuration file updated to agree.
+
+ [BA] smartd: user can make smartd check the disks at any time
+ (ie, interrupt sleep) by sending signal SIGUSR1 to smartd. This
+ can be done for example with:
+ kill -USR1 <pid>
+ where <pid> is the process ID number of smartd.
+
+ [EB] scsi: don't trust the data we receive from the drive too
+ much. It very well might have errors (like zero response length).
+ Seen on Megaraid logical drive, and verified in the driver source.
+
+ [BA] smartd: added Directive -m for sending test email and
+ for modifying email reminder behavior. Updated manual, and sample
+ configuration file to illustrate & explain this.
+
+ [BA] smartd: increased size of a continued smartd.conf line to
+ 1023 characters.
+
+ [BA] Simplified Directive parsers and improved warning/error
+ messages.
+
+smartmontools-5.0.45
+
+ [EB] Fixed bug in smartd where testunitready logic inverted
+ prevented functioning on scsi devices.
+ The bug in question only affects smartd users with scsi devices.
+ To see if your version of smartd has the testunitready() bug, do
+ smartd -V
+ If the version of the module smartd.c in a line like:
+ Module: smartd.c revision: 1.66 date: 2002/11/17
+ has a revision greater than or equal to 1.30, and less than or equal to
+ 1.64, then your version of the code has this problem.
+ This problem affected releases starting with RELEASE_5_0_16 up to and
+ including RELEASE_5_0_43.
+
+ [BA] Added testunitnotready to smartctl for symmetry with smartd.
+
+ [SB] added Czech descriptions to .spec file
+ [SB] corrected comment in smartd.conf example
+
+ [BA] Changed way that entries in the ATA error log are printed,
+ to make it clearer which is the most recent error and
+ which is the oldest one.
+
+ NOTE: All changes made prior to this point were done by Bruce Allen
+ [BA] although several of them had been suggested by earlier postings
+ by Stanislav Brabec [SB].
+
+smartmontools-5.0.43
+
+ Changed Temperature_Centigrade to Temperature_Celsius.
+ The term "Centigrade" ceased to exist in 1948. (c.f
+ http://www.bartleby.com/64/C004/016.html).
+
+smartmontools-5.0.42
+
+ Modified SCSI device check to also send warning emails if
+ requested in directives file.
+
+ Added a new smartd configuration file Directive: -M ADDRESS.
+ This sends a single warning email to ADDRESS for failures or
+ errors detected with the -c, -L, -l, or -f Directives.
+
+smartmontools-5.0.38
+
+ Modified perror() statements in atacmds.c so that printout for SMART
+ commands errors is properly suppressed or queued depending upon users
+ choices for error reporting modes.
+
+ Added Italian descriptions to smartmontools.spec file.
+
+ Started impementing send-mail-on-error for smartd; not yet enabled.
+
+ Added -P (Permissive) Directive to smartd.conf file to allow SMART
+ monitoring of pre-ATA-3 Rev 4 disks that have SMART but do not have
+ a SMART capability bit.
+
+ Removed charset encodings from smartmontools.spec file for non-English
+ fields.
+
+smartmontools-5.0.32
+
+ Added manual page smartd.conf.5 for configuration file.
+
+ smartctl: Missing ANSI prototype in failuretest(); fixed.
+
+ smartctl: Checksum warnings now printed on stdout, or are silent,
+ depending upon -q and -Q settings.
+
+smartmontools-5.0.31
+
+ Changed Makefile so that the -V option does not reflect file state
+ before commit!
+
+ smartctl: added new options -W, -U, and -P to control if and how the
+ smartctl exits if an error is detected in either a SMART data
+ structure checksum, or a SMART command returns an error.
+
+ modified manual page to break options into slightly more logical
+ categories.
+
+ reformatted 'usage' message order to agree with man page ordering
+
+ modified .spec file so that locale information now contains
+ character set definition. Changed pt_BR to pt since we do not use any
+ aspect other than language. See man setlocale.
+
+smartmontools-5.0.30
+ smartctl: added new options -n and -N to force device to be ATA or SCSI
+ smartctl: no longer dies silently if device path does not start/dev/X
+ smartctl: now handles arbitrary device paths
+
+smartmontools-5.0.29
+ Modified .spec file and Makefile to make them more compliant with
+ the "right" way of doing things.
+
+smartmontools-5.0.26
+ Fixed typesetting error in man page smartd.8
+
+ Removed redundant variable (harmless) from smartd.c
+
+smartmontools-5.0.25
+
+ Added a new directive for the configuration file. If the word
+ DEVICESCAN appears before any non-commented material in the
+ configuration file, then the confi file will be ignored and the
+ devices wil be scanned.
+
+smartmontools-5.0.24
+
+ Note: it has now been confirmed that the code modifications between
+ 5.0.23 and 5.0.24 have eliminated the GCC 3.2 problems. Note that
+ there is a GCC bug howerver, see #8404 at
+ http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=query
+ http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8404
+
+ Added new Directive for Configuration file:
+ -C <N> This sets the time in between disk checks to be <N>
+ seconds apart. Note that although you can give
+ this Directive multiple times on different lines of
+ the configuration file, only the final value that
+ is given has an effect, and applies to all the
+ disks. The default value of <N> is 1800 sec, and
+ the minimum allowed value is ten seconds.
+
+ Problem wasn't the print format. F.L.W. Meunier <0@pervalidus.net>
+ sent me a gcc 3.2 build and I ran it under a debugger. The
+ problem seems to be with passing the very large (2x512+4) byte
+ data structures as arguments. I never liked this anyway; it was
+ inherited from smartsuite. So I've changed all the heavyweight
+ functions (ATA ones, anyone) to just passing pointers, not hideous
+ kB size structures on the stack. Hopefully this will now build OK
+ under gcc 3.2 with any sensible compilation options.
+
+smartmontools-5.0.23
+
+ Because of reported problems with GCC 3.2 compile, I have gone
+ thorough the code and explicitly changed all print format
+ parameters to correspond EXACTLY to int unless they have to be
+ promoted to long longs. To quote from the glibc bible: [From
+ GLIBC Manual: Since the prototype doesn't specify types for
+ optional arguments, in a call to a variadic function the default
+ argument promotions are performed on the optional argument
+ values. This means the objects of type char or short int (whether
+ signed or not) are promoted to either int or unsigned int, as
+ appropriate.]
+
+smartmontools-5.0.22
+
+ smartd, smartctl now warn if they find an attribute whose ID
+ number does not match between Data and Threshold structures.
+
+ Fixed nasty bug which led to wrong number of arguments for a
+ varargs statement, with attendent stack corruption. Sheesh!
+ Have added script to CVS attic to help find such nasties in the
+ future.
+
+smartmontools-5.0.21
+
+ Eliminated some global variables out of header files and other
+ minor cleanup of smartd.
+
+smartmontools-5.0.20
+
+ Did some revision of the man page for smartd and made the usage
+ messages for Directives 100% consistent.
+
+smartmontools-5.0-19
+
+ smartd: prints warning message when it gets SIGHUP, saying that it
+ is NOT re-reading the config file.
+
+ smartctl: updated man page to say self-test commands -O,x,X,s,S,A
+ appear to be supported in the code. [I can't test these, can anyone
+ report?]
+
+smartmontools-5.0-18
+
+ smartctl: smartctl would previously print the LBA of a self-test
+ if it completed, and the LBA was not 0 or 0xff...f However
+ according to the specs this is not correct. According to the
+ specs, if the self-test completed without error then LBA is
+ undefined. This version fixes that. LBA value only printed if
+ self-test encountered an error.
+
+smartmontools-5.0-17
+
+ smartd has changed significantly. This is the first CVS checkin of
+ code that extends the options available for smartd. The following
+ options can be placed into the /etc/smartd.conf file, and control the
+ behavior of smartd.
+ Configuration file Directives (following device name):
+ -A Device is an ATA device
+ -S Device is a SCSI device
+ -c Monitor SMART Health Status
+ -l Monitor SMART Error Log for changes
+ -L Monitor SMART Self-Test Log for new errors
+ -f Monitor for failure of any 'Usage' Attributes
+ -p Report changes in 'Prefailure' Attributes
+ -u Report changes in 'Usage' Attributes
+ -t Equivalent to -p and -u Directives
+ -a Equivalent to -c -l -L -f -t Directives
+ -i ID Ignore Attribute ID for -f Directive
+ -I ID Ignore Attribute ID for -p, -u or -t Directive
+ # Comment: text after a hash sign is ignored
+ \ Line continuation character
+
+ cleaned up functions used for printing CVS IDs. Now use string
+ library, as it should be.
+
+ modified length of device name string in smartd internal structure
+ to accomodate max length device name strings
+
+ removed un-implemented (-e = Email notification) option from
+ command line arg list. We'll put it back on when implemeneted.
+
+ smartd now logs serious (fatal) conditions in its operation at
+ loglevel LOG_CRIT rather than LOG_INFO before exiting with error.
+
+ smartd used to open a file descriptor for each SMART enabled
+ device, and then keep it open the entire time smartd was running.
+ This meant that some commands, like IOREADBLKPART did not work,
+ since the fd to the device was open. smartd now opens the device
+ when it needs to read values, then closes it. Also, if one time
+ around it can't open the device, it simply prints a warning
+ message but does not give up. Have eliminated the .fd field from
+ data structures -- no longer gets used.
+
+ smartd now opens SCSI devices as well using O_RDONLY rather than
+ O_RDWR. If someone can no longer monitor a SCSI device that used
+ to be readable, this may well be the reason why.
+
+ smartd never checked if the number of ata or scsi devices detected
+ was greater than the max number it could monitor. Now it does.
+
+smartmontools-5.0-16
+
+ smartd on startup now looks in the configuration file /etc/smartd.conf for
+ a list of devices which to include in its monitoring list. See man page
+ (man smartd) for syntax.
+
+ smartd: close file descriptors of SCSI device if not SMART capable
+ Closes ALL file descriptors after forking to daemon.
+
+ added new temperature attribute (231, temperature)
+
+ smartd: now open ATA disks using O_RDONLY
+
+smartmontools-5.0-11
+
+ smartd now prints the name of a failed or changed attribute
+ into logfile, not just ID number
+
+ Changed name of -p (print version) option to -V
+
+ Minor change in philosophy: if a SMART command fails or the device
+ appears incapable of a SMART command that the user has asked for,
+ complain by printing an error message, but go ahead and try
+ anyway. Since unimplemented SMART commands should just return an
+ error but not cause disk problems, this should't cause any
+ difficulty.
+
+ Added two new flags: q and Q. q is quiet mode - only print: For
+ the -l option, errors recorded in the SMART error log; For the -L
+ option, errors recorded in the device self-test log; For the -c
+ SMART "disk failing" status or device attributes (pre-failure or
+ usage) which failed either now or in the past; For the -v option
+ device attributes (pre-failure or usage) which failed either now
+ or in the past. Q is Very Quiet mode: Print no ouput. The only
+ way to learn about what was found is to use the exit status of
+ smartctl.
+
+ smartctl now returns sensible values (bitmask). See smartctl.h
+ for the values, and the man page for documentation.
+
+ The SMART status check now uses the correct ATA call. If failure
+ is detected we search through attributes to list the failed ones.
+ If the SMART status check shows GOOD, we then look to see if their
+ are any usage attributes or prefail attributes have failed at any
+ time. If so we print them.
+
+ Modified function that prints vendor attributes to say if the
+ attribute has currently failed or has ever failed.
+
+ -p option now prints out license info and CVS strings for all
+ modules in the code, nicely formatted.
+
+ Previous versions of this code (and Smartsuite) only generate
+ SMART failure errors if the value of an attribute is below the
+ threshold and the prefailure bit is set. However the ATA Spec
+ (ATA4 <=Rev 4) says that it is a SMART failure if the value of an
+ attribute is LESS THAN OR EQUAL to the threshold and the
+ prefailure bit is set. This is now fixed in both smartctl and
+ smartd. Note that this is a troubled subject -- the original
+ SFF 8035i specification defining SMART was inconsistent about
+ this. One section says that Attribute==Threshold is pass,
+ and another section says it is fail. However the ATA specs are
+ consistent and say Attribute==Threshold is a fail.
+
+ smartd did not print the correct value of any failing SMART attribute. It
+ printed the index in the attribute table, not the attribute
+ ID. This is fixed.
+
+ when starting self-tests in captive mode ioctl returns EIO because
+ the drive has been busied out. Detect this and don't return an eror
+ in this case. Check this this is correct (or how to fix it?)
+
+ fixed possible error in how to determine ATA standard support
+ for devices with no ATA minor revision number.
+
+ device opened only in read-only not read-write mode. Don't need R/W
+ access to get smart data. Check this with Andre.
+
+ smartctl now handles all possible choices of "multiple options"
+ gracefully. It goes through the following phases of operation,
+ in order: INFORMATION, ENABLE/DISABLE, DISPLAY DATA, RUN/ABORT TESTS.
+ Documentation has bee updated to explain the different phases of
+ operation. Control flow through ataPrintMain()
+ simplified.
+
+ If reading device identity information fails, try seeing if the info
+ can be accessed using a "DEVICE PACKET" command. This way we can
+ at least get device info.
+
+ Modified Makefile to automatically tag CVS archive on issuance of
+ a release
+
+ Modified drive detection so minor device ID code showing ATA-3 rev
+ 0 (no SMART) is known to not be SMART capable.
+
+ Now verify the checksum of the device ID data structure, and of the
+ attributes threshold structure. Before neither of these
+ structures had their checksums verified.
+
+ New behavior vis-a-vis checksums. If they are wrong, we log
+ warning messages to stdout, stderr, and syslog, but carry on
+ anyway. All functions now call a checksumwarning routine if the
+ checksum doesn't vanish as it should.
+
+ Changed Read Hard Disk Identity function to get fresh info from
+ the disk on each call rather than to use the values that were read
+ upon boot-up into the BIOS. This is the biggest change in this
+ release. The ioctl(device, HDIO_GET_IDENTITY, buf ) call should
+ be avoided in such code. Note that if people get garbled strings
+ for the model, serial no and firmware versions of their drives,
+ then blame goes here (the BIOS does the byte swapping for you,
+ apparently!)
+
+ Function ataSmartSupport now looks at correct bits in drive
+ identity structure to verify first that these bits are valid,
+ before using them.
+
+ Function ataIsSmartEnabled() written which uses the Drive ID state
+ information to tell if SMART is enabled or not. We'll carry this
+ along for the moment without using it.
+
+ Function ataDoesSmartWork() guaranteed to work if the device
+ supports SMART.
+
+ Replace some numbers by #define MACROS
+
+ Wrote Function TestTime to return test time associated with each
+ different type of test.
+
+ Thinking of the future, have added a new function called
+ ataSmartStatus2(). Eventually when I understand how to use the
+ TASKFILE API and am sure that this works correctly, it will
+ replace ataSmartStatus(). This queries the drive directly to
+ see if the SMART status is OK, rather than comparing thresholds to
+ attribute values ourselves. But I need to get some drives that fail
+ their SMART status to check it.
+
+
+smartmontools-5.0-10
+ Removed extraneous space before printing in some error messages
+ Fixed additional typos in documentation
+ Fixed some character buffers that were too short for their contents.
+
+smartmontools-5.0-9
+
+ Put project home path into all source files near the top
+ Corrected typos in the documentation
+ Modified Makefile so that Mandrake Cooker won't increment version number
+ (unless they happen to be working on my machine, which I doubt!)
+
+smartmontools-5.0-8:
+
+ For IBM disks whose raw temp data includes three temps. print all
+ three
+
+ print timestamps for error log to msec precision
+
+ added -m option for Hitachi disks that store power on life in
+ minutes
+
+ added -L option for printing self-test error logs
+
+ in -l option, now print power on lifetime, so that one can see
+ when the error took place
+
+ updated SMART structure definitions to ATA-5 spec
+
+ added -p option
+
+ added -f and -F options to enable/disable autosave threshold
+ parameters
+
+ changed argv parsing to use getops -- elminate buffer overflow
+ vulnerability
+
+ expanded and corrected documentation
+
+ fixed problem with smartd. It did not actually call
+ ataSmartEnable()! Since the argument was left out, the test
+ always suceeded because it evaluated to a pointer to the function.
+
+ smartd: closed open file descriptors if device does not support
+ smart. Note: this still needs to be fixed for SCSI devices
+
+
+smartmontools-5.0-0 STARTED with smartsuite-2.1-2
--- /dev/null
+ 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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ 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.
--- /dev/null
+Smartmontools installation instructions
+=======================================
+
+$Id: INSTALL,v 1.62 2005/10/22 17:11:39 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] Guidelines for OS/2, eComStation
+[12] Guidelines for OpenBSD
+[13] Comments
+[14] Detailed description of ./configure options
+
+[1] System requirements
+=======================
+
+ A) Linux
+
+ Any Linux distribution will support smartmontools if it has a
+ kernel version greater than or equal to 2.2.14. So any recent
+ Linux distribution should support smartmontools.
+
+ There are two parts of smartmontools that may require a patched or
+ nonstandard kernel:
+
+ (1) To get the ATA RETURN SMART STATUS command, the kernel needs
+ to support the HDIO_DRIVE_TASK ioctl().
+
+ (2) To run Selective Self-tests, the kernel needs to support the
+ HDIO_DRIVE_TASKFILE ioctl().
+
+ If your kernel does not support one or both of these ioctls, then
+ smartmontools will "mostly" work. The things that don't work will
+ give you harmless warning messages.
+
+ Although "not officially supported" by the developers, smartmontools
+ has also been successfully build and run on a legacy Linux system
+ with kernel 2.0.33 and libc.so.5. On such systems, the restrictions
+ above apply.
+
+ 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/OpenBSD
+
+ The code was tested on a 1.6ZG (i.e., 1.6-current) system. It should
+ also function under 1.6.1 and later releases (unverified). Currently
+ it doesn't support ATA devices on 3ware RAID controllers.
+
+ E) Cygwin
+
+ The code was tested on Cygwin 1.5.7, 1.5.11 and 1.5.18. It should also
+ work on other recent releases.
+
+ Release 1.5.15 or later is recommended for Cygwin smartd. Older versions
+ do not provide syslogd support.
+
+ 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(SP5,SP6), 2000(SP4) and
+ XP(no SP,SP1a,SP2). 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).
+
+ SMARTVSD.VXD relies on the standard IDE port driver ESDI_506.PDR.
+ If the system uses a vendor specific driver, access of SMART data
+ is not possible on 9x/ME. This is the case if e.g. the optional
+ "IDE miniport driver" is installed on a system with VIA chipset.
+
+ 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 by the SMART IOCTL of NT4/2000/XP. Undocumented
+ and possibly buggy system calls are used for this purpose,
+ see WARNINGS file for details.
+
+ SCSI devices are supported on all versions of Windows. An installed
+ ASPI interface (WNASPI32.DLL) is required to access SCSI devices.
+ The code was tested with Adaptec Windows ASPI drivers 4.71.2.
+ (http://www.adaptec.com/worldwide/support/drivers_by_product.jsp?cat=/Product/ASPI-4.70)
+
+ 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 captive mode
+ - aborting tests
+ - switching automatic offline testing on or off
+ - support for SCSI
+ - checking the power mode [-n Directive of smartd] (this is not
+ completely impossible, but not by using a documented API)
+
+ * 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 in the next major version of Mac OS.
+
+ 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.
+
+ H) OS/2, eComStation
+
+ The code was tested on eComStation 1.1, but it should work on all versions
+ of OS/2.
+ Innotek LibC 0.5 runtime is required.
+ Currently only ATA disks are supported, SCSI support will be added.
+
+
+[2] Installing from 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/OpenBSD
+=================================
+ ./configure --prefix=/usr/pkg \
+ --with-docdir=/usr/pkg/share/doc/smartmontools
+
+ On OpenBSD, it is important that you use GNU make (gmake from
+ /usr/ports/devel/gmake) to build smartmontools, as the BSD make doesn't
+ know how to make the manpages.
+
+[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] Guidelines for OS/2, eComStation
+=====================================
+
+To compile the OS/2 code, please run
+
+ ./os_os2/configure.os2
+ make
+ make install
+
+[12] Guidelines for OpenBSD
+==========================
+ To match the way it will installed when it becomes available as a PORT, use
+ the following:
+
+ ./configure --prefix=/usr/local \
+ --sysconfdir=/etc
+ --with-initscriptdir=/usr/local/share/doc/smartmontools-VERSION \
+ --with-docdir=/usr/local/share/doc/smartmontools-VERSION \
+ --enable-sample
+
+ It is important that you use GNU make (gmake from /usr/ports/devel/gmake)
+ to build smartmontools, as the default OpenBSD make doesn't know how to build
+ the man pages.
+
+ NOTE1: --with-initscriptdir installs a SystemV startup script. It really
+ should be --without-initscriptdir, but the Makefile code is incorrect and
+ trys to install the initscript (smartd) to /no. So, an interim fix it to
+ set the initscript dir to the doc dir.
+
+ NOTE2: --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
+
+[13] 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
+
+
+[14] Detailed description of arguments to configure command
+===========================================================
+
+When you type:
+./configure [options]
+there are six particularly important variables that affect where the
+smartmontools software is installed. The variables are listed here,
+with their default values in square brackets, and the quantities that
+they affect described following that. This is a very wide table: please read
+it in a wide window.
+
+OPTIONS DEFAULT AFFECTS
+------- ------- -------
+--prefix /usr/local Please see below
+--sbindir ${prefix}/sbin Directory for smartd/smartctl executables;
+ Contents of smartd/smartctl man pages
+--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
--- /dev/null
+## Process this file with automake to produce Makefile.in
+#
+# $Id: Makefile.am,v 1.74 2005/11/29 18:22:51 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_openbsd.c \
+ os_openbsd.h \
+ os_solaris.c \
+ os_solaris.h \
+ os_solaris_ata.s \
+ os_win32.c \
+ os_generic.c \
+ os_generic.h
+
+
+if OS_WIN32_MINGW
+
+smartd_SOURCES += \
+ posix/regex.h \
+ posix/regex.c \
+ 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
+
+# Included by regex.c:
+EXTRA_smartd_SOURCES += \
+ posix/regcomp.c \
+ posix/regexec.c \
+ posix/regex_internal.c \
+ posix/regex_internal.h
+
+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_openbsd.c \
+ os_openbsd.h \
+ os_solaris.c \
+ os_solaris.h \
+ os_win32.c \
+ os_generic.c \
+ os_generic.h
+
+if OS_WIN32_MINGW
+
+smartctl_SOURCES += \
+ posix/regex.h \
+ posix/regex.c \
+ os_win32/syslog.h
+
+# Included by regex.c:
+EXTRA_smartctl_SOURCES += \
+ posix/regcomp.c \
+ posix/regexec.c \
+ posix/regex_internal.c \
+ posix/regex_internal.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 ${srcdir}/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 \
+ os_darwin/SMART.in \
+ os_darwin/StartupParameters.plist \
+ os_darwin/English_Localizable.strings \
+ $(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
+
+if SMARTD_SUFFIX
+CLEANFILES += smartd.conf$(smartd_suffix)
+endif
+
+
+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
+
+smartd.initd: $(srcdir)/smartd.initd.in Makefile
+ sed "s|/usr/local/sbin/|$(sbindir)/|g" $(srcdir)/smartd.initd.in > $@
+
+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/local/share/man/|$(mandir)/|g" | \
+ sed "s|/usr/local/sbin/|$(sbindir)/|g" | \
+ sed "s|/usr/local/etc/rc\\.d/init.d/|$(initddir)/|g" | \
+ sed "s|/usr/local/share/doc/smartmontools-5.1/|$(docsdir)/|g" | \
+ sed "s|/usr/local/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'
+
+# Fix links in man2html output
+FIXHTML = sed 's,<A HREF="http://[-a-z/]*/man2html?\([1-8]\)+\(smart[cd][.a-z]*\)">,<A HREF="\2.\1.html">,g' \
+ | sed 's,<A HREF="http://[-a-z/]*/man2html">,<A HREF=".">,g' \
+ | sed 's,<A HREF="http://[-a-z/]*/man2html?[^"]*">\([^<]*\)</A>,\1,g' \
+ | sed 's,<A HREF="mailto:[^s][^m][^a][^"]*">\([^<]*\)</A>,\1,g'
+
+# Convert man pages into .html and .txt
+
+htmlman: smartctl.8.html smartd.8.html smartd.conf.5.html
+
+txtman: smartctl.8.txt smartd.8.txt smartd.conf.5.txt
+
+%.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 -s $@
+ touch -r $< $@
+
+$(docdir_win32)/%: %
+ $(UNIX2DOS) < $< > $@
+ touch -r $< $@
+
+$(docdir_win32)/%.txt: $(srcdir)/%
+ $(UNIX2DOS) < $< > $@
+ touch -r $< $@
+
+$(docdir_win32)/%.conf: $(srcdir)/%.conf
+ $(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_\(ATTR_PACKED\|INTTYPES_H\|STDINT_H\|STRTOULL\|U*INT64_T\|UNISTD_H\) 1$$,/* #undef HAVE_\1 */,' | \
+ sed 's,i.86-pc-mingw32,i686-pc-win32vc6,' > $@
+
+endif
+
+SUBDIRS= . examplescripts
--- /dev/null
+# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# $Id: Makefile.am,v 1.74 2005/11/29 18:22:51 chrfranke Exp $
+#
+
+
+SOURCES = $(smartctl_SOURCES) $(EXTRA_smartctl_SOURCES) $(smartd_SOURCES) $(EXTRA_smartd_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = smartd$(EXEEXT) smartctl$(EXEEXT)
+@OS_WIN32_MINGW_TRUE@am__append_1 = \
+@OS_WIN32_MINGW_TRUE@ posix/regex.h \
+@OS_WIN32_MINGW_TRUE@ posix/regex.c \
+@OS_WIN32_MINGW_TRUE@ os_win32/daemon_win32.h \
+@OS_WIN32_MINGW_TRUE@ os_win32/daemon_win32.c \
+@OS_WIN32_MINGW_TRUE@ os_win32/hostname_win32.h \
+@OS_WIN32_MINGW_TRUE@ os_win32/hostname_win32.c \
+@OS_WIN32_MINGW_TRUE@ os_win32/syslog.h \
+@OS_WIN32_MINGW_TRUE@ os_win32/syslog_win32.c
+
+
+# Included by regex.c:
+@OS_WIN32_MINGW_TRUE@am__append_2 = \
+@OS_WIN32_MINGW_TRUE@ posix/regcomp.c \
+@OS_WIN32_MINGW_TRUE@ posix/regexec.c \
+@OS_WIN32_MINGW_TRUE@ posix/regex_internal.c \
+@OS_WIN32_MINGW_TRUE@ posix/regex_internal.h
+
+@OS_WIN32_MINGW_TRUE@am__append_3 = \
+@OS_WIN32_MINGW_TRUE@ posix/regex.h \
+@OS_WIN32_MINGW_TRUE@ posix/regex.c \
+@OS_WIN32_MINGW_TRUE@ os_win32/syslog.h
+
+
+# Included by regex.c:
+@OS_WIN32_MINGW_TRUE@am__append_4 = \
+@OS_WIN32_MINGW_TRUE@ posix/regcomp.c \
+@OS_WIN32_MINGW_TRUE@ posix/regexec.c \
+@OS_WIN32_MINGW_TRUE@ posix/regex_internal.c \
+@OS_WIN32_MINGW_TRUE@ posix/regex_internal.h
+
+@SMARTD_SUFFIX_TRUE@am__append_5 = smartd.conf$(smartd_suffix)
+@OS_WIN32_MINGW_TRUE@am__append_6 = $(FILES_WIN32) $(exedir_win32)/syslogevt.exe distdir.mkdir syslogevt.check
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/configure AUTHORS COPYING INSTALL NEWS TODO \
+ config.guess config.sub depcomp install-sh missing
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(docsdir)" \
+ "$(DESTDIR)$(initddir)" "$(DESTDIR)$(sysconfdir)"
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(sbin_PROGRAMS)
+am__smartctl_SOURCES_DIST = 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 \
+ posix/regex.h posix/regex.c os_win32/syslog.h
+@OS_WIN32_MINGW_TRUE@am__objects_1 = regex.$(OBJEXT)
+am_smartctl_OBJECTS = smartctl.$(OBJEXT) atacmdnames.$(OBJEXT) \
+ atacmds.$(OBJEXT) ataprint.$(OBJEXT) knowndrives.$(OBJEXT) \
+ scsicmds.$(OBJEXT) scsiprint.$(OBJEXT) utility.$(OBJEXT) \
+ $(am__objects_1)
+am__EXTRA_smartctl_SOURCES_DIST = os_linux.c os_linux.h os_freebsd.c \
+ os_freebsd.h os_netbsd.c os_netbsd.h os_openbsd.c os_openbsd.h \
+ os_solaris.c os_solaris.h os_win32.c os_generic.c os_generic.h \
+ posix/regcomp.c posix/regexec.c posix/regex_internal.c \
+ posix/regex_internal.h
+smartctl_OBJECTS = $(am_smartctl_OBJECTS)
+am__smartd_SOURCES_DIST = 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 \
+ posix/regex.h posix/regex.c 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
+@OS_WIN32_MINGW_TRUE@am__objects_3 = regex.$(OBJEXT) \
+@OS_WIN32_MINGW_TRUE@ daemon_win32.$(OBJEXT) \
+@OS_WIN32_MINGW_TRUE@ hostname_win32.$(OBJEXT) \
+@OS_WIN32_MINGW_TRUE@ syslog_win32.$(OBJEXT)
+am_smartd_OBJECTS = smartd.$(OBJEXT) atacmdnames.$(OBJEXT) \
+ atacmds.$(OBJEXT) ataprint.$(OBJEXT) knowndrives.$(OBJEXT) \
+ scsicmds.$(OBJEXT) scsiprint.$(OBJEXT) utility.$(OBJEXT) \
+ $(am__objects_3)
+am__EXTRA_smartd_SOURCES_DIST = 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_openbsd.c os_openbsd.h os_solaris.c os_solaris.h \
+ os_solaris_ata.s os_win32.c os_generic.c os_generic.h \
+ posix/regcomp.c posix/regexec.c posix/regex_internal.c \
+ posix/regex_internal.h
+smartd_OBJECTS = $(am_smartd_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CCASCOMPILE = $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS)
+SOURCES = $(smartctl_SOURCES) $(EXTRA_smartctl_SOURCES) \
+ $(smartd_SOURCES) $(EXTRA_smartd_SOURCES)
+DIST_SOURCES = $(am__smartctl_SOURCES_DIST) \
+ $(am__EXTRA_smartctl_SOURCES_DIST) $(am__smartd_SOURCES_DIST) \
+ $(am__EXTRA_smartd_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man_MANS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+docsDATA_INSTALL = $(INSTALL_DATA)
+initdDATA_INSTALL = $(INSTALL_DATA)
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(docs_DATA) $(initd_DATA) $(sysconf_DATA)
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+ASFLAGS = @ASFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+OS_DARWIN_FALSE = @OS_DARWIN_FALSE@
+OS_DARWIN_TRUE = @OS_DARWIN_TRUE@
+OS_SOLARIS_FALSE = @OS_SOLARIS_FALSE@
+OS_SOLARIS_TRUE = @OS_SOLARIS_TRUE@
+OS_WIN32_MINGW_FALSE = @OS_WIN32_MINGW_FALSE@
+OS_WIN32_MINGW_TRUE = @OS_WIN32_MINGW_TRUE@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SMARTD_SUFFIX_FALSE = @SMARTD_SUFFIX_FALSE@
+SMARTD_SUFFIX_TRUE = @SMARTD_SUFFIX_TRUE@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+docdir = @docdir@
+exampledir = @exampledir@
+exec_prefix = @exec_prefix@
+gcc_have_attr_packed = @gcc_have_attr_packed@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+initddir = @initddir@
+install_sh = @install_sh@
+libc_have_working_snprintf = @libc_have_working_snprintf@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+os_deps = @os_deps@
+os_libs = @os_libs@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+releaseversion = @releaseversion@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+smartd_suffix = @smartd_suffix@
+smartmontools_release_date = @smartmontools_release_date@
+smartmontools_release_time = @smartmontools_release_time@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+AM_CPPFLAGS = -DSMARTMONTOOLS_SYSCONFDIR=\"$(sysconfdir)\"
+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 $(am__append_1)
+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_openbsd.c \
+ os_openbsd.h os_solaris.c os_solaris.h os_solaris_ata.s \
+ os_win32.c os_generic.c os_generic.h $(am__append_2)
+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 $(am__append_3)
+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_openbsd.c os_openbsd.h \
+ os_solaris.c os_solaris.h os_win32.c os_generic.c os_generic.h \
+ $(am__append_4)
+
+# 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.
+@OS_SOLARIS_TRUE@extra_MANS = smartd.conf.4 \
+@OS_SOLARIS_TRUE@ smartctl.1m \
+@OS_SOLARIS_TRUE@ smartd.1m
+
+# For systems that adopts traditional manner
+@OS_SOLARIS_FALSE@man_MANS = smartd.conf.5 \
+@OS_SOLARIS_FALSE@ smartctl.8 \
+@OS_SOLARIS_FALSE@ smartd.8
+
+docsdir = $(docdir)
+docs_DATA = AUTHORS \
+ CHANGELOG \
+ COPYING \
+ INSTALL \
+ NEWS \
+ README \
+ TODO \
+ WARNINGS \
+ smartd.conf
+
+sysconf_DATA = smartd.conf$(smartd_suffix)
+EXTRA_DIST = smartmontools.spec \
+ smartd.initd.in \
+ smartd.8.in \
+ smartctl.8.in \
+ smartd.conf.5.in \
+ smartd.conf \
+ autogen.sh \
+ os_darwin/SMART.in \
+ os_darwin/StartupParameters.plist \
+ os_darwin/English_Localizable.strings \
+ $(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 $(am__append_5) \
+ $(am__append_6)
+@OS_DARWIN_FALSE@initd_DATA = smartd.initd
+@OS_DARWIN_TRUE@initd_DATA = SMART \
+@OS_DARWIN_TRUE@ os_darwin/StartupParameters.plist \
+@OS_DARWIN_TRUE@ os_darwin/English_Localizable.strings
+
+@OS_DARWIN_FALSE@initd_install_name = smartd$(smartd_suffix)
+@OS_DARWIN_TRUE@initd_install_name = SMART
+@OS_DARWIN_FALSE@initd_DATA_install = install-initdDATA-generic
+@OS_DARWIN_TRUE@initd_DATA_install = install-initdDATA-darwin
+
+# Commands to convert man pages into .html and .txt
+# TODO: configure
+MAN2HTML = man2html
+#MAN2HTML = groff -man -Thtml
+MAN2TXT = groff -man -Tascii -P'-bcou'
+
+# Fix links in man2html output
+FIXHTML = sed 's,<A HREF="http://[-a-z/]*/man2html?\([1-8]\)+\(smart[cd][.a-z]*\)">,<A HREF="\2.\1.html">,g' \
+ | sed 's,<A HREF="http://[-a-z/]*/man2html">,<A HREF=".">,g' \
+ | sed 's,<A HREF="http://[-a-z/]*/man2html?[^"]*">\([^<]*\)</A>,\1,g' \
+ | sed 's,<A HREF="mailto:[^s][^m][^a][^"]*">\([^<]*\)</A>,\1,g'
+
+
+# Definitions for Windows distribution
+@OS_WIN32_MINGW_TRUE@distdir_win32 = $(PACKAGE)-$(VERSION).win32
+@OS_WIN32_MINGW_TRUE@distzip_win32 = $(PACKAGE)-$(VERSION).win32.zip
+@OS_WIN32_MINGW_TRUE@exedir_win32 = $(distdir_win32)/bin
+@OS_WIN32_MINGW_TRUE@docdir_win32 = $(distdir_win32)/doc
+@OS_WIN32_MINGW_TRUE@FILES_WIN32 = $(exedir_win32)/smartctl.exe \
+@OS_WIN32_MINGW_TRUE@ $(exedir_win32)/smartd.exe \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/AUTHORS.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/CHANGELOG.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/COPYING.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/INSTALL.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/NEWS.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/README.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/TODO.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/WARNINGS.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartd.conf \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartctl.8.html \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartctl.8.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartd.8.html \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartd.8.txt \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartd.conf.5.html \
+@OS_WIN32_MINGW_TRUE@ $(docdir_win32)/smartd.conf.5.txt
+
+
+# Textfile converter from cygutils
+@OS_WIN32_MINGW_TRUE@UNIX2DOS = unix2dos -D
+SUBDIRS = . examplescripts
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj .s
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+ cd $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+smartctl$(EXEEXT): $(smartctl_OBJECTS) $(smartctl_DEPENDENCIES)
+ @rm -f smartctl$(EXEEXT)
+ $(LINK) $(smartctl_LDFLAGS) $(smartctl_OBJECTS) $(smartctl_LDADD) $(LIBS)
+smartd$(EXEEXT): $(smartd_OBJECTS) $(smartd_DEPENDENCIES)
+ @rm -f smartd$(EXEEXT)
+ $(LINK) $(smartd_LDFLAGS) $(smartd_OBJECTS) $(smartd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atacmdnames.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atacmds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ataprint.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon_win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostname_win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/knowndrives.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_darwin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_freebsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_generic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_linux.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_netbsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_openbsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_solaris.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regcomp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_internal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regexec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scsicmds.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scsiprint.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smartctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smartd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syslog_win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utility.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+regex.o: posix/regex.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regex.o -MD -MP -MF "$(DEPDIR)/regex.Tpo" -c -o regex.o `test -f 'posix/regex.c' || echo '$(srcdir)/'`posix/regex.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regex.Tpo" "$(DEPDIR)/regex.Po"; else rm -f "$(DEPDIR)/regex.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regex.c' object='regex.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regex.o `test -f 'posix/regex.c' || echo '$(srcdir)/'`posix/regex.c
+
+regex.obj: posix/regex.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regex.obj -MD -MP -MF "$(DEPDIR)/regex.Tpo" -c -o regex.obj `if test -f 'posix/regex.c'; then $(CYGPATH_W) 'posix/regex.c'; else $(CYGPATH_W) '$(srcdir)/posix/regex.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regex.Tpo" "$(DEPDIR)/regex.Po"; else rm -f "$(DEPDIR)/regex.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regex.c' object='regex.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regex.obj `if test -f 'posix/regex.c'; then $(CYGPATH_W) 'posix/regex.c'; else $(CYGPATH_W) '$(srcdir)/posix/regex.c'; fi`
+
+regcomp.o: posix/regcomp.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regcomp.o -MD -MP -MF "$(DEPDIR)/regcomp.Tpo" -c -o regcomp.o `test -f 'posix/regcomp.c' || echo '$(srcdir)/'`posix/regcomp.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regcomp.Tpo" "$(DEPDIR)/regcomp.Po"; else rm -f "$(DEPDIR)/regcomp.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regcomp.c' object='regcomp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regcomp.o `test -f 'posix/regcomp.c' || echo '$(srcdir)/'`posix/regcomp.c
+
+regcomp.obj: posix/regcomp.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regcomp.obj -MD -MP -MF "$(DEPDIR)/regcomp.Tpo" -c -o regcomp.obj `if test -f 'posix/regcomp.c'; then $(CYGPATH_W) 'posix/regcomp.c'; else $(CYGPATH_W) '$(srcdir)/posix/regcomp.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regcomp.Tpo" "$(DEPDIR)/regcomp.Po"; else rm -f "$(DEPDIR)/regcomp.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regcomp.c' object='regcomp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regcomp.obj `if test -f 'posix/regcomp.c'; then $(CYGPATH_W) 'posix/regcomp.c'; else $(CYGPATH_W) '$(srcdir)/posix/regcomp.c'; fi`
+
+regexec.o: posix/regexec.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regexec.o -MD -MP -MF "$(DEPDIR)/regexec.Tpo" -c -o regexec.o `test -f 'posix/regexec.c' || echo '$(srcdir)/'`posix/regexec.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regexec.Tpo" "$(DEPDIR)/regexec.Po"; else rm -f "$(DEPDIR)/regexec.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regexec.c' object='regexec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regexec.o `test -f 'posix/regexec.c' || echo '$(srcdir)/'`posix/regexec.c
+
+regexec.obj: posix/regexec.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regexec.obj -MD -MP -MF "$(DEPDIR)/regexec.Tpo" -c -o regexec.obj `if test -f 'posix/regexec.c'; then $(CYGPATH_W) 'posix/regexec.c'; else $(CYGPATH_W) '$(srcdir)/posix/regexec.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regexec.Tpo" "$(DEPDIR)/regexec.Po"; else rm -f "$(DEPDIR)/regexec.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regexec.c' object='regexec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regexec.obj `if test -f 'posix/regexec.c'; then $(CYGPATH_W) 'posix/regexec.c'; else $(CYGPATH_W) '$(srcdir)/posix/regexec.c'; fi`
+
+regex_internal.o: posix/regex_internal.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regex_internal.o -MD -MP -MF "$(DEPDIR)/regex_internal.Tpo" -c -o regex_internal.o `test -f 'posix/regex_internal.c' || echo '$(srcdir)/'`posix/regex_internal.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regex_internal.Tpo" "$(DEPDIR)/regex_internal.Po"; else rm -f "$(DEPDIR)/regex_internal.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regex_internal.c' object='regex_internal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regex_internal.o `test -f 'posix/regex_internal.c' || echo '$(srcdir)/'`posix/regex_internal.c
+
+regex_internal.obj: posix/regex_internal.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regex_internal.obj -MD -MP -MF "$(DEPDIR)/regex_internal.Tpo" -c -o regex_internal.obj `if test -f 'posix/regex_internal.c'; then $(CYGPATH_W) 'posix/regex_internal.c'; else $(CYGPATH_W) '$(srcdir)/posix/regex_internal.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/regex_internal.Tpo" "$(DEPDIR)/regex_internal.Po"; else rm -f "$(DEPDIR)/regex_internal.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='posix/regex_internal.c' object='regex_internal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regex_internal.obj `if test -f 'posix/regex_internal.c'; then $(CYGPATH_W) 'posix/regex_internal.c'; else $(CYGPATH_W) '$(srcdir)/posix/regex_internal.c'; fi`
+
+daemon_win32.o: os_win32/daemon_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT daemon_win32.o -MD -MP -MF "$(DEPDIR)/daemon_win32.Tpo" -c -o daemon_win32.o `test -f 'os_win32/daemon_win32.c' || echo '$(srcdir)/'`os_win32/daemon_win32.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/daemon_win32.Tpo" "$(DEPDIR)/daemon_win32.Po"; else rm -f "$(DEPDIR)/daemon_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/daemon_win32.c' object='daemon_win32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o daemon_win32.o `test -f 'os_win32/daemon_win32.c' || echo '$(srcdir)/'`os_win32/daemon_win32.c
+
+daemon_win32.obj: os_win32/daemon_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT daemon_win32.obj -MD -MP -MF "$(DEPDIR)/daemon_win32.Tpo" -c -o daemon_win32.obj `if test -f 'os_win32/daemon_win32.c'; then $(CYGPATH_W) 'os_win32/daemon_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/daemon_win32.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/daemon_win32.Tpo" "$(DEPDIR)/daemon_win32.Po"; else rm -f "$(DEPDIR)/daemon_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/daemon_win32.c' object='daemon_win32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o daemon_win32.obj `if test -f 'os_win32/daemon_win32.c'; then $(CYGPATH_W) 'os_win32/daemon_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/daemon_win32.c'; fi`
+
+hostname_win32.o: os_win32/hostname_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hostname_win32.o -MD -MP -MF "$(DEPDIR)/hostname_win32.Tpo" -c -o hostname_win32.o `test -f 'os_win32/hostname_win32.c' || echo '$(srcdir)/'`os_win32/hostname_win32.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hostname_win32.Tpo" "$(DEPDIR)/hostname_win32.Po"; else rm -f "$(DEPDIR)/hostname_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/hostname_win32.c' object='hostname_win32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hostname_win32.o `test -f 'os_win32/hostname_win32.c' || echo '$(srcdir)/'`os_win32/hostname_win32.c
+
+hostname_win32.obj: os_win32/hostname_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hostname_win32.obj -MD -MP -MF "$(DEPDIR)/hostname_win32.Tpo" -c -o hostname_win32.obj `if test -f 'os_win32/hostname_win32.c'; then $(CYGPATH_W) 'os_win32/hostname_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/hostname_win32.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hostname_win32.Tpo" "$(DEPDIR)/hostname_win32.Po"; else rm -f "$(DEPDIR)/hostname_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/hostname_win32.c' object='hostname_win32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hostname_win32.obj `if test -f 'os_win32/hostname_win32.c'; then $(CYGPATH_W) 'os_win32/hostname_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/hostname_win32.c'; fi`
+
+syslog_win32.o: os_win32/syslog_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT syslog_win32.o -MD -MP -MF "$(DEPDIR)/syslog_win32.Tpo" -c -o syslog_win32.o `test -f 'os_win32/syslog_win32.c' || echo '$(srcdir)/'`os_win32/syslog_win32.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/syslog_win32.Tpo" "$(DEPDIR)/syslog_win32.Po"; else rm -f "$(DEPDIR)/syslog_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/syslog_win32.c' object='syslog_win32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o syslog_win32.o `test -f 'os_win32/syslog_win32.c' || echo '$(srcdir)/'`os_win32/syslog_win32.c
+
+syslog_win32.obj: os_win32/syslog_win32.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT syslog_win32.obj -MD -MP -MF "$(DEPDIR)/syslog_win32.Tpo" -c -o syslog_win32.obj `if test -f 'os_win32/syslog_win32.c'; then $(CYGPATH_W) 'os_win32/syslog_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/syslog_win32.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/syslog_win32.Tpo" "$(DEPDIR)/syslog_win32.Po"; else rm -f "$(DEPDIR)/syslog_win32.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os_win32/syslog_win32.c' object='syslog_win32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o syslog_win32.obj `if test -f 'os_win32/syslog_win32.c'; then $(CYGPATH_W) 'os_win32/syslog_win32.c'; else $(CYGPATH_W) '$(srcdir)/os_win32/syslog_win32.c'; fi`
+
+.s.o:
+ $(CCASCOMPILE) -c $<
+
+.s.obj:
+ $(CCASCOMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)"
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ 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)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ 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)$(man5dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ 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)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ 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)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+install-docsDATA: $(docs_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docsdir)" || $(mkdir_p) "$(DESTDIR)$(docsdir)"
+ @list='$(docs_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(docsDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docsdir)/$$f'"; \
+ $(docsDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docsdir)/$$f"; \
+ done
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(sysconfdir)" || $(mkdir_p) "$(DESTDIR)$(sysconfdir)"
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(sysconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sysconfdir)/$$f'"; \
+ $(sysconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sysconfdir)/$$f"; \
+ done
+
+uninstall-sysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(sysconfdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sysconfdir)/$$f"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ $(mkdir_p) $(distdir)/os_darwin
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(docsdir)" "$(DESTDIR)$(initddir)" "$(DESTDIR)$(sysconfdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-docsDATA install-initdDATA install-man
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-recursive
+
+@OS_SOLARIS_FALSE@install-man: install-man5 install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-docsDATA uninstall-info-am uninstall-initdDATA \
+ uninstall-man uninstall-sbinPROGRAMS uninstall-sysconfDATA
+
+uninstall-info: uninstall-info-recursive
+
+@OS_SOLARIS_FALSE@uninstall-man: uninstall-man5 uninstall-man8
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+ check-am clean clean-generic clean-recursive \
+ clean-sbinPROGRAMS ctags ctags-recursive dist dist-all \
+ dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-recursive distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-docsDATA install-exec install-exec-am install-info \
+ install-info-am install-initdDATA install-man install-man5 \
+ install-man8 install-sbinPROGRAMS install-strip \
+ install-sysconfDATA installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am uninstall-docsDATA \
+ uninstall-info-am uninstall-initdDATA uninstall-man \
+ uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS \
+ uninstall-sysconfDATA
+
+
+@SET_MAKE@
+@OS_SOLARIS_TRUE@install-man: $(extra_MANS)
+@OS_SOLARIS_TRUE@ @$(NORMAL_INSTALL)
+@OS_SOLARIS_TRUE@ $(mkinstalldirs) $(DESTDIR)$(mandir)/man4
+@OS_SOLARIS_TRUE@ $(mkinstalldirs) $(DESTDIR)$(mandir)/man1m
+@OS_SOLARIS_TRUE@ for i in $(extra_MANS); do \
+@OS_SOLARIS_TRUE@ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+@OS_SOLARIS_TRUE@ else file=$$i; fi; \
+@OS_SOLARIS_TRUE@ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+@OS_SOLARIS_TRUE@ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst"; \
+@OS_SOLARIS_TRUE@ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst; \
+@OS_SOLARIS_TRUE@ done
+@OS_SOLARIS_TRUE@uninstall-man:
+@OS_SOLARIS_TRUE@ @$(NORMAL_UNINSTALL)
+@OS_SOLARIS_TRUE@ for i in $(extra_MANS); do \
+@OS_SOLARIS_TRUE@ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+@OS_SOLARIS_TRUE@ else file=$$i; fi; \
+@OS_SOLARIS_TRUE@ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+@OS_SOLARIS_TRUE@ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+@OS_SOLARIS_TRUE@ echo " rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst"; \
+@OS_SOLARIS_TRUE@ rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst; \
+@OS_SOLARIS_TRUE@ done
+@OS_SOLARIS_TRUE@%.1m: %.8
+@OS_SOLARIS_TRUE@ awk '/^.TH/ {$$3="1m"} {print}' < $< | \
+@OS_SOLARIS_TRUE@ sed -e 's/smartd\.conf\(.*\)(5)/smartd.conf\1(4)/g' \
+@OS_SOLARIS_TRUE@ -e 's/syslog\.conf\(.*\)(5)/syslog.conf\1(4)/g' \
+@OS_SOLARIS_TRUE@ -e 's/smartctl\(.*\)(8)/smartctl\1(1m)/g' \
+@OS_SOLARIS_TRUE@ -e 's/syslogd\(.*\)(8)/syslogd\1(1m)/g' \
+@OS_SOLARIS_TRUE@ -e 's|/var/log/messages|/var/adm/messages|g' \
+@OS_SOLARIS_TRUE@ -e 's/smartd\(.*\)(8)/smartd\1(1m)/g' > $@
+@OS_SOLARIS_TRUE@%.4: %.5
+@OS_SOLARIS_TRUE@ awk '/^.TH/ {$$3="4"} {print}' < $< | \
+@OS_SOLARIS_TRUE@ sed -e 's/smartd\.conf\(.*\)(5)/smartd.conf\1(4)/g' \
+@OS_SOLARIS_TRUE@ -e 's/syslog\.conf\(.*\)(5)/syslog.conf\1(4)/g' \
+@OS_SOLARIS_TRUE@ -e 's/smartctl\(.*\)(8)/smartdctl\1(1m)/g' \
+@OS_SOLARIS_TRUE@ -e 's/syslogd\(.*\)(8)/syslogd\1(1m)/g' \
+@OS_SOLARIS_TRUE@ -e 's|/var/log/messages|/var/adm/messages|g' \
+@OS_SOLARIS_TRUE@ -e 's/smartd\(.*\)(8)/smartd\1(1m)/g' > $@
+
+@SMARTD_SUFFIX_TRUE@smartd.conf$(smartd_suffix): smartd.conf
+@SMARTD_SUFFIX_TRUE@ cp ${srcdir}/smartd.conf smartd.conf$(smartd_suffix)
+
+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
+
+@OS_DARWIN_TRUE@SMART : os_darwin/SMART.in
+@OS_DARWIN_TRUE@ sed "s|/usr/sbin/|$(sbindir)/|" $< > $@
+
+@OS_DARWIN_TRUE@install-initdDATA-darwin: $(initd_DATA)
+@OS_DARWIN_TRUE@ $(mkinstalldirs) $(DESTDIR)$(initddir)
+@OS_DARWIN_TRUE@ $(mkinstalldirs) $(DESTDIR)$(initddir)/SMART
+@OS_DARWIN_TRUE@ $(mkinstalldirs) $(DESTDIR)$(initddir)/SMART/Resources
+@OS_DARWIN_TRUE@ $(INSTALL_SCRIPT) $(top_builddir)/SMART $(DESTDIR)$(initddir)/SMART
+@OS_DARWIN_TRUE@ $(INSTALL_DATA) $(srcdir)/os_darwin/StartupParameters.plist \
+@OS_DARWIN_TRUE@ $(DESTDIR)$(initddir)/SMART/StartupParameters.plist
+@OS_DARWIN_TRUE@ for i in English ; do \
+@OS_DARWIN_TRUE@ RDIR=$(DESTDIR)$(initddir)/SMART/Resources/$${i}.lproj ; \
+@OS_DARWIN_TRUE@ $(mkinstalldirs) $$RDIR ;\
+@OS_DARWIN_TRUE@ $(INSTALL_DATA) $(srcdir)/os_darwin/$${i}_Localizable.strings \
+@OS_DARWIN_TRUE@ $$RDIR/Localizable.strings ; \
+@OS_DARWIN_TRUE@ done
+@OS_DARWIN_TRUE@ @echo -e "\n\n####################################################################\n#"
+@OS_DARWIN_TRUE@ @echo -e "# PLEASE READ THIS BOX!\n#"
+@OS_DARWIN_TRUE@ @echo -e "# To manually start the smartd daemon, run:\n# ${initddir}/SMART/SMART start\n#"
+@OS_DARWIN_TRUE@ @echo -e "# To automatically start smartd on bootup, add the line:\n# SMARTd=-YES-\n# to /etc/hostconfig\n#"
+@OS_DARWIN_TRUE@ @echo -e "# smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n# man smartd"
+@OS_DARWIN_TRUE@ @echo -e "# to learn about it. A sample configuration file can be found in:\n# ${docdir}\n#"
+@OS_DARWIN_TRUE@ @echo -e "####################################################################\n\n"
+
+@OS_DARWIN_FALSE@smartd.initd: $(srcdir)/smartd.initd.in Makefile
+@OS_DARWIN_FALSE@ sed "s|/usr/local/sbin/|$(sbindir)/|g" $(srcdir)/smartd.initd.in > $@
+
+@OS_DARWIN_FALSE@install-initdDATA-generic: $(initd_DATA)
+@OS_DARWIN_FALSE@ $(mkinstalldirs) $(DESTDIR)$(initddir)
+@OS_DARWIN_FALSE@ $(INSTALL_SCRIPT) $(top_builddir)/smartd.initd $(DESTDIR)$(initddir)/smartd$(smartd_suffix)
+@OS_DARWIN_FALSE@ @echo -e "\n\n####################################################################\n#"
+@OS_DARWIN_FALSE@ @echo -e "# PLEASE READ THIS BOX!\n#"
+@OS_DARWIN_FALSE@ @echo -e "# To manually start the smartd daemon, run:\n# ${initddir}/smartd start\n#"
+@OS_DARWIN_FALSE@ @echo -e "# To automatically start smartd on bootup, run:\n# /sbin/chkconfig --add smartd\n#"
+@OS_DARWIN_FALSE@ @echo -e "# smartd can now use a configuration file ${sysconfdir}/smartd.conf. Do:\n# man smartd"
+@OS_DARWIN_FALSE@ @echo -e "# to learn about it. A sample configuration file can be found in:\n# ${docdir}\n#"
+@OS_DARWIN_FALSE@ @echo -e "####################################################################\n\n"
+
+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/local/share/man/|$(mandir)/|g" | \
+ sed "s|/usr/local/sbin/|$(sbindir)/|g" | \
+ sed "s|/usr/local/etc/rc\\.d/init.d/|$(initddir)/|g" | \
+ sed "s|/usr/local/share/doc/smartmontools-5.1/|$(docsdir)/|g" | \
+ sed "s|/usr/local/etc/smartd\\.conf|$(sysconfdir)/smartd.conf|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) $< > $@
+
+# Build Windows distribution
+
+@OS_WIN32_MINGW_TRUE@dist-win32: $(distzip_win32)
+
+@OS_WIN32_MINGW_TRUE@distdir-win32: distdir.mkdir $(FILES_WIN32) syslogevt.check
+
+@OS_WIN32_MINGW_TRUE@$(distzip_win32): distdir.mkdir $(FILES_WIN32) syslogevt.check
+@OS_WIN32_MINGW_TRUE@ @rm -fv $(distzip_win32)
+@OS_WIN32_MINGW_TRUE@ cd $(distdir_win32) && zip -9Dr ../$(distzip_win32) .
+
+@OS_WIN32_MINGW_TRUE@cleandist-win32:
+@OS_WIN32_MINGW_TRUE@ rm -rf $(distdir_win32) distdir.mkdir syslogevt.check
+
+@OS_WIN32_MINGW_TRUE@distdir.mkdir:
+@OS_WIN32_MINGW_TRUE@ @test -d $(exedir_win32) || mkdir -pv $(exedir_win32)
+@OS_WIN32_MINGW_TRUE@ @test -d $(docdir_win32) || mkdir -pv $(docdir_win32)
+@OS_WIN32_MINGW_TRUE@ touch $@
+
+@OS_WIN32_MINGW_TRUE@syslogevt.check:
+@OS_WIN32_MINGW_TRUE@ @if [ -f $(srcdir)/os_win32/syslogevt.exe ]; then \
+@OS_WIN32_MINGW_TRUE@ cp -pv $(srcdir)/os_win32/syslogevt.exe $(exedir_win32)/syslogevt.exe; \
+@OS_WIN32_MINGW_TRUE@ else echo "Warning: $(srcdir)/os_win32/syslogevt.exe missing."; fi
+@OS_WIN32_MINGW_TRUE@ touch $@
+
+@OS_WIN32_MINGW_TRUE@$(exedir_win32)/%.exe: %.exe
+@OS_WIN32_MINGW_TRUE@ cp -p $< $@
+@OS_WIN32_MINGW_TRUE@ strip -s $@
+@OS_WIN32_MINGW_TRUE@ touch -r $< $@
+
+@OS_WIN32_MINGW_TRUE@$(docdir_win32)/%: %
+@OS_WIN32_MINGW_TRUE@ $(UNIX2DOS) < $< > $@
+@OS_WIN32_MINGW_TRUE@ touch -r $< $@
+
+@OS_WIN32_MINGW_TRUE@$(docdir_win32)/%.txt: $(srcdir)/%
+@OS_WIN32_MINGW_TRUE@ $(UNIX2DOS) < $< > $@
+@OS_WIN32_MINGW_TRUE@ touch -r $< $@
+
+@OS_WIN32_MINGW_TRUE@$(docdir_win32)/%.conf: $(srcdir)/%.conf
+@OS_WIN32_MINGW_TRUE@ $(UNIX2DOS) < $< > $@
+@OS_WIN32_MINGW_TRUE@ touch -r $< $@
+
+# Build config_vc6.h for MSVC 6 from MinGW config.h
+
+@OS_WIN32_MINGW_TRUE@config-vc6: $(srcdir)/os_win32/config_vc6.h
+
+@OS_WIN32_MINGW_TRUE@$(srcdir)/os_win32/config_vc6.h: config.h
+@OS_WIN32_MINGW_TRUE@ sed '1i/* config_vc6.h. Generated by Makefile. */' $< | \
+@OS_WIN32_MINGW_TRUE@ sed 's,^#define HAVE_\(ATTR_PACKED\|INTTYPES_H\|STDINT_H\|STRTOULL\|U*INT64_T\|UNISTD_H\) 1$$,/* #undef HAVE_\1 */,' | \
+@OS_WIN32_MINGW_TRUE@ sed 's,i.86-pc-mingw32,i686-pc-win32vc6,' > $@
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+smartmontools NEWS
+------------------
+CVS ID: $Id: NEWS,v 1.29 2006/04/12 15:46:30 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 2006-04-12
+Summary: smartmontools release 5.36 (STABLE)
+-----------------------------------------------------------
+This is a stable smartmontools release. The 5.34 version
+described just below was never officially released because
+Bruce Allen decided to wait until Linux support for
+accessing SATA devices through libata was in the official
+kernel.org sources. Changes include:
+
+- Win 2000/XP:ability to cancel drive self-tests
+- Additions to the table of known drives
+- FreeBSD support for 3ware char device interface and
+ multiple 3ware cards
+- Various cygwin improvements for running as service
+- Works 'out of the box' with Linux SATA libata
+- smartd option added to list test schedules
+- smartctl option added to list part of drive database
+- various improvements for SCSI disks and logs
+
+
+Date 2005-04-19
+Summary: smartmontools release 5.34 (STABLE)
+-----------------------------------------------------------
+This is a stable smartmontools release. It includes:
+- OS/2 and eComStation support
+All Platforms:
+ - Printing of drive family info
+ - SCSI disks: output size of grown defect list
+ - Added info about drive family to 'smartctl -i' output.
+ - Added option ',q' for smartd '-n' directive to suppress
+ 'skipping checks' message which may spin up laptop disk.
+ - Added message if smartd '-n' check power mode spins up disk.
+Cygwin and Windows:
+ - Added info about Windows version and service pack to banner line.
+ - Added support for smartd '-n' directive for Win2000/XP.
+ - Added support for READ_LOG for WinNT4 also.
+ - Fixed bug that prevents display of empty logs on Win2000/XP
+ - Fixed use of cached smart enabled state in 'smartctl -i' output.
+Windows:
+ - Fixed bug that prevents running smartd as service on WinNT4.
+
+
+Date 2004-9-5
+Summary: smartmontools release 5.33 (UNSTABLE/EXPERIMENTAL)
+-----------------------------------------------------------
+This is an unstable/experimental release of smartmontools. It includes
+ - support for Darwin/Mac OSX
+ - support for OpenBSD
+ - support for 3ware ATA RAID controllers under FreeBSD
+ - support for 3ware 9500 series SATA RAID controllers under
+ Linux. Use /dev/twa[0-15] devices to access these.
+ - support for 3ware character device interfaces /dev/twe[0-15]
+ under Linux. This allows (for example) Selective Self-tests.
+ - support for Marvell chip-set based SATA controllers under Linux.
+ - smartd mail now works also under Windows (using "Blat" mailer).
+ - smartd can now be run as a Windows service.
+Please report sucess/failure with these items to the
+smartmontools-support mailing list.
+
+
+Date 2004-7-5
+Summary: smartmontools release 5.32 (STABLE)
+-----------------------------------------------------------
+This is an stable release of smartmontools.
+Note added 2004/7/7: users building a Solaris/Intel version of the code should
+modify the 'configure' file, changing "pc-*-solaris*" on line 106
+to read "*-pc-solaris*". Reference:
+http://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 3165 of smartd.c, and changing:
+ "else if (cfgentries[0]) {"
+ to read:
+ "else if (cfgentries && cfgentries[0]) {"
+
+
+Date: 2004-2-24
+Summary: smartmontools release 5.29 (Experimental, not STABLE)
+--------------------------------------------------------------
+This is another experimental release, to replace the 5.27 release that
+had a damaged configure script. The next stable release will be 5.30
+- This release has SCSI support for NetBSD
+
+
+Date: 2004-2-12
+Summary: smartmontools release 5.27 (Experimental, not STABLE)
+--------------------------------------------------------------
+- WARNING: this release has a broken --prefix=/a/path option to the
+ configure script. The consequence is that smartd will not look for the
+ configuration file (smartd.conf) at the desired location.
+- NetBSD support added
+- A new Directive (-s) for smartd.conf now enables flexible automatic
+ scheduled self-testing for both ATA and SCSI devices.
+- Solaris now has ATA device support (SPARC only)
+- A new Directive (-n) for smartd.conf to avoid spinning up disks
+- Errors when smartd sends mail are now logged to SYSLOG
+- Solaris smartd mail now works correctly (uses mailx not mail)
+
+
+Date: 2003-11-29
+Summary: smartmontools release 5.26
+-----------------------------------
+This is a stable smartmontools release. The only known problem is
+that under Solaris, the email features of smartd do not work 'out of
+the box'. Three workarounds are:
+ [1] use '-M exec mailx' in /etc/smartd.conf
+ [2] in the start script for smartd, put /usr/ucb into PATH before
+ /bin
+ [3] upgrade to release 5.27 or later, or the latest CVS snapshot
+
+
+Date: 2003-11-19
+Summary: smartmontools release 5.25
+-----------------------------------
+This release should not hang when accessing USB devices. It provides
+smartd SCSI self-test log monitoring for self-test errors, and a
+larger table of known ATA drives. DEVICESCAN should work correctly
+even on file systems containing XFS or JFS partitions, and on machines
+that use devfs, even without traditional links.
+
+From this time on, even numbered releases will be 'stable' ones and
+odd numbered releases (like 5.25) will be unstable/testing/development
+releases.
+
+
+Date: 2003-10-30
+Summary: smartmontools release 5.23
+-----------------------------------
+This release has one known problem: DEVICESCAN device scanning does
+not work correctly if the disk with the /dev directory also has XFS
+or JFS file systems on it.
+
+
+Date: 2003-10-28
+Summary: smartmontools release 5.22
+-----------------------------------
+Replaces flawed 5.21 release: the -T verypermissive option had to be
+entered as -T verpermissive. First experimental solaris support (SCSI
+only). This release had a serious flaw: smartd left open file descriptors
+for devices that it couldn't monitor.
+
+
+Date: 2003-10-14
+Summary: smartmontools release 5.21
+-----------------------------------
+Preliminary support for FreeBSD added to smartmontools. For FreeBSD,
+ATA support requires a 5.1-CURRENT kernel while SCSI support should
+work across multiple versions (any that support CAM).
+
+
+Date: 2003-10-04
+Summary: smartmontools release 5.20
+-----------------------------------
+Replaces flawed 5.19 release (which had a zero-length man page
+smartd.conf.5).
+
+
+Date: 2003-10-03
+Summary: smartmontools release 5.19
+-----------------------------------
+This is the first release of smartmontools based on autoconf/automake.
+For this reason, it is a very experimental release. Please let us
+know in particular about documenation errors/omissions, missing or
+unneccesary files, and similar oversights. The major changes are:
+ [1] installation scripts based on autoconfig/automake
+ [2] ./configure [options] lets you set arbitrary paths
+ [3] supports FHS with ./configure --prefix=/usr/local
+ [4] correct paths are inserted into all man pages, binaries, etc.
+ [5] tarballs and RPMs are now GPG-signed
+
+
+Date: 2003-10-02 11:35
+Summary: smartd SEGV
+--------------------
+Some versions of smartd, including smartmontools release 5.1-18, will
+SEGV if the combination of Directives in /etc/smartd.conf contains
+-l error
+AND/OR
+-l selftest
+without any Attribute monitoring Directives. This is fixed in 5.19
+and above.
+
+A good workaround is to add:
+-o on
+OR
+-o off
+to enable or disable automatic offline data collection.
+
+
+Date: 2002-11-17 07:41
+Summary: testunitready bug in smartd
+------------------------------------
+A bug in smartd prevented functioning on scsi devices.
+The bug in question only affects smartd users with scsi devices.
+To see if your version of smartd has the testunitready() bug, do
+smartd -V
+If the version of the module smartd.c in a line like:
+Module: smartd.c revision: 1.66 date: 2002/11/17
+has a revision greater than or equal to 1.30, and less than or
+equal to 1.64, then your version of the code has this problem.
+
+This problem affected releases starting with RELEASE_5_0_16 up to and
+including RELEASE_5_0_43.
--- /dev/null
+==========================================================
+smartmontools - S.M.A.R.T. utility toolset for Darwin/Mac
+OSX, FreeBSD, Linux, NetBSD, OpenBSD, Solaris, and Windows.
+==========================================================
+
+$Id: README,v 1.55 2006/04/12 14:54:28 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-6 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 detailed installation instructions.
+
+See the "WARNINGS" file for reports of hardware where these utilities
+might cause serious problems such as lockups.
+
+== GETTING STARTED ==
+
+To examine SMART data from a disk, try:
+ smartctl -a /dev/hda
+for ATA disks, or
+ smartctl -a /dev/sda
+for SCSI disks. See the manual page 'man smartctl' for more
+information.
+
+To start automatic monitoring of your disks with the smartd daemon,
+try:
+ smartd -d
+to start the daemon in foreground (debug) mode, or
+ smartd
+to start the daemon in background mode. This will log messages to
+SYSLOG. If you would like to get email warning messages, please set
+up the configuration file smartd.conf with the '-m' mail warning
+Directive. See the manual page 'man smartd' for more information.
--- /dev/null
+TODO list for smartmontools:
+
+$Id: TODO,v 1.59 2005/12/11 18:40:35 ballen4705 Exp $
+
+SATA devices under Linux
+------------------------
+These work OK if you use the standard IDe drivers in drivers/ide.
+
+The situation is more complicated if you use libata.
+
+Prior to Linux kernel version 2.6.15-rc1, libata does not support the
+HDIO_DRIVE_TASK, HDIO_DRIVE_CMD, and HDIO_DRIVE_TASKFILE ioctl()s that
+are needed by smartmontools. Support for HDIO_DRIVE_TASK and
+HDIO_DRIVE_CMD was added into libata by Jeff Garzik starting with
+Linux kernel version 2.6.15-rc1. Starting with this version, you can
+use all the smartmontools commands apart from initiating selective
+self-tests (which also requires HDIO_DRIVE_TASKFILE). A typical
+command line might look like this:
+ smartctl -a -d ata /dev/sda
+The '-d ata' is required, since otherwise smartmontools will assume
+that the device is SCSI, not ATA/SATA. Similar syntax will work with
+smartd.
+
+You may be able to patch earlier versions of libata. Please search the
+Linux Kernel Mailing list to find this patch, or look at the thread:
+http://groups.google.de/groups?hl=en&lr=&ie=UTF-8&threadm=2yYBY-4HB-55%40gated-at.bofh.it&rnum=3&prev=/groups%3Fq%3Dsmartmontools%26hl%3Den%26lr%3D%26ie%3DUTF-8%26scoring%3Dd%26selm%3D2yYBY-4HB-55%2540gated-at.bofh.it%26rnum%3D3
+To use this, just use (for example) 'smartctl -a -d ata /dev/sda'.
+
+Since this looks like this patch will become standard, we need to add something
+to smartmontools to automatically recognize the libata, and add the '-d ata'
+automatically.
+
+SATA devices
+------------
+The ATA PASS THROUGH SCSI command (12 and 16 byte cdb) as defined in
+SAT: http://www.t10.org/ftp/t10/drafts/sat/sat-r07.pdf (section 12.2)
+provides a general way to pass ATA SMART commands through to SATA
+devices.
+
+Doug Gilbert will in the future add a '-d sat' type (note, this is not
+a typo, we do not mean '-d sata') which will instruct the generic
+smartmontools code to assume an ATA device but use those ATA PASS
+THROUGH commands.
+
+This should provide additional support for SATA devices under most or
+all operating systems.
+
+USB devices under Linux
+-----------------------
+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
+-------
+
+Add support for 3ware 9000 series SATA controllers.
+
+Cygwin and Windows
+------------------
+Add IDE/ATA selective self test.
+
+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
--- /dev/null
+$Id: WARNINGS,v 1.32 2005/04/20 19:17:33 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 NT4, 2000 or XP system.
+PROBLEM: Use of undocumented system calls 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 undocumented
+ and possibly buggy system calls for this purpose:
+ NT4: IOCTL_SCSI_PASS_THROUGH.with undocumented pseudo SCSI
+ command SCSIOP_ATA_PASSTHROUGH (0xCC).
+ 2000/XP: Undocumented IOCTL_IDE_PASS_THROUGH.
+
+
+DARWIN
+------
+
+SYSTEM: Any system before Tiger
+PROBLEM: Can't switch off SMART, can't switch off auto-save, can't run
+ short tests.
+REPORTER: Geoff Keating <geoffk@geoffk.org>
+NOTE: There's a bug in the system library: when you ask it to
+ do any of these things, it does the inverse (switches on,
+ runs extended tests). Radar 3727283.
+
+SYSTEM: All known systems
+PROBLEM: When drive is asleep, SMART commands fail
+REPORTER: Geoff Keating <geoffk@geoffk.org>
+NOTE: You can prevent the drive from sleeping by saying
+ pmset -a disksleep 0
+ or by unchecking the 'Put the hard disk(s) to sleep when possible'
+ checkbox in the Energy Saver preferences. Radar 4094403.
--- /dev/null
+# generated automatically by aclocal 1.9.3 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# -*- Autoconf -*-
+# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# Generated from amversion.in; do not edit by hand.
+
+# 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.
+
+# 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
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+ [AM_AUTOMAKE_VERSION([1.9.3])])
+
+# Figure out how to run the assembler. -*- Autoconf -*-
+
+# serial 3
+
+# Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# AM_PROG_AS
+# ----------
+AC_DEFUN([AM_PROG_AS],
+[# By default we simply use the C compiler to build assembly code.
+AC_REQUIRE([AC_PROG_CC])
+test "${CCAS+set}" = set || CCAS=$CC
+test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
+AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)])
+AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)])
+])
+
+# AM_AUX_DIR_EXPAND
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 6
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# serial 7 -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+#serial 2
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 7
+
+# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# This macro actually does too much some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 11
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $1 | $1:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# -*- Autoconf -*-
+# Copyright (C) 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 1
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 3
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 2
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# -*- Autoconf -*-
+
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 3
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+
+# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake. There are at least two reasons why we must not
+# use `-m 0755':
+# - it causes special bits like SGID to be ignored,
+# - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out. Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 2
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 3
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# AM_PROG_INSTALL_STRIP
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# serial 1
+
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
--- /dev/null
+/*
+ * 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-6 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.13 2006/04/12 14:54:28 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];
+ }
+}
--- /dev/null
+/*
+ * 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-6 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.5 2006/04/12 14:54:28 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
--- /dev/null
+/*
+ * atacmds.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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 "config.h"
+#include "int64.h"
+#include "atacmds.h"
+#include "extern.h"
+#include "utility.h"
+
+const char *atacmds_c_cvsid="$Id: atacmds.c,v 1.168 2006/04/12 17:01:46 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);
+ if (retval && con->controller_port<=0)
+ pout("WARNING: apparently missing '-d 3ware,N' disk specification\n");
+ break;
+ case CONTROLLER_MARVELL_SATA:
+ retval=marvell_command_interface(device, 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", (unsigned char)(*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;
+ }
+ }
+
+#ifndef __NetBSD__
+ // if machine is big-endian, swap byte order as needed
+ // (the NetBSD kernel does deliver the results in host byte order)
+ 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));
+ }
+#endif
+
+ // 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. Note that it should return 1
+// regardless of whether the disk's SMART status is 'healthy' or
+// 'failing'.
+int ataDoesSmartWork(int device){
+ int retval=smartcommandhandler(device, STATUS, 0, NULL);
+
+ if (-1 == retval)
+ return 0;
+
+ return 1;
+}
+
+// This function uses a different interface (DRIVE_TASK) than the
+// other commands in this file.
+int ataSmartStatus2(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;
+}
+
+
--- /dev/null
+/*
+ * atacmds.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.81 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+// Macro to check expected size of struct at compile time using a
+// dummy typedef. On size mismatch, compiler reports a negative array
+// size. If you see an error message of this form, it means that the
+// #pragma pack(1) pragma below is not having the desired effect on
+// your compiler.
+#define ASSERT_SIZEOF_STRUCT(s, n) \
+ typedef char assert_sizeof_struct_##s[(sizeof(struct s) == (n)) ? 1 : -1]
+
+// Add __attribute__((packed)) if compiler supports it
+// because some gcc versions (at least ARM) lack support of #pragma pack()
+#ifdef HAVE_ATTR_PACKED
+#define ATTR_PACKED __attribute__((packed))
+#else
+#define ATTR_PACKED
+#endif
+
+typedef enum {
+ // returns no data, just succeeds or fails
+ ENABLE,
+ DISABLE,
+ AUTOSAVE,
+ IMMEDIATE_OFFLINE,
+ AUTO_OFFLINE,
+ STATUS, // just says if SMART is working or not
+ STATUS_CHECK, // says if disk's SMART status is healthy, or failing
+ // return 512 bytes of data:
+ READ_VALUES,
+ READ_THRESHOLDS,
+ READ_LOG,
+ IDENTIFY,
+ PIDENTIFY,
+ // returns 1 byte of data
+ CHECK_POWER_MODE,
+ // writes 512 bytes of data:
+ WRITE_LOG
+} smart_command_set;
+
+// ATA Specification Command Register Values (Commands)
+#define ATA_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];
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_identify_device, 512);
+
+/* ata_smart_attribute is the vendor specific in SFF-8035 spec */
+#pragma pack(1)
+struct ata_smart_attribute {
+ unsigned char id;
+ // meaning of flag bits: see MACROS just below
+ // WARNING: MISALIGNED!
+ unsigned short flags;
+ unsigned char current;
+ unsigned char worst;
+ unsigned char raw[6];
+ unsigned char reserv;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_attribute, 12);
+
+// MACROS to interpret the flags bits in the previous structure.
+// These have not been implemented using bitflags and a union, to make
+// it portable across bit/little endian and different platforms.
+
+// 0: Prefailure bit
+
+// From SFF 8035i Revision 2 page 19: Bit 0 (pre-failure/advisory bit)
+// - If the value of this bit equals zero, an attribute value less
+// than or equal to its corresponding attribute threshold indicates an
+// advisory condition where the usage or age of the device has
+// exceeded its intended design life period. If the value of this bit
+// equals one, an attribute value less than or equal to its
+// corresponding attribute threshold indicates a prefailure condition
+// where imminent loss of data is being predicted.
+#define ATTRIBUTE_FLAGS_PREFAILURE(x) (x & 0x01)
+
+// 1: Online bit
+
+// From SFF 8035i Revision 2 page 19: Bit 1 (on-line data collection
+// bit) - If the value of this bit equals zero, then the attribute
+// value is updated only during off-line data collection
+// activities. If the value of this bit equals one, then the attribute
+// value is updated during normal operation of the device or during
+// both normal operation and off-line testing.
+#define ATTRIBUTE_FLAGS_ONLINE(x) (x & 0x02)
+
+
+// The following are (probably) IBM's, Maxtors and Quantum's definitions for the
+// vendor-specific bits:
+// 2: Performance type bit
+#define ATTRIBUTE_FLAGS_PERFORMANCE(x) (x & 0x04)
+
+// 3: Errorrate type bit
+#define ATTRIBUTE_FLAGS_ERRORRATE(x) (x & 0x08)
+
+// 4: Eventcount bit
+#define ATTRIBUTE_FLAGS_EVENTCOUNT(x) (x & 0x10)
+
+// 5: Selfpereserving bit
+#define ATTRIBUTE_FLAGS_SELFPRESERVING(x) (x & 0x20)
+
+
+// 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;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_values, 512);
+
+/* Maxtor, IBM: self-test failure checkpoint byte meaning:
+ 00 - write test
+ 01 - servo basic
+ 02 - servo random
+ 03 - G-list scan
+ 04 - Handling damage
+ 05 - Read scan
+*/
+
+/* Vendor attribute of SMART Threshold (compare to ata_smart_attribute above) */
+#pragma pack(1)
+struct ata_smart_threshold_entry {
+ unsigned char id;
+ unsigned char threshold;
+ unsigned char reserved[10];
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_threshold_entry, 12);
+
+/* Format of Read SMART THreshold Command */
+/* Compare to ata_smart_values above */
+#pragma pack(1)
+struct ata_smart_thresholds_pvt {
+ unsigned short int revnumber;
+ struct ata_smart_threshold_entry thres_entries[NUMBER_ATA_SMART_ATTRIBUTES];
+ unsigned char reserved[149];
+ unsigned char chksum;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_thresholds_pvt, 512);
+
+
+// Table 42 of T13/1321D Rev 1 spec (Error Data Structure)
+#pragma pack(1)
+struct ata_smart_errorlog_error_struct {
+ unsigned char reserved;
+ unsigned char error_register;
+ unsigned char sector_count;
+ unsigned char sector_number;
+ unsigned char cylinder_low;
+ unsigned char cylinder_high;
+ unsigned char drive_head;
+ unsigned char status;
+ unsigned char extended_error[19];
+ unsigned char state;
+ unsigned short timestamp;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_error_struct, 30);
+
+
+// Table 41 of T13/1321D Rev 1 spec (Command Data Structure)
+#pragma pack(1)
+struct ata_smart_errorlog_command_struct {
+ unsigned char devicecontrolreg;
+ unsigned char featuresreg;
+ unsigned char sector_count;
+ unsigned char sector_number;
+ unsigned char cylinder_low;
+ unsigned char cylinder_high;
+ unsigned char drive_head;
+ unsigned char commandreg;
+ unsigned int timestamp;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_command_struct, 12);
+
+// Table 40 of T13/1321D Rev 1 spec (Error log data structure)
+#pragma pack(1)
+struct ata_smart_errorlog_struct {
+ struct ata_smart_errorlog_command_struct commands[5];
+ struct ata_smart_errorlog_error_struct error_struct;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_struct, 90);
+
+// Table 39 of T13/1321D Rev 1 spec (SMART error log sector)
+#pragma pack(1)
+struct ata_smart_errorlog {
+ unsigned char revnumber;
+ unsigned char error_log_pointer;
+ struct ata_smart_errorlog_struct errorlog_struct[5];
+ unsigned short int ata_error_count;
+ unsigned char reserved[57];
+ unsigned char checksum;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_errorlog, 512);
+
+// Table 45 of T13/1321D Rev 1 spec (Self-test log descriptor entry)
+#pragma pack(1)
+struct ata_smart_selftestlog_struct {
+ unsigned char selftestnumber; // Sector number register
+ unsigned char selfteststatus;
+ unsigned short int timestamp;
+ unsigned char selftestfailurecheckpoint;
+ unsigned int lbafirstfailure;
+ unsigned char vendorspecific[15];
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog_struct, 24);
+
+// Table 44 of T13/1321D Rev 1 spec (Self-test log data structure)
+#pragma pack(1)
+struct ata_smart_selftestlog {
+ unsigned short int revnumber;
+ struct ata_smart_selftestlog_struct selftest_struct[21];
+ unsigned char vendorspecific[2];
+ unsigned char mostrecenttest;
+ unsigned char reserved[2];
+ unsigned char chksum;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog, 512);
+
+// SMART LOG DIRECTORY Table 52 of T13/1532D Vol 1 Rev 1a
+#pragma pack(1)
+struct ata_smart_log_entry {
+ unsigned char numsectors;
+ unsigned char reserved;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_log_entry, 2);
+
+#pragma pack(1)
+struct ata_smart_log_directory {
+ unsigned short int logversion;
+ struct ata_smart_log_entry entry[255];
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_smart_log_directory, 512);
+
+// SMART SELECTIVE SELF-TEST LOG Table 61 of T13/1532D Volume 1
+// Revision 3
+#pragma pack(1)
+struct test_span {
+ uint64_t start;
+ uint64_t end;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(test_span, 16);
+
+#pragma pack(1)
+struct ata_selective_self_test_log {
+ unsigned short logversion;
+ struct test_span span[5];
+ unsigned char reserved1[337-82+1];
+ unsigned char vendor_specific1[491-338+1];
+ uint64_t currentlba;
+ unsigned short currentspan;
+ unsigned short flags;
+ unsigned char vendor_specific2[507-504+1];
+ unsigned short pendingtime;
+ unsigned char reserved2;
+ unsigned char checksum;
+} ATTR_PACKED;
+#pragma pack()
+ASSERT_SIZEOF_STRUCT(ata_selective_self_test_log, 512);
+
+#define SELECTIVE_FLAG_DOSCAN (0x0002)
+#define SELECTIVE_FLAG_PENDING (0x0008)
+#define SELECTIVE_FLAG_ACTIVE (0x0010)
+
+// 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);
+int marvell_command_interface(int device, smart_command_set command, int select, char *data);
+// Optional functions of os_*.c
+#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
+// Return true if OS caches the ATA identify sector
+int ata_identify_is_cached(int fd);
+#endif
+
+// 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_ */
--- /dev/null
+/*
+ * ataprint.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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 "config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif // #ifdef HAVE_LOCALE_H
+
+#include "int64.h"
+#include "atacmdnames.h"
+#include "atacmds.h"
+#include "ataprint.h"
+#include "smartctl.h"
+#include "extern.h"
+#include "utility.h"
+#include "knowndrives.h"
+
+const char *ataprint_c_cvsid="$Id: ataprint.c,v 1.164 2006/04/12 14:54:28 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;
+#ifndef __NetBSD__
+ swapbytes(tmp, in, n);
+#else
+ strncpy(tmp, in, n); /* NetBSD delivers host byte order strings */
+#endif
+ tmp[n] = '\0';
+ trim(out, tmp);
+}
+
+void infofound(char *output) {
+ 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;
+ char separator=',';
+
+ // get correct character to use as thousands separator
+#ifdef HAVE_LOCALE_H
+ struct lconv *currentlocale=NULL;
+ setlocale (LC_ALL, "");
+ currentlocale=localeconv();
+ if (*(currentlocale->thousands_sep))
+ separator=*(currentlocale->thousands_sep);
+#endif // #ifdef HAVE_LOCALE_H
+
+ // 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 locale-specific separators (default is comma)
+ 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, "%c%03"PRIu64, separator, 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];
+
+ // format drive information (with byte swapping as needed)
+ formatdriveidstring(model, (char *)drive->model,40);
+ formatdriveidstring(serial, (char *)drive->serial_no,20);
+ formatdriveidstring(firm, (char *)drive->fw_rev,8);
+
+ // print out model, serial # and firmware versions (byte-swap ASCI strings)
+ drivetype=lookupdrive(model, firm);
+
+ // Print model family if known
+ if (drivetype>=0 && knowndrives[drivetype].modelfamily)
+ pout("Model Family: %s\n", knowndrives[drivetype].modelfamily);
+
+ pout("Device Model: ");
+ infofound(model);
+ pout("Serial Number: ");
+ infofound(serial);
+ pout("Firmware Version: ");
+ infofound(firm);
+
+ if (determine_capacity(drive, capacity))
+ pout("User Capacity: %s bytes\n", capacity);
+
+ // See if drive is recognized
+ 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 (allowing some screw-ups in the
+ // thresholds page data to slip by)
+ if (disk->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");
+#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
+ if (ata_identify_is_cached(fd)) {
+ pout(" %sabled status cached by OS, trying SMART RETURN STATUS cmd.\n",
+ (isenabled?"En":"Dis"));
+ isenabled=ataDoesSmartWork(fd);
+ }
+#endif
+ }
+
+ 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;
+}
--- /dev/null
+/*
+ * ataprint.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.28 2006/04/12 14:54:28 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
--- /dev/null
+#!/bin/sh
+# $Id: autogen.sh,v 1.13 2005/09/19 09:28:11 chrfranke 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.9` || AUTOMAKE=`typep automake-1.8` || AUTOMAKE=`typep automake-1.7` || AUTOMAKE=`typep automake17` ||
+{
+echo
+echo "You must have at least GNU Automake 1.7 (up to 1.9.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.9.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, automake-1.8, or automake-1.9 in"
+echo "your PATH, but not the respective aclocal-1.7, aclocal-1.8, or"
+echo "aclocal-1.9. Your installation of GNU Automake is broken or"
+echo "incomplete."
+exit 2;
+}
+
+# Warn if Automake version is unknown
+ver=
+case "$AUTOMAKE" in
+ *automake-1.[78]|*automake17)
+ ;;
+ *)
+ ver="`$AUTOMAKE --version | head -1 | sed -n 's,^.*\([12]\.[.0-9]*[-pl0-9]*\).*$,\1,p'`"
+ ver="${ver:-?.?.?}"
+ case "$ver" in
+ 1.[78]*|1.9.[1-6]) ver= ;;
+ esac ;;
+esac
+
+test -z "$ver" ||
+{
+echo "Note: GNU Automake version ${ver} was not tested by the developers."
+echo "Please report success/failure to the smartmontools-support mailing list."
+}
+
+set -e # stops on error status
+
+${ACLOCAL}
+autoheader
+${AUTOMAKE} --add-missing --copy --foreign
+autoconf
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+timestamp='2004-10-25'
+
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amd64:OpenBSD:*:*)
+ echo x86_64-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ cats:OpenBSD:*:*)
+ echo arm-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ luna88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips64-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit 0 ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit 0 ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit 0 ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit 0 ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit 0 ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit 0 ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms && exit 0 ;;
+ I*) echo ia64-dec-vms && exit 0 ;;
+ V*) echo vax-dec-vms && exit 0 ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* smartmontools CVS Tag */
+#undef CONFIG_H_CVSID
+
+/* use mailx as default mailer */
+#undef DEFAULT_MAILER
+
+/* Define to 1 if you have the `ata_identify_is_cached' function in os_*.c. */
+#undef HAVE_ATA_IDENTIFY_IS_CACHED
+
+/* Define to 1 if C compiler supports __attribute__((packed)) */
+#undef HAVE_ATTR_PACKED
+
+/* 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 `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define to 1 if you have the `get_os_version_str' function in os_*.c. */
+#undef HAVE_GET_OS_VERSION_STR
+
+/* Define to 1 if the system has the type `int64_t'. */
+#undef HAVE_INT64_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* 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. */
+#undef HAVE_STDLIB_H
+
+/* 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. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if you have the <sys/inttypes.h> header file. */
+#undef HAVE_SYS_INTTYPES_H
+
+/* Define to 1 if you have the <sys/int_types.h> header file. */
+#undef HAVE_SYS_INT_TYPES_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/tweio.h> header file. */
+#undef HAVE_SYS_TWEIO_H
+
+/* Define to 1 if you have the <sys/twereg.h> header file. */
+#undef HAVE_SYS_TWEREG_H
+
+/* Define to 1 if you have the <sys/tw_osl_ioctl.h> header file. */
+#undef HAVE_SYS_TW_OSL_IOCTL_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#undef HAVE_UINT64_T
+
+/* 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
+
+/* Define to 1 if the `snprintf' function is sane */
+#undef HAVE_WORKING_SNPRINTF
+
+/* need assembly code os_solaris_ata.s */
+#undef NEED_SOLARIS_ATA_CODE
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* smartmontools Home Page */
+#undef PACKAGE_HOMEPAGE
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* smartmontools Build Host */
+#undef SMARTMONTOOLS_BUILD_HOST
+
+/* smartmontools Configure Arguments */
+#undef SMARTMONTOOLS_CONFIGURE_ARGS
+
+/* smartmontools Configure Date */
+#undef SMARTMONTOOLS_CONFIGURE_DATE
+
+/* smartmontools Release Date */
+#undef SMARTMONTOOLS_RELEASE_DATE
+
+/* smartmontools Release Time */
+#undef SMARTMONTOOLS_RELEASE_TIME
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+timestamp='2004-08-29'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | msp430 \
+ | ns16k | ns32k \
+ | openrisc | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ or32 | or32-*)
+ basic_machine=or32-unknown
+ os=-coff
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for smartmontools 5.36.
+#
+# Report bugs to <smartmontools-support@lists.sourceforge.net>.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='smartmontools'
+PACKAGE_TARNAME='smartmontools'
+PACKAGE_VERSION='5.36'
+PACKAGE_STRING='smartmontools 5.36'
+PACKAGE_BUGREPORT='smartmontools-support@lists.sourceforge.net'
+
+ac_unique_file="smartctl.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CCAS CCASFLAGS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CPP EGREP libc_have_working_snprintf gcc_have_attr_packed ASFLAGS exampledir initddir docdir smartd_suffix SMARTD_SUFFIX_TRUE SMARTD_SUFFIX_FALSE releaseversion smartmontools_release_date smartmontools_release_time os_deps os_libs OS_DARWIN_TRUE OS_DARWIN_FALSE OS_SOLARIS_TRUE OS_SOLARIS_FALSE OS_WIN32_MINGW_TRUE OS_WIN32_MINGW_FALSE LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CCAS_set=${CCAS+set}
+ac_env_CCAS_value=$CCAS
+ac_cv_env_CCAS_set=${CCAS+set}
+ac_cv_env_CCAS_value=$CCAS
+ac_env_CCASFLAGS_set=${CCASFLAGS+set}
+ac_env_CCASFLAGS_value=$CCASFLAGS
+ac_cv_env_CCASFLAGS_set=${CCASFLAGS+set}
+ac_cv_env_CCASFLAGS_value=$CCASFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures smartmontools 5.36 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of smartmontools 5.36:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-sample Enables appending .sample to the installed smartd rc
+ script and configuration file
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-initscriptdir=dir
+ Location of init scripts (default is
+ ${sysconfdir}/rc.d/init.d)
+ --with-docdir=dir Location of documentation (default is
+ ${prefix}/share/doc/smartmontools-5.X)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CCAS assembler compiler command (defaults to CC)
+ CCASFLAGS assembler compiler flags (defaults to CFLAGS)
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <smartmontools-support@lists.sourceforge.net>.
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+smartmontools configure 5.36
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by smartmontools $as_me 5.36, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+smartmontools_configure_date=`date -u +"%Y/%m/%d %T %Z"`
+smartmontools_cvs_tag=`echo '$Id: configure.in,v 1.113 2005/11/27 20:01:29 chrfranke Exp $'`
+smartmontools_release_date=2006/04/12
+smartmontools_release_time="17:39:01 UTC"
+
+
+cat >>confdefs.h <<_ACEOF
+#define SMARTMONTOOLS_CONFIGURE_ARGS "$ac_configure_args"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SMARTMONTOOLS_CONFIGURE_DATE "$smartmontools_configure_date"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SMARTMONTOOLS_RELEASE_DATE "$smartmontools_release_date"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SMARTMONTOOLS_RELEASE_TIME "$smartmontools_release_time"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIG_H_CVSID "$smartmontools_cvs_tag"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_HOMEPAGE "http://smartmontools.sourceforge.net/"
+_ACEOF
+
+
+ ac_config_headers="$ac_config_headers config.h"
+
+
+am__api_version="1.9"
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='smartmontools'
+ VERSION='5.36'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi;
+ echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+# By default we simply use the C compiler to build assembly code.
+
+test "${CCAS+set}" = set || CCAS=$CC
+test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
+
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+case "${host}" in
+ *-*-mingw*)
+ CPPFLAGS="$CPPFLAGS -mno-cygwin"
+ LDFLAGS="$LDFLAGS -mno-cygwin"
+ CPPFLAGS="$CPPFLAGS -idirafter ${srcdir}/posix -idirafter ${srcdir}/os_win32"
+esac
+
+# AC_SEARCH_LIBS (FUNCTION, SEARCH-LIBS, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], [OTHER-LIBRARIES])
+echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5
+echo $ECHO_N "checking for library containing gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_search_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gethostbyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gethostbyname" = no; then
+ for ac_lib in nsl; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_search_gethostbyname" >&6
+if test "$ac_cv_search_gethostbyname" != no; then
+ test "$ac_cv_search_gethostbyname" = "none required" || LIBS="$ac_cv_search_gethostbyname $LIBS"
+
+else
+ echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5
+echo $ECHO_N "checking for library containing gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_search_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gethostbyname=no
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gethostbyname" = no; then
+ for ac_lib in nsl; do
+ LIBS="-l$ac_lib -lsocket $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_search_gethostbyname" >&6
+if test "$ac_cv_search_gethostbyname" != no; then
+ test "$ac_cv_search_gethostbyname" = "none required" || LIBS="$ac_cv_search_gethostbyname $LIBS"
+
+fi
+
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in locale.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in getopt.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dev/ata/atavar.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in netdb.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in inttypes.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in stdint.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/inttypes.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/int_types.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/tweio.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/twereg.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/tw_osl_ioctl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ---------------------------------------------------------- ##
+## Report this to smartmontools-support@lists.sourceforge.net ##
+## ---------------------------------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for int64_t" >&5
+echo $ECHO_N "checking for int64_t... $ECHO_C" >&6
+if test "${ac_cv_type_int64_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((int64_t *) 0)
+ return 0;
+if (sizeof (int64_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_int64_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_int64_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5
+echo "${ECHO_T}$ac_cv_type_int64_t" >&6
+if test $ac_cv_type_int64_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT64_T 1
+_ACEOF
+
+
+fi
+echo "$as_me:$LINENO: checking for uint64_t" >&5
+echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6
+if test "${ac_cv_type_uint64_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((uint64_t *) 0)
+ return 0;
+if (sizeof (uint64_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_uint64_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_uint64_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5
+echo "${ECHO_T}$ac_cv_type_uint64_t" >&6
+if test $ac_cv_type_uint64_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UINT64_T 1
+_ACEOF
+
+
+fi
+
+
+
+for ac_func in getopt
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in getopt_long
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in getdomainname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in gethostname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in gethostbyname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in sigset
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in strtoull
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in uname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+# Check whether snprintf appends null char and returns expected length on overflow
+
+
+echo "$as_me:$LINENO: checking for working snprintf" >&5
+echo $ECHO_N "checking for working snprintf... $ECHO_C" >&6
+if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+ char buf[]="ABCDEFGHI";
+ int i=snprintf(buf,8,"12345678"); return !(!buf[7] && i==8);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ libc_have_working_snprintf=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+libc_have_working_snprintf=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "$libc_have_working_snprintf" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_WORKING_SNPRINTF 1
+_ACEOF
+
+fi
+echo "$as_me:$LINENO: result: $libc_have_working_snprintf" >&5
+echo "${ECHO_T}$libc_have_working_snprintf" >&6
+
+# check for __attribute__((packed))
+
+
+echo "$as_me:$LINENO: checking whether C compiler supports __attribute__((packed))" >&5
+echo $ECHO_N "checking whether C compiler supports __attribute__((packed))... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+struct a { int b; } __attribute__((packed));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gcc_have_attr_packed=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gcc_have_attr_packed=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test "$gcc_have_attr_packed" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_ATTR_PACKED 1
+_ACEOF
+
+fi
+echo "$as_me:$LINENO: result: $gcc_have_attr_packed" >&5
+echo "${ECHO_T}$gcc_have_attr_packed" >&6
+
+
+
+
+
+exampledir='${docdir}/examplescripts'
+
+
+
+# Check whether --with-initscriptdir or --without-initscriptdir was given.
+if test "${with_initscriptdir+set}" = set; then
+ withval="$with_initscriptdir"
+ initddir="$withval"
+else
+ initddir='${sysconfdir}/rc.d/init.d'
+fi;
+
+
+
+# Check whether --with-docdir or --without-docdir was given.
+if test "${with_docdir+set}" = set; then
+ withval="$with_docdir"
+ docdir="$withval"
+else
+ docdir='${prefix}/share/doc/${PACKAGE}-${VERSION}'
+fi;
+
+
+# Check whether --enable-sample or --disable-sample was given.
+if test "${enable_sample+set}" = set; then
+ enableval="$enable_sample"
+ smartd_suffix='.sample'
+else
+ smartd_suffix=''
+fi;
+
+
+
+if test $smartd_suffix; then
+ SMARTD_SUFFIX_TRUE=
+ SMARTD_SUFFIX_FALSE='#'
+else
+ SMARTD_SUFFIX_TRUE='#'
+ SMARTD_SUFFIX_FALSE=
+fi
+
+
+if test "$prefix" = "NONE"; then
+ if test "$mandir" = '${prefix}/man'; then
+ mandir='${prefix}/share/man'
+
+ fi
+fi
+
+releaseversion='${PACKAGE}-${VERSION}'
+
+
+
+
+case "${host}" in
+ *-*-linux-gnu*)
+ os_deps='os_linux.o'
+
+ os_libs=''
+ ;;
+ *-*-linux*)
+ os_deps='os_linux.o'
+
+ os_libs=''
+ ;;
+ *-*-freebsd*)
+ os_deps='os_freebsd.o'
+
+ os_libs='-lcam'
+;;
+ sparc-*-solaris*)
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MAILER "mailx"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define NEED_SOLARIS_ATA_CODE "os_solaris_ata.s"
+_ACEOF
+
+ os_deps='os_solaris.o os_solaris_ata.o'
+
+ os_libs=''
+ ;;
+ *-pc-solaris*)
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MAILER "mailx"
+_ACEOF
+
+ os_deps='os_solaris.o'
+
+ os_libs=''
+ ;;
+ *-*-netbsd*)
+ os_deps='os_netbsd.o'
+
+ os_libs='-lutil'
+ ;;
+ *-*-openbsd*)
+ os_deps='os_openbsd.o'
+
+ os_libs='-lutil'
+ ;;
+ *-*-cygwin*)
+ os_deps='os_win32.o'
+
+ os_libs=''
+ ;;
+ *-*-mingw*)
+ os_deps='os_win32.o'
+
+ os_libs=''
+ ;;
+ *-*-darwin*)
+ os_deps='os_darwin.o'
+
+ os_libs='-framework CoreFoundation -framework IOKit'
+ ;;
+ *)
+ os_deps='os_generic.o'
+
+ os_libs=''
+ ;;
+esac
+
+# Define symbols for optional functions in OS specific module
+case "${os_deps}" in
+ os_win32*)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ATA_IDENTIFY_IS_CACHED 1
+_ACEOF
+ ;;
+esac
+case "${os_deps}" in
+ os_win32*)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GET_OS_VERSION_STR 1
+_ACEOF
+ ;;
+esac
+
+
+
+if echo $host_os | grep '^darwin' > /dev/null; then
+ OS_DARWIN_TRUE=
+ OS_DARWIN_FALSE='#'
+else
+ OS_DARWIN_TRUE='#'
+ OS_DARWIN_FALSE=
+fi
+
+
+
+if echo $host_os | grep '^solaris' > /dev/null; then
+ OS_SOLARIS_TRUE=
+ OS_SOLARIS_FALSE='#'
+else
+ OS_SOLARIS_TRUE='#'
+ OS_SOLARIS_FALSE=
+fi
+
+
+
+if echo $host_os | grep '^mingw' > /dev/null; then
+ OS_WIN32_MINGW_TRUE=
+ OS_WIN32_MINGW_FALSE='#'
+else
+ OS_WIN32_MINGW_TRUE='#'
+ OS_WIN32_MINGW_FALSE=
+fi
+
+
+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
+ case "${host}" in
+ *-*-solaris*)
+ if test -z "`echo "$CFLAGS" | grep "\-xmemalign" 2> /dev/null`" ; then
+ CFLAGS="-xmemalign=1i $CFLAGS"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-xCC" 2> /dev/null`" ; then
+ CFLAGS="-xCC $CFLAGS"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-xO" 2> /dev/null`" ; then
+ CFLAGS="-xO2 $CFLAGS"
+ fi
+ esac
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define SMARTMONTOOLS_BUILD_HOST "${host}"
+_ACEOF
+
+
+
+
+ ac_config_files="$ac_config_files Makefile examplescripts/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${SMARTD_SUFFIX_TRUE}" && test -z "${SMARTD_SUFFIX_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"SMARTD_SUFFIX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"SMARTD_SUFFIX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${OS_DARWIN_TRUE}" && test -z "${OS_DARWIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"OS_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"OS_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${OS_SOLARIS_TRUE}" && test -z "${OS_SOLARIS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"OS_SOLARIS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"OS_SOLARIS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${OS_WIN32_MINGW_TRUE}" && test -z "${OS_WIN32_MINGW_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"OS_WIN32_MINGW\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"OS_WIN32_MINGW\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by smartmontools $as_me 5.36, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+smartmontools config.status 5.36
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "examplescripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES examplescripts/Makefile" ;;
+ "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CYGPATH_W@,$CYGPATH_W,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@ACLOCAL@,$ACLOCAL,;t t
+s,@AUTOCONF@,$AUTOCONF,;t t
+s,@AUTOMAKE@,$AUTOMAKE,;t t
+s,@AUTOHEADER@,$AUTOHEADER,;t t
+s,@MAKEINFO@,$MAKEINFO,;t t
+s,@install_sh@,$install_sh,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s,@mkdir_p@,$mkdir_p,;t t
+s,@AWK@,$AWK,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@am__leading_dot@,$am__leading_dot,;t t
+s,@AMTAR@,$AMTAR,;t t
+s,@am__tar@,$am__tar,;t t
+s,@am__untar@,$am__untar,;t t
+s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
+s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
+s,@MAINT@,$MAINT,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@DEPDIR@,$DEPDIR,;t t
+s,@am__include@,$am__include,;t t
+s,@am__quote@,$am__quote,;t t
+s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s,@CCDEPMODE@,$CCDEPMODE,;t t
+s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s,@CCAS@,$CCAS,;t t
+s,@CCASFLAGS@,$CCASFLAGS,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@libc_have_working_snprintf@,$libc_have_working_snprintf,;t t
+s,@gcc_have_attr_packed@,$gcc_have_attr_packed,;t t
+s,@ASFLAGS@,$ASFLAGS,;t t
+s,@exampledir@,$exampledir,;t t
+s,@initddir@,$initddir,;t t
+s,@docdir@,$docdir,;t t
+s,@smartd_suffix@,$smartd_suffix,;t t
+s,@SMARTD_SUFFIX_TRUE@,$SMARTD_SUFFIX_TRUE,;t t
+s,@SMARTD_SUFFIX_FALSE@,$SMARTD_SUFFIX_FALSE,;t t
+s,@releaseversion@,$releaseversion,;t t
+s,@smartmontools_release_date@,$smartmontools_release_date,;t t
+s,@smartmontools_release_time@,$smartmontools_release_time,;t t
+s,@os_deps@,$os_deps,;t t
+s,@os_libs@,$os_libs,;t t
+s,@OS_DARWIN_TRUE@,$OS_DARWIN_TRUE,;t t
+s,@OS_DARWIN_FALSE@,$OS_DARWIN_FALSE,;t t
+s,@OS_SOLARIS_TRUE@,$OS_SOLARIS_TRUE,;t t
+s,@OS_SOLARIS_FALSE@,$OS_SOLARIS_FALSE,;t t
+s,@OS_WIN32_MINGW_TRUE@,$OS_WIN32_MINGW_TRUE,;t t
+s,@OS_WIN32_MINGW_FALSE@,$OS_WIN32_MINGW_FALSE,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+# Compute $ac_file's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $ac_file | $ac_file:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X$ac_file : 'X\(//\)[^/]' \| \
+ X$ac_file : 'X\(//\)$' \| \
+ X$ac_file : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p $dirpart/$fdir
+ else
+ as_dir=$dirpart/$fdir
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
--- /dev/null
+#
+# $Id: configure.in,v 1.114 2006/04/12 17:39:32 ballen4705 Exp $
+#
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.50)
+AC_INIT(smartmontools, 5.36, 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.114 2006/04/12 17:39:32 ballen4705 Exp $'`
+smartmontools_release_date=2006/04/12
+smartmontools_release_time="17:39:01 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_HEADERS([locale.h])
+AC_CHECK_HEADERS([getopt.h])
+AC_CHECK_HEADERS([dev/ata/atavar.h])
+AC_CHECK_HEADERS([netdb.h])
+dnl we need [u]int64_t and friends.
+AC_CHECK_HEADERS([inttypes.h]) dnl C99, UNIX98, solaris 2.6+
+AC_CHECK_HEADERS([stdint.h]) dnl C99
+AC_CHECK_HEADERS([sys/inttypes.h]) dnl pre-UNIX98
+AC_CHECK_HEADERS([sys/int_types.h]) dnl pre-UNIX98, solaris 2.6+
+dnl Check for FreeBSD twe include files...currently missing on 5.2, but should be there
+AC_CHECK_HEADERS([sys/tweio.h])
+AC_CHECK_HEADERS([sys/twereg.h])
+dnl Check for FreeBSD twa include files...
+AC_CHECK_HEADERS([sys/tw_osl_ioctl.h])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_CHECK_TYPES([int64_t, uint64_t])
+
+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])
+
+# Check whether snprintf appends null char and returns expected length on overflow
+AH_TEMPLATE(HAVE_WORKING_SNPRINTF, [Define to 1 if the `snprintf' function is sane])
+AC_MSG_CHECKING([for working snprintf])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[ char buf[]="ABCDEFGHI";
+ int i=snprintf(buf,8,"12345678"); return !(!buf[7] && i==8); ]])],
+ [libc_have_working_snprintf=yes], [libc_have_working_snprintf=no])
+AC_SUBST(libc_have_working_snprintf)
+if test "$libc_have_working_snprintf" = "yes"; then
+ AC_DEFINE(HAVE_WORKING_SNPRINTF)
+fi
+AC_MSG_RESULT([$libc_have_working_snprintf])
+
+# check for __attribute__((packed))
+AH_TEMPLATE(HAVE_ATTR_PACKED, [Define to 1 if C compiler supports __attribute__((packed))])
+AC_MSG_CHECKING([whether C compiler supports __attribute__((packed))])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [[struct a { int b; } __attribute__((packed));]])],
+ [gcc_have_attr_packed=yes], [gcc_have_attr_packed=no])
+AC_SUBST(gcc_have_attr_packed)
+if test "$gcc_have_attr_packed" = "yes"; then
+ AC_DEFINE(HAVE_ATTR_PACKED)
+fi
+AC_MSG_RESULT([$gcc_have_attr_packed])
+
+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']) ;;
+ *-*-openbsd*)
+ AC_SUBST([os_deps], ['os_openbsd.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'])
+ 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
+
+# Define symbols for optional functions in OS specific module
+case "${os_deps}" in
+ os_win32*)
+ AC_DEFINE(HAVE_ATA_IDENTIFY_IS_CACHED, 1, [Define to 1 if you have the `ata_identify_is_cached' function in os_*.c.]) ;;
+esac
+case "${os_deps}" in
+ os_win32*)
+ AC_DEFINE(HAVE_GET_OS_VERSION_STR, 1, [Define to 1 if you have the `get_os_version_str' function in os_*.c.]) ;;
+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)
+AC_PROG_MAKE_SET
--- /dev/null
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2004-05-31.23
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+# 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.
+
+# 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit 0
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit 0
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # Dependencies are output in .lo.d with libtool 1.4.
+ # With libtool 1.5 they are output both in $dir.libs/$base.o.d
+ # and in $dir.libs/$base.o.d and $dir$base.o.d. We process the
+ # latter, because the former will be cleaned when $dir.libs is
+ # erased.
+ tmpdepfile1="$dir.libs/$base.lo.d"
+ tmpdepfile2="$dir$base.o.d"
+ tmpdepfile3="$dir.libs/$base.d"
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1="$dir$base.o.d"
+ tmpdepfile2="$dir$base.d"
+ tmpdepfile3="$dir$base.d"
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile1"; then
+ tmpdepfile="$tmpdepfile1"
+ elif test -f "$tmpdepfile2"; then
+ tmpdepfile="$tmpdepfile2"
+ else
+ tmpdepfile="$tmpdepfile3"
+ fi
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
--- /dev/null
+#!/bin/bash
+#
+# This is a script from the smartmontools examplescripts/ directory.
+# It can be used as an argument to the -M exec Directive in
+# /etc/smartd.conf, in a line like
+# -m root@localhost -M exec /path/to/this/file
+#
+# Please see man 8 smartd or man 5 smartd.conf for further
+# information.
+#
+# $Id: Example1,v 1.7 2004/08/29 02:33:17 ballen4705 Exp $
+
+# Save standard input into a temp file
+cat > /root/tempfile
+
+# Echo command line arguments into temp file
+echo "Command line argument 1:" >> /root/tempfile
+echo $1 >> /root/tempfile
+echo "Command line argument 2:" >> /root/tempfile
+echo $2 >> /root/tempfile
+echo "Command line argument 3:" >> /root/tempfile
+echo $3 >> /root/tempfile
+
+# Echo environment variables into a temp file
+echo "Variables are": >> /root/tempfile
+echo "$SMARTD_DEVICE" >> /root/tempfile
+echo "$SMARTD_DEVICESTRING" >> /root/tempfile
+echo "$SMARTD_DEVICETYPE" >> /root/tempfile
+echo "$SMARTD_MESSAGE" >> /root/tempfile
+echo "$SMARTD_FULLMESSAGE" >> /root/tempfile
+echo "$SMARTD_ADDRESS" >> /root/tempfile
+echo "$SMARTD_SUBJECT" >> /root/tempfile
+echo "$SMARTD_TFIRST" >> /root/tempfile
+echo "$SMARTD_TFIRSTEPOCH" >> /root/tempfile
+
+# Run smartctl -a and save output in temp file
+/usr/sbin/smartctl -a -d $SMARTD_DEVICETYPE $SMARTD_DEVICE >> /root/tempfile
+
+# Email the contents of the temp file. Solaris and other OSes
+# may need to use /bin/mailx not /bin/mail.
+/bin/mail -s "SMART errors detected on host: `hostname`" $SMARTD_ADDRESS < /root/tempfile
+
+# And exit
+exit 0
--- /dev/null
+#! /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
+
--- /dev/null
+#! /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
+
--- /dev/null
+## Process this file with automake to produce Makefile.in
+examplesdir=$(exampledir)
+
+examples_DATA = README
+
+examples_SCRIPTS = Example1 \
+ Example2 \
+ Example3
+
+EXTRA_DIST = $(examples_SCRIPTS)
--- /dev/null
+# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = examplescripts
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(examplesdir)" \
+ "$(DESTDIR)$(examplesdir)"
+examplesSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(examples_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+examplesDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(examples_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+ASFLAGS = @ASFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+OS_DARWIN_FALSE = @OS_DARWIN_FALSE@
+OS_DARWIN_TRUE = @OS_DARWIN_TRUE@
+OS_SOLARIS_FALSE = @OS_SOLARIS_FALSE@
+OS_SOLARIS_TRUE = @OS_SOLARIS_TRUE@
+OS_WIN32_MINGW_FALSE = @OS_WIN32_MINGW_FALSE@
+OS_WIN32_MINGW_TRUE = @OS_WIN32_MINGW_TRUE@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SMARTD_SUFFIX_FALSE = @SMARTD_SUFFIX_FALSE@
+SMARTD_SUFFIX_TRUE = @SMARTD_SUFFIX_TRUE@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+docdir = @docdir@
+exampledir = @exampledir@
+exec_prefix = @exec_prefix@
+gcc_have_attr_packed = @gcc_have_attr_packed@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+initddir = @initddir@
+install_sh = @install_sh@
+libc_have_working_snprintf = @libc_have_working_snprintf@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+os_deps = @os_deps@
+os_libs = @os_libs@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+releaseversion = @releaseversion@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+smartd_suffix = @smartd_suffix@
+smartmontools_release_date = @smartmontools_release_date@
+smartmontools_release_time = @smartmontools_release_time@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+examplesdir = $(exampledir)
+examples_DATA = README
+examples_SCRIPTS = Example1 \
+ Example2 \
+ Example3
+
+EXTRA_DIST = $(examples_SCRIPTS)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examplescripts/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign examplescripts/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-examplesSCRIPTS: $(examples_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(examplesdir)" || $(mkdir_p) "$(DESTDIR)$(examplesdir)"
+ @list='$(examples_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(examplesSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(examplesdir)/$$f'"; \
+ $(examplesSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(examplesdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-examplesSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(examples_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(examplesdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(examplesdir)/$$f"; \
+ done
+uninstall-info-am:
+install-examplesDATA: $(examples_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(examplesdir)" || $(mkdir_p) "$(DESTDIR)$(examplesdir)"
+ @list='$(examples_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(examplesDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(examplesdir)/$$f'"; \
+ $(examplesDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(examplesdir)/$$f"; \
+ done
+
+uninstall-examplesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(examples_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(examplesdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(examplesdir)/$$f"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(examplesdir)" "$(DESTDIR)$(examplesdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-examplesDATA install-examplesSCRIPTS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-examplesDATA uninstall-examplesSCRIPTS \
+ uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-examplesDATA install-examplesSCRIPTS install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-examplesDATA uninstall-examplesSCRIPTS \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+# Home page: http://smartmontools.sourceforge.net
+#
+# $Id: README,v 1.5 2006/04/12 14:54:28 ballen4705 Exp $
+#
+# Copyright (C) 2003-6 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 brief description to use below.
+
+The files contained in this directory are:
+
+Example1: appends values of $SMARTD_* environment variables and the output
+ of smartctl -a to the normal email message, and sends that
+ to the email address listed as the argument to the -m
+ Directive.
+
+Example2: Appends output of smartctl -a to the normal email message
+ and sends that to the email address listed as the argument
+ to the -m Directive.
+
+Example3: Uses wall(1) to send a warning message to all users, then powers
+ down the machine.
+
+
--- /dev/null
+/*
+ * extern.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.41 2006/04/12 14:54:28 ballen4705 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
--- /dev/null
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2004-10-22.00
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit 0;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit 0;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ test -n "$dir_arg$dstarg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ src=
+
+ if test -d "$dst"; then
+ mkdircmd=:
+ chmodcmd=
+ else
+ mkdircmd=$mkdirprog
+ fi
+ else
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dst=$dst/`basename "$src"`
+ fi
+ fi
+
+ # This sed command emulates the dirname command.
+ dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+
+ # Make sure that the destination directory exists.
+
+ # Skip lots of stat calls in the usual case.
+ if test ! -d "$dstdir"; then
+ defaultIFS='
+ '
+ IFS="${IFS-$defaultIFS}"
+
+ oIFS=$IFS
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+ shift
+ IFS=$oIFS
+
+ pathcomp=
+
+ while test $# -ne 0 ; do
+ pathcomp=$pathcomp$1
+ shift
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp"
+ # mkdir can fail with a `File exist' error in case several
+ # install-sh are creating the directory concurrently. This
+ # is OK.
+ test -d "$pathcomp" || exit
+ fi
+ pathcomp=$pathcomp/
+ done
+ fi
+
+ if test -n "$dir_arg"; then
+ $doit $mkdircmd "$dst" \
+ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+ else
+ dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Copy the file name to the temp name.
+ $doit $cpprog "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dstdir/$dstfile"; then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+ || {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+ }
+ }
+ fi || { (exit 1); exit; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+ (exit 0); exit
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
--- /dev/null
+/*
+ * int64.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-6 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.13 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+// 64 bit integer typedefs
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+#ifdef HAVE_SYS_INTTYPES_H
+#include <sys/inttypes.h>
+#else
+#ifdef HAVE_SYS_INT_TYPES_H
+#include <sys/int_types.h>
+#else
+#if defined(_WIN32) && defined(_MSC_VER)
+// for MSVC 6.0
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+// for systems with above includes missing (like ix86-pc-linux-gnulibc1),
+// default to GCC if types are undefined in types.h
+#include <sys/types.h>
+#ifndef HAVE_INT64_T
+typedef long long int64_t;
+#endif
+#ifndef HAVE_UINT64_T
+typedef unsigned long long uint64_t;
+#endif
+#endif // _WIN32 && _MSC_VER
+#endif // HAVE_SYS_INT_TYPES_H
+#endif // HAVE_SYS_INTTYPES_H
+#endif // HAVE_STDINT_H
+#endif // HAVE_INTTYPES_H
+
+// 64 bit integer format strings
+
+#if defined(_WIN32) && defined(_MSC_VER)
+// for MSVC 6.0
+#define PRId64 "I64d"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#endif // _WIN32 && _MSC_VER
+
+// If macros not defined in inttypes.h, fix here. Default is GCC
+// style
+#ifndef PRId64
+#define PRId64 "lld"
+#endif // ndef PRId64
+
+#ifndef PRIu64
+#define PRIu64 "llu"
+#endif // ndef PRIu64
+
+#ifndef PRIx64
+#define PRIx64 "llx"
+#endif // ndef PRIx64
+
+
+#if defined(_WIN32) && defined(_MSC_VER)
+// for MSVC 6.0: "unsigned __int64 -> double" conversion not implemented (why?-)
+__inline double uint64_to_double(uint64_t ull) {
+ return ((int64_t)ull >= 0 ? (double)(int64_t)ull :
+ ((double)(int64_t)(ull - 9223372036854775808UI64)) + 9223372036854775808.0);
+}
+#else
+#define uint64_to_double(ull) ((double)(ull))
+#endif // _WIN32 && _MSC_VER
+
+
+#endif // INT64_H
--- /dev/null
+/*
+ * knowndrives.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ * Address of support mailing list: smartmontools-support@lists.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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 "config.h"
+#include "int64.h"
+#include <stdio.h>
+#include "atacmds.h"
+#include "ataprint.h"
+#include "extern.h"
+#include "knowndrives.h"
+#include "utility.h" // includes <regex.h>
+
+const char *knowndrives_c_cvsid="$Id: knowndrives.c,v 1.139 2006/04/05 19:50:07 chrfranke 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", // ER60A46A firmware
+ "(IBM-|Hitachi )?IC35L0[12346]0AVER07",
+ "^ER60A46A$",
+ NULL, NULL, NULL, NULL
+ },
+ { "IBM Deskstar 60GXP series", // All other firmware
+ "(IBM-|Hitachi )?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][123468AG][OF]A[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
+ },
+ { NULL, // ExcelStor J240, J340, J360, J680, and J880
+ "^ExcelStor Technology J(24|34|36|68|88)0$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // Fujitsu M1623TAU
+ "^FUJITSU M1623TAU$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { "Fujitsu MHG and MHH series",
+ "^FUJITSU MH(G2102|H20(64|48|32))AT$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { "Fujitsu MHJ and MHK series",
+ "^FUJITSU MH[JK]....ATU?$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ 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)|153AH|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
+ },
+ { NULL, // Fujitsu MHN2300AT
+ "^FUJITSU MHN2300AT$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { NULL, // Fujitsu MHR2040AT
+ "^FUJITSU MHR2040AT$",
+ ".*", // Tested on 40BA
+ NULL,
+ vendoropts_Fujitsu_MHR2040AT,
+ NULL, NULL
+ },
+ { NULL, // Fujitsu MHR2020AT
+ "^FUJITSU MHR2020AT$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { "Fujitsu MHSxxxxAT family",
+ "^FUJITSU MHS20[6432]0AT( .)?$",
+ ".*",
+ NULL,
+ vendoropts_Fujitsu_MHS2020AT,
+ NULL, 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 MHT2xxxAT/MHU2100AT series",
+ "^FUJITSU MH(T20[23468]0AT( PL)?|U2100AT)$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { "Fujitsu MHTxxxxAH family",
+ "^FUJITSU MHT20[468]0AH$",
+ ".*",
+ NULL,
+ vendoropts_9_seconds,
+ NULL, NULL
+ },
+ { NULL, // Samsung SV4012H (known firmware)
+ "^SAMSUNG SV4012H$",
+ "^RM100-08$",
+ NULL,
+ vendoropts_Samsung_SV4012H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // Samsung SV4012H (all other firmware)
+ "^SAMSUNG SV4012H$",
+ ".*",
+ may_need_minus_F_disabled,
+ vendoropts_Samsung_SV4012H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // Samsung SV0412H (known firmware)
+ "^SAMSUNG SV0412H$",
+ "^SK100-01$",
+ NULL,
+ vendoropts_Samsung_SV1204H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // Samsung SV0412H (all other firmware)
+ "^SAMSUNG SV0412H$",
+ ".*",
+ may_need_minus_F_disabled,
+ vendoropts_Samsung_SV1204H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // Samsung SV1204H (known firmware)
+ "^SAMSUNG SV1204H$",
+ "^RK100-1[3-5]$",
+ NULL,
+ vendoropts_Samsung_SV1204H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // Samsung SV1204H (all other firmware)
+ "^SAMSUNG SV1204H$",
+ ".*",
+ may_need_minus_F_disabled,
+ vendoropts_Samsung_SV1204H,
+ specialpurpose_reverse_samsung,
+ same_as_minus_F
+ },
+ { NULL, // SAMSUNG SV0322A tested with FW JK200-35
+ "^SAMSUNG SV0322A$",
+ ".*",
+ NULL,
+ 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
+ },
+ {
+ NULL, // 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
+ },
+ { NULL, // All Samsung drives with '.*-25' firmware
+ "^SAMSUNG.*",
+ ".*-25$",
+ may_need_minus_F2_disabled,
+ vendoropts_Samsung_SV4012H,
+ specialpurpose_reverse_samsung2,
+ same_as_minus_F2
+ },
+ { NULL, // All Samsung drives with '.*-26 or later (currently to -39)' firmware
+ "^SAMSUNG.*",
+ ".*-(2[6789]|3[0-9])$",
+ NULL,
+ vendoropts_Samsung_SV4012H,
+ NULL,
+ 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 Fireball 3 family",
+ "^Maxtor 2F0[234]0[JL]0$",
+ ".*",
+ NULL,
+ vendoropts_9_minutes,
+ NULL, NULL
+ },
+ { "Maxtor DiamondMax 2160 Ultra ATA family",
+ "^Maxtor 8(2160D2|3228D3|3240D3|4320D4|6480D6|8400D8|8455D8)$",
+ ".*",
+ NULL,
+ vendoropts_9_minutes,
+ NULL, NULL
+ },
+ { "Maxtor DiamondMax 2880 Ultra ATA family",
+ "^Maxtor 9(0510D4|0576D4|0648D5|0720D5|0840D6|0845D6|0864D6|1008D7|1080D8|1152D8)$",
+ ".*",
+ NULL,
+ vendoropts_9_minutes,
+ 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,
+ vendoropts_Maxtor_4D080H4,
+ 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",
+ "^Maxtor 4D0(20H1|40H2|60H3|80H4)$",
+ ".*",
+ NULL,
+ vendoropts_Maxtor_4D080H4,
+ NULL, NULL
+ },
+ { "Maxtor DiamondMax 16 family",
+ "^Maxtor 4(R0[68]0[JL]0|R1[26]0L0|A160J0|R120L4)$",
+ ".*",
+ 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 17 VL family",
+ "^Maxtor 9(0431U1|0641U2|0871U2|1301U3|1741U4)$",
+ ".*",
+ 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 10 family",
+ "^Maxtor 6(B(30|25|20|16|12|08)0[MPRS]|L(100P|120[MP]|160M|200[MPRS]|250[RS]|300[RS]))0$",
+ ".*",
+ 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|30|32)0[JN]0$",
+ ".*",
+ NULL,
+ vendoropts_9_minutes,
+ NULL, 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
+ },
+ { "Hitachi Endurastar J4K20/N4K20 (formerly DK23FA-20J)",
+ "^(HITACHI_DK23FA-20J|HTA422020F9AT[JN]0)$",
+ ".*",
+ 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",
+ "^(IBM-|Hitachi )?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",
+ "^(IBM-|Hitachi )?IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "IBM/Hitachi Travelstar 40GNX family",
+ "^(IBM-|Hitachi )?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
+ },
+ { "Hitachi Travelstar 5K100 series",
+ "^HTS5410[1864]0G9(AT|SA)00$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Hitachi Travelstar 7K60",
+ "^HTS726060M9AT00$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Hitachi Travelstar E7K60 family",
+ "^HTE7260[46]0M9AT00$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "IBM/Hitachi Deskstar 120GXP family",
+ "^(IBM-)?IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "IBM/Hitachi Deskstar GXP-180 family",
+ "^(IBM-)?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 7K80 series",
+ "^(Hitachi )?HDS7280([48]0PLAT20|(40)?PLA320)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Hitachi Deskstar 7K250 series",
+ "^(Hitachi )?HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Hitachi Deskstar 7K400 series",
+ "^(Hitachi )?HDS724040KL(AT|SA)80$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK4025GAS
+ "^TOSHIBA MK4025GAS$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Toshiba 2.5\" HDD series", // TOSHIBA MK6021GAS [Bruce -- use for testing on laptop]
+ "^TOSHIBA MK6021GAS$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK6022GAX
+ "^TOSHIBA MK6022GAX$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK4019GAX/MK4019GAXB
+ "^TOSHIBA MK4019GAXB?$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK6409MAV
+ "^TOSHIBA MK6409MAV$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOS MK3019GAXB SUN30G
+ "^TOS MK3019GAXB SUN30G$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK2016GAP, MK2017GAP, MK2018GAP, MK2018GAS, MK2023GAS
+ "^TOSHIBA MK20(1[678]GAP|(18|23)GAS)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK4018GAS, MK4018GAP
+ "^TOSHIBA MK4018GA[SP]$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK3017GAP
+ "^TOSHIBA MK3017GAP$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // TOSHIBA MK8026GAX
+ "^TOSHIBA MK8026GAX$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Momentus family",
+ "^ST9(20|28|40|48)11A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Momentus 4200.2 Series",
+ "^ST9(100822|808210|60821|50212|402113|30219)A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Momentus 5400.2 series",
+ "^ST9(100823|808211|60822|408114|308110)A$",
+ ".*",
+ 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 U4 family",
+ "^ST3(2112|4311|6421|8421)A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate U8 family",
+ "^ST3(8410|4313|17221|13021)A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate U10 family",
+ "^ST3(20423|15323|10212)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|30011|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 5400.1",
+ "^ST340015A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Barracuda 7200.7 and 7200.7 Plus family",
+ "^ST3(200021A|200822AS?|16002[13]AS?|12002[26]AS?|1[26]0827AS|8001[13]AS?|80817AS|60014A|40014AS?)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Barracuda 7200.8 family",
+ "^ST3(400832|300831|250823|200826)AS?$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Seagate Medalist 17240, 13030, 10231, 8420, and 4310",
+ "^ST3(17240|13030|10231|8420|4310)A$",
+ ".*",
+ 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...?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...BA$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // Western Digital Caviar AC12500, AC14300, AC23200, AC24300, AC25100,
+ // AC36400, AC38400
+ "^WDC AC(125|143|232|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|30|32)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 RE Serial ATA series",
+ "^WDC WD((12|16|25|32)00SD|4000YR)-.*$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Western Digital Raptor family",
+ "^WDC WD(360|740)GD",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM BIGFOOT TS10.0A
+ "^QUANTUM BIGFOOT TS10.0A$",
+ ".*",
+ NULL, 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
+ },
+ { NULL, // QUANTUM FIREBALL CX10.2A
+ "^QUANTUM FIREBALL CX10.2A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Quantum Fireball Plus LM series",
+ "^QUANTUM FIREBALLP LM(10.2|15|20.5|30)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { "Quantum Fireball CR series",
+ "^QUANTUM FIREBALL CR(4.3|8.4)A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALLP AS10.2, AS20.5, and AS40.0
+ "^QUANTUM FIREBALLP AS(10.2|20.5|40.0)$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALL EX6.4A
+ "^QUANTUM FIREBALL EX6.4A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALL ST3.2A
+ "^QUANTUM FIREBALL ST3.2A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALL EX3.2A
+ "^QUANTUM FIREBALL EX3.2A$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALLP KX27.3
+ "^QUANTUM FIREBALLP KX27.3$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ { NULL, // QUANTUM FIREBALLP KA10.1
+ "^QUANTUM FIREBALLP KA10.1$",
+ ".*",
+ NULL, NULL, NULL, NULL
+ },
+ /*------------------------------------------------------------
+ * End of table. Do not add entries below this marker.
+ *------------------------------------------------------------ */
+ {NULL, 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 : "");
+ pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", drivetable->modelfamily ?
+ drivetable->modelfamily : "");
+
+ // 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;
+}
+
+// Shows all presets for drives in knowndrives[].
+// Returns <0 on syntax error in regular expressions.
+int showallpresets(void){
+ int i;
+ int rc = 0;
+ regex_t regex;
+
+ // 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");
+ }
+
+ // Check all regular expressions
+ for (i=0; knowndrives[i].modelregexp; i++){
+ if (compileregex(®ex, knowndrives[i].modelregexp, REG_EXTENDED))
+ rc = -1;
+ if (knowndrives[i].firmwareregexp) {
+ if (compileregex(®ex, knowndrives[i].firmwareregexp, REG_EXTENDED))
+ rc = -1;
+ }
+ }
+ pout("For information about adding a drive to the database see the FAQ on the\n");
+ pout("smartmontools home page: " PACKAGE_HOMEPAGE "\n");
+ return rc;
+}
+
+// Shows all matching presets for a drive in knowndrives[].
+// Returns # matching entries.
+int showmatchingpresets(const char *model, const char *firmware){
+ int i;
+ int cnt = 0;
+ const char * firmwaremsg = (firmware ? firmware : "(any)");
+ regex_t regex;
+
+ for (i=0; knowndrives[i].modelregexp; i++){
+ if (i > 0)
+ regfree(®ex);
+ if (compileregex(®ex, knowndrives[i].modelregexp, REG_EXTENDED))
+ continue;
+ if (regexec(®ex, model, 0, NULL, 0))
+ continue;
+ if (firmware && knowndrives[i].firmwareregexp) {
+ regfree(®ex);
+ if (compileregex(®ex, knowndrives[i].firmwareregexp, REG_EXTENDED))
+ continue;
+ if (regexec(®ex, firmware, 0, NULL, 0))
+ continue;
+ }
+ if (++cnt == 1)
+ pout("Drive found in smartmontools Database. Drive identity strings:\n"
+ "%-*s %s\n"
+ "%-*s %s\n"
+ "match smartmontools Drive Database entry:\n",
+ TABLEPRINTWIDTH, "MODEL:", model, TABLEPRINTWIDTH, "FIRMWARE:", firmwaremsg);
+ else if (cnt == 2)
+ pout("and match these additional entries:\n");
+ showonepreset(&knowndrives[i]);
+ pout("\n");
+ }
+ regfree(®ex);
+ if (cnt == 0)
+ pout("No presets are defined for this drive. Its identity strings:\n"
+ "MODEL: %s\n"
+ "FIRMWARE: %s\n"
+ "do not match any of the known regular expressions.\n",
+ model, firmwaremsg);
+ return cnt;
+}
+
+// Shows the presets (if any) that are available for the given drive.
+void 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;
+}
--- /dev/null
+/*
+ * knowndrives.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ * Address of support mailing list: smartmontools-support@lists.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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.16 2006/04/05 19:50:07 chrfranke Exp $\n"
+
+/* Structure used to store settings for specific drives in knowndrives[]. The
+ * elements are used in the following ways:
+ *
+ * modelfamily Informal string about the model family/series of a
+ * device. Set to NULL if no info (apart from device id)
+ * known.
+ * 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 modelfamily;
+ 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[].
+// Returns <0 on syntax error in regular expressions.
+int showallpresets(void);
+
+// Shows all matching presets for a drive in knowndrives[].
+// Returns # matching entries.
+int showmatchingpresets(const char *model, const char *firmware);
+
+// 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
--- /dev/null
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2004-09-07.08
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# 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.
+
+# 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit 0
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit 0
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case "$1" in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
--- /dev/null
+/*
+ * os_darwin.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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 "config.h"
+#include "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+
+#include "os_darwin.h"
+
+// Needed by '-V' option (CVS versioning) of smartd/smartctl
+const char *os_XXXX_c_cvsid="$Id: os_darwin.c,v 1.13 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+
+// Print examples for smartctl.
+void print_smartctl_examples(){
+ printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
+ printf(
+ " smartctl -a disk0 (Prints all SMART information)\n\n"
+ " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n"
+#ifdef HAVE_GETOPT_LONG
+ " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n"
+ " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n"
+ " (Prints Self-Test & Attribute errors)\n\n"
+#else
+ " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n"
+ " smartctl -A -l selftest -q errorsonly /dev/disk0\n"
+ " (Prints Self-Test & Attribute errors)\n\n"
+#endif
+ " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n"
+ " (You can use IOService: ...)\n\n"
+ " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n"
+ " (... Or IODeviceTree:)\n"
+ );
+ return;
+}
+
+// tries to guess device type given the name (a path). See utility.h
+// for return values.
+int guess_device_type (const char* dev_name) {
+ // Only ATA is supported right now, so that's what it'd better be.
+ 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 marvell_command_interface(int fd, smart_command_set command,
+ int select, char *data)
+{ return -1; }
+
+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;
+}
--- /dev/null
+/*
+ * os_generic.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 Geoff Keating <geoffk@geoffk.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example COPYING); if not, write to the Free
+ * Software Foundation, Inc., 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_DARWIN_H_CVSID "$Id: os_darwin.h,v 1.5 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+// There isn't actually any content here yet.
+
+#endif /* OS_DARWIN_H_ */
--- /dev/null
+<?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>
--- /dev/null
+#!/bin/sh
+
+# Darwin init file for smartd
+#
+# Home page of code is: http://smartmontools.sourceforge.net
+#
+# Copyright (C) 2004-6 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.4 2006/04/12 14:54:28 ballen4705 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"
--- /dev/null
+{
+ Description = "SMART disk monitoring";
+ Provides = ("SMART");
+ Requires = ("System Log");
+}
--- /dev/null
+/*
+ * os_freebsd.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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 <fcntl.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 <stddef.h>
+
+
+#include "config.h"
+#include "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+#include "os_freebsd.h"
+
+static const char *filenameandversion="$Id: os_freebsd.c,v 1.49 2006/04/12 14:54:28 ballen4705 Exp $";
+
+const char *os_XXXX_c_cvsid="$Id: os_freebsd.c,v 1.49 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_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"
+ " (Prints Self-Test & Attribute errors)\n\n"
+ " smartctl -a --device=3ware,2 /dev/twa0\n"
+ " smartctl -a --device=3ware,2 /dev/twe0\n"
+ " (Prints all SMART information for ATA disk on\n"
+ " third port of first 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/twa0\n"
+ " smartctl -a -d 3ware,2 /dev/twe0\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 __unused) {
+ 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) {
+#ifdef IOCATAREQUEST
+ if ((fdchan->device = open(dev,O_RDONLY))<0) {
+#else
+ if ((fdchan->atacommand = open("/dev/ata",O_RDWR))<0) {
+#endif
+ 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);
+#ifdef IOCATAREQUEST
+ if ((fdchan->device = open(buf,O_RDWR))<0) {
+#else
+ if ((fdchan->atacommand = open(buf,O_RDWR))<0) {
+#endif
+ int myerror = errno; // preserver across free call
+ free(fdchan);
+ errno=myerror;
+ return -1;
+ }
+ }
+
+ if (parse_ok == CONTROLLER_3WARE_9000_CHAR) {
+ char buf[512];
+ sprintf(buf,"/dev/twa%d",fdchan->device);
+#ifdef IOCATAREQUEST
+ if ((fdchan->device = open(buf,O_RDWR))<0) {
+#else
+ if ((fdchan->atacommand = open(buf,O_RDWR))<0) {
+#endif
+ 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
+#ifdef IOCATAREQUEST
+ if (fdchan->device)
+ failed=close(fdchan->device);
+#else
+ if (fdchan->atacommand)
+ failed=close(fdchan->atacommand);
+#endif
+
+ 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_DISK_3WARE 2
+#define BAD_KERNEL 3
+#define MAX_MSG 3
+
+// Utility function for printing warnings
+void printwarning(int msgNo, const char* extra) {
+ static int printed[] = {0,0,0,0};
+ static const char* message[]={
+ "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n",
+
+ "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
+
+ "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
+
+ "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
+ };
+
+ if (msgNo >= 0 && msgNo <= MAX_MSG) {
+ if (!printed[msgNo]) {
+ printed[msgNo] = 1;
+ pout("%s", message[msgNo]);
+ if (extra)
+ pout("%s",extra);
+ }
+ }
+ return;
+}
+
+
+// Interface to ATA devices. See os_linux.c
+int marvell_command_interface(int fd __unused, smart_command_set command __unused, int select __unused, char *data __unused) {
+ return -1;
+}
+
+int ata_command_interface(int fd, smart_command_set command, int select, char *data) {
+#if !defined(ATAREQUEST) && !defined(IOCATAREQUEST)
+ // 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;
+#ifdef IOCATAREQUEST
+ struct ata_ioc_request request;
+#else
+ struct ata_cmd iocmd;
+#endif
+ unsigned char buff[512];
+
+ // check that "file descriptor" is valid
+ if (isnotopen(&fd,&con))
+ return -1;
+
+ bzero(buff,512);
+
+#ifdef IOCATAREQUEST
+ bzero(&request,sizeof(struct ata_ioc_request));
+#else
+ bzero(&iocmd,sizeof(struct ata_cmd));
+#endif
+ bzero(buff,512);
+
+#ifndef IOCATAREQUEST
+ iocmd.cmd=ATAREQUEST;
+ iocmd.channel=con->channel;
+ iocmd.device=con->device;
+#define request iocmd.u.request
+#endif
+
+ request.u.ata.command=ATA_SMART_CMD;
+ request.timeout=600;
+ switch (command){
+ case READ_VALUES:
+ request.u.ata.feature=ATA_SMART_READ_VALUES;
+ request.u.ata.lba=0xc24f<<8;
+ request.flags=ATA_CMD_READ;
+ request.data=buff;
+ request.count=512;
+ copydata=1;
+ break;
+ case READ_THRESHOLDS:
+ request.u.ata.feature=ATA_SMART_READ_THRESHOLDS;
+ request.u.ata.count=1;
+ request.u.ata.lba=1|(0xc24f<<8);
+ request.flags=ATA_CMD_READ;
+ request.data=buff;
+ request.count=512;
+ copydata=1;
+ break;
+ case READ_LOG:
+ request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR;
+ request.u.ata.lba=select|(0xc24f<<8);
+ request.u.ata.count=1;
+ request.flags=ATA_CMD_READ;
+ request.data=buff;
+ request.count=512;
+ copydata=1;
+ break;
+ case IDENTIFY:
+ request.u.ata.command=ATA_IDENTIFY_DEVICE;
+ request.flags=ATA_CMD_READ;
+ request.data=buff;
+ request.count=512;
+ copydata=1;
+ break;
+ case PIDENTIFY:
+ request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE;
+ request.flags=ATA_CMD_READ;
+ request.data=buff;
+ request.count=512;
+ copydata=1;
+ break;
+ case ENABLE:
+ request.u.ata.feature=ATA_SMART_ENABLE;
+ request.u.ata.lba=0xc24f<<8;
+ request.flags=ATA_CMD_CONTROL;
+ break;
+ case DISABLE:
+ request.u.ata.feature=ATA_SMART_DISABLE;
+ request.u.ata.lba=0xc24f<<8;
+ request.flags=ATA_CMD_CONTROL;
+ break;
+ case AUTO_OFFLINE:
+ // NOTE: According to ATAPI 4 and UP, this command is obsolete
+ request.u.ata.feature=ATA_SMART_AUTO_OFFLINE;
+ request.u.ata.lba=select|(0xc24f<<8);
+ request.flags=ATA_CMD_CONTROL;
+ break;
+ case AUTOSAVE:
+ request.u.ata.feature=ATA_SMART_AUTOSAVE;
+ request.u.ata.count=0xf1; // to enable autosave
+ request.u.ata.lba=0xc24f<<8;
+ request.flags=ATA_CMD_CONTROL;
+ break;
+ case IMMEDIATE_OFFLINE:
+ request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE;
+ request.u.ata.lba = select|(0xc24f<<8); // put test in sector
+ 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.
+ request.u.ata.feature=ATA_SMART_STATUS;
+ request.u.ata.lba=0xc24f<<8;
+ 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;
+
+#ifdef IOCATAREQUEST
+ if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
+#else
+ if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
+#endif
+ return -1;
+
+#if __FreeBSD_version < 502000
+ printwarning(NO_RETURN,NULL);
+#endif
+
+ high = (request.u.ata.lba >> 16) & 0xff;
+ low = (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)request.u.ata.command,
+ (int)request.u.ata.feature,
+ (int)request.u.ata.count,
+ (int)((request.u.ata.lba) & 0xff),
+ (int)((request.u.ata.lba>>8) & 0xff),
+ (int)((request.u.ata.lba>>16) & 0xff),
+ (int)request.error);
+ printwarning(BAD_SMART,buf);
+ return 0;
+ }
+
+#ifdef IOCATAREQUEST
+ if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
+#else
+ if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
+#endif
+ {
+ 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
+
+#define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
+#define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
+#define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
+
+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;
+ struct twe_usercommand* cmd_twe = NULL;
+ TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
+ TWE_Command_ATA* ata = NULL;
+
+ // Used by both the SCSI and char interfaces
+ char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
+
+ if (disknum < 0) {
+ printwarning(NO_DISK_3WARE,NULL);
+ return -1;
+ }
+
+ // check that "file descriptor" is valid
+ if (isnotopen(&fd,&con))
+ return -1;
+
+ memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
+
+ if (escalade_type==CONTROLLER_3WARE_9000_CHAR) {
+ cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
+ cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
+ cmd_twa->driver_pkt.buffer_length = 512;
+ ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
+ } else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) {
+ cmd_twe = (struct twe_usercommand*)ioctl_buffer;
+ ata = &cmd_twe->tu_command.ata;
+ } else {
+ pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
+ "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum);
+ errno=ENOSYS;
+ return -1;
+ }
+
+ ata->opcode = TWE_OP_ATA_PASSTHROUGH;
+
+ // Same for (almost) all commands - but some reset below
+ ata->request_id = 0xFF;
+ ata->unit = disknum;
+ ata->host_id = 0;
+ ata->status = 0;
+ ata->flags = 0x1;
+ ata->drive_head = 0x0;
+ ata->sector_num = 0;
+
+ // All SMART commands use this CL/CH signature. These are magic
+ // values from the ATA specifications.
+ ata->cylinder_lo = 0x4F;
+ ata->cylinder_hi = 0xC2;
+
+ // SMART ATA COMMAND REGISTER value
+ 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;
+ if (escalade_type==CONTROLLER_3WARE_678K_CHAR) {
+ cmd_twe->tu_data = data;
+ cmd_twe->tu_size = 512;
+ }
+ ata->sgl_offset = 0x5;
+ ata->size = 0x5;
+ ata->param = 0xD;
+ 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)
+ // ata->size++;
+ }
+ else {
+ // Non data command -- but doesn't use large sector
+ // count register values.
+ ata->sgl_offset = 0x0;
+ ata->size = 0x5;
+ ata->param = 0x8;
+ ata->sector_count = 0x0;
+ }
+
+ // Now set ATA registers depending upon command
+ switch (command){
+ case CHECK_POWER_MODE:
+ ata->command = ATA_CHECK_POWER_MODE;
+ ata->features = 0;
+ ata->cylinder_lo = 0;
+ ata->cylinder_hi = 0;
+ break;
+ case READ_VALUES:
+ ata->features = ATA_SMART_READ_VALUES;
+ break;
+ case READ_THRESHOLDS:
+ ata->features = ATA_SMART_READ_THRESHOLDS;
+ break;
+ case READ_LOG:
+ ata->features = ATA_SMART_READ_LOG_SECTOR;
+ // log number to return
+ ata->sector_num = select;
+ break;
+ case WRITE_LOG:
+ readdata=0;
+ ata->features = ATA_SMART_WRITE_LOG_SECTOR;
+ ata->sector_count = 1;
+ ata->sector_num = select;
+ ata->param = 0xF; // PIO data write
+ break;
+ case IDENTIFY:
+ // ATA IDENTIFY DEVICE
+ ata->command = ATA_IDENTIFY_DEVICE;
+ ata->features = 0;
+ ata->cylinder_lo = 0;
+ 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:
+ ata->features = ATA_SMART_ENABLE;
+ break;
+ case DISABLE:
+ ata->features = ATA_SMART_DISABLE;
+ break;
+ case AUTO_OFFLINE:
+ ata->features = ATA_SMART_AUTO_OFFLINE;
+ // Enable or disable?
+ ata->sector_count = select;
+ break;
+ case AUTOSAVE:
+ ata->features = ATA_SMART_AUTOSAVE;
+ // Enable or disable?
+ ata->sector_count = select;
+ break;
+ case IMMEDIATE_OFFLINE:
+ ata->features = ATA_SMART_IMMEDIATE_OFFLINE;
+ // What test type to run?
+ ata->sector_num = select;
+ break;
+ case STATUS_CHECK:
+ 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.
+ 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()
+ if (escalade_type==CONTROLLER_3WARE_9000_CHAR) {
+#ifdef IOCATAREQUEST
+ ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
+#else
+ ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
+#endif
+ } else {
+#ifdef IOCATAREQUEST
+ ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe);
+#else
+ ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe);
+#endif
+ }
+
+ // 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:
+ // - ata->status contains the 3ware controller STATUS
+ // - ata->command contains the ATA STATUS register
+ // - ata->features contains the ATA ERROR register
+ //
+ // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
+ // If bit 0 (error bit) is set, then ATA ERROR register is valid.
+ // While we *might* decode the ATA ERROR register, at the moment it
+ // doesn't make much sense: we don't care in detail why the error
+ // happened.
+
+ if (ata->status || (ata->command & 0x21)) {
+ pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",ata->status,ata->command,ata->flags);
+ 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, cmd_twa->pdata, 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=ata->cylinder_lo;
+ unsigned short cyl_hi=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 *)&(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_tw_channel_unit (const char* name, int* unit, int* dev) {
+ const char *p;
+
+ /* device node sanity check */
+ for (p = name + 3; *p; p++)
+ if (*p < '0' || *p > '9')
+ return -1;
+ if (strlen(name) > 4 && *(name + 3) == '0')
+ return -1;
+
+ if (dev != NULL)
+ *dev=atoi(name + 3);
+
+ /* no need for unit number */
+ if (unit != NULL)
+ *unit=0;
+ return 0;
+}
+
+
+#ifndef IOCATAREQUEST
+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
+}
+#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_ctrl = "twe";
+static const char * fbsd_dev_twa_ctrl = "twa";
+
+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))) {
+#ifndef IOCATAREQUEST
+ if (chan != NULL) {
+ if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+ return CONTROLLER_UNKNOWN;
+ }
+ }
+#endif
+ 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_twa_ctrl,dev_name,
+ strlen(fbsd_dev_twa_ctrl))) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+ return CONTROLLER_UNKNOWN;
+ }
+ }
+ else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
+ return CONTROLLER_UNKNOWN;
+ }
+ return CONTROLLER_3WARE_9000_CHAR;
+ }
+
+ if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
+ strlen(fbsd_dev_twe_ctrl))) {
+ if (chan != NULL) {
+ if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
+ return CONTROLLER_UNKNOWN;
+ }
+ }
+ else if (get_tw_channel_unit(dev_name,NULL,NULL)<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;
+}
--- /dev/null
+/*
+ * os_freebsd.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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/
+ *
+ */
+
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Copyright (c) 2004-05 Applied Micro Circuits Corporation.
+ * Copyright (c) 2004-05 Vinod Kashyap
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef OS_FREEBSD_H_
+#define OS_FREEBSD_H_
+
+#define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h,v 1.20 2006/04/12 14:54:28 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 <sys/twereg.h>
+#else
+/**
+ * The following cut out of twereg.h
+ *
+ */
+#if __FreeBSD_version < 500040
+#define __packed __attribute__((__packed__))
+#endif
+
+#define TWE_MAX_SGL_LENGTH 62
+#define TWE_MAX_ATA_SGL_LENGTH 60
+#define TWE_OP_ATA_PASSTHROUGH 0x11
+
+/* scatter/gather list entry */
+typedef struct
+{
+ u_int32_t address;
+ u_int32_t length;
+} __packed TWE_SG_Entry;
+
+typedef struct {
+ u_int8_t opcode:5; /* TWE_OP_INITCONNECTION */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t res2:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int16_t message_credits;
+ u_int32_t response_queue_pointer;
+} __packed TWE_Command_INITCONNECTION;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_READ/TWE_OP_WRITE */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int16_t block_count;
+ u_int32_t lba;
+ TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH];
+} __packed TWE_Command_IO;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_HOTSWAP */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int8_t action;
+#define TWE_OP_HOTSWAP_REMOVE 0x00 /* remove assumed-degraded unit */
+#define TWE_OP_HOTSWAP_ADD_CBOD 0x01 /* add CBOD to empty port */
+#define TWE_OP_HOTSWAP_ADD_SPARE 0x02 /* add spare to empty port */
+ u_int8_t aport;
+} __packed TWE_Command_HOTSWAP;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_SETATAFEATURE */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int8_t feature;
+#define TWE_OP_SETATAFEATURE_WCE 0x02
+#define TWE_OP_SETATAFEATURE_DIS_WCE 0x82
+ u_int8_t feature_mode;
+ u_int16_t all_units;
+ u_int16_t persistence;
+} __packed TWE_Command_SETATAFEATURE;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_CHECKSTATUS */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t res2:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int16_t target_status; /* set low byte to target request's ID */
+} __packed TWE_Command_CHECKSTATUS;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_GETPARAM, TWE_OP_SETPARAM */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int16_t param_count;
+ TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH];
+} __packed TWE_Command_PARAM;
+
+typedef struct
+{
+ u_int8_t opcode:5; /* TWE_OP_REBUILDUNIT */
+ u_int8_t res1:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t src_unit:4;
+ u_int8_t host_id:4;
+ u_int8_t status;
+ u_int8_t flags;
+ u_int8_t action:7;
+#define TWE_OP_REBUILDUNIT_NOP 0
+#define TWE_OP_REBUILDUNIT_STOP 2 /* stop all rebuilds */
+#define TWE_OP_REBUILDUNIT_START 4 /* start rebuild with lowest unit */
+#define TWE_OP_REBUILDUNIT_STARTUNIT 5 /* rebuild src_unit (not supported) */
+ u_int8_t cs:1; /* request state change on src_unit */
+ u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */
+} __packed TWE_Command_REBUILDUNIT;
+
+typedef struct
+{
+ u_int8_t opcode:5;
+ u_int8_t sgl_offset:3;
+ u_int8_t size;
+ u_int8_t request_id;
+ u_int8_t unit: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;
+
+#endif
+
+#ifdef HAVE_SYS_TWEIO_H
+#include <sys/tweio.h>
+#else
+/*
+ * Following cut out of tweio.h
+ *
+ */
+/*
+ * User-space command
+ *
+ * Note that the command's scatter/gather list will be computed by the
+ * driver, and cannot be filled in by the consumer.
+ */
+struct twe_usercommand {
+ TWE_Command tu_command; /* command ready for the controller */
+ void *tu_data; /* pointer to data in userspace */
+ size_t tu_size; /* userspace data length */
+};
+
+#define TWEIO_COMMAND _IOWR('T', 100, struct twe_usercommand)
+
+#endif
+
+#ifdef HAVE_SYS_TW_OSL_IOCTL_H
+#include <sys/tw_osl_ioctl.h>
+#else
+/*
+ * Following cut out of tw_osl_types.h
+ *
+ */
+
+typedef void TW_VOID;
+typedef char TW_INT8;
+typedef unsigned char TW_UINT8;
+typedef short TW_INT16;
+typedef unsigned short TW_UINT16;
+typedef int TW_INT32;
+typedef unsigned int TW_UINT32;
+typedef long long TW_INT64;
+typedef unsigned long long TW_UINT64;
+
+/*
+ * Following cut out of tw_cl_share.h
+ *
+ */
+
+#pragma pack(1)
+
+struct tw_cl_event_packet {
+ TW_UINT32 sequence_id;
+ TW_UINT32 time_stamp_sec;
+ TW_UINT16 aen_code;
+ TW_UINT8 severity;
+ TW_UINT8 retrieved;
+ TW_UINT8 repeat_count;
+ TW_UINT8 parameter_len;
+ TW_UINT8 parameter_data[98];
+ TW_UINT32 event_src;
+ TW_UINT8 severity_str[20];
+};
+
+#pragma pack()
+
+/*
+ * Following cut out of tw_cl_fwif.h
+ *
+ */
+
+#define TWA_FW_CMD_ATA_PASSTHROUGH 0x11
+
+#define TWA_SENSE_DATA_LENGTH 18
+
+#pragma pack(1)
+/* 7000 structures. */
+struct tw_cl_command_init_connect {
+ TW_UINT8 res1__opcode; /* 3:5 */
+ TW_UINT8 size;
+ TW_UINT8 request_id;
+ TW_UINT8 res2;
+ TW_UINT8 status;
+ TW_UINT8 flags;
+ TW_UINT16 message_credits;
+ TW_UINT32 features;
+ TW_UINT16 fw_srl;
+ TW_UINT16 fw_arch_id;
+ TW_UINT16 fw_branch;
+ TW_UINT16 fw_build;
+ TW_UINT32 result;
+};
+
+
+/* Structure for downloading firmware onto the controller. */
+struct tw_cl_command_download_firmware {
+ TW_UINT8 sgl_off__opcode;/* 3:5 */
+ TW_UINT8 size;
+ TW_UINT8 request_id;
+ TW_UINT8 unit;
+ TW_UINT8 status;
+ TW_UINT8 flags;
+ TW_UINT16 param;
+ TW_UINT8 sgl[1];
+};
+
+
+/* Structure for hard resetting the controller. */
+struct tw_cl_command_reset_firmware {
+ TW_UINT8 res1__opcode; /* 3:5 */
+ TW_UINT8 size;
+ TW_UINT8 request_id;
+ TW_UINT8 unit;
+ TW_UINT8 status;
+ TW_UINT8 flags;
+ TW_UINT8 res2;
+ TW_UINT8 param;
+};
+
+
+/* Structure for sending get/set param commands. */
+struct tw_cl_command_param {
+ TW_UINT8 sgl_off__opcode;/* 3:5 */
+ TW_UINT8 size;
+ TW_UINT8 request_id;
+ TW_UINT8 host_id__unit; /* 4:4 */
+ TW_UINT8 status;
+ TW_UINT8 flags;
+ TW_UINT16 param_count;
+ TW_UINT8 sgl[1];
+};
+
+
+/* Generic command packet. */
+struct tw_cl_command_generic {
+ TW_UINT8 sgl_off__opcode;/* 3:5 */
+ TW_UINT8 size;
+ TW_UINT8 request_id;
+ TW_UINT8 host_id__unit; /* 4:4 */
+ TW_UINT8 status;
+ TW_UINT8 flags;
+ TW_UINT16 count; /* block cnt, parameter cnt, message credits */
+};
+
+
+/* Command packet header. */
+struct tw_cl_command_header {
+ TW_UINT8 sense_data[TWA_SENSE_DATA_LENGTH];
+ struct {
+ TW_INT8 reserved[4];
+ TW_UINT16 error;
+ TW_UINT8 padding;
+ TW_UINT8 res__severity; /* 5:3 */
+ } status_block;
+ TW_UINT8 err_specific_desc[98];
+ struct {
+ TW_UINT8 size_header;
+ TW_UINT16 reserved;
+ TW_UINT8 size_sense;
+ } header_desc;
+};
+
+
+/* 7000 Command packet. */
+union tw_cl_command_7k {
+ struct tw_cl_command_init_connect init_connect;
+ struct tw_cl_command_download_firmware download_fw;
+ struct tw_cl_command_reset_firmware reset_fw;
+ struct tw_cl_command_param param;
+ struct tw_cl_command_generic generic;
+ TW_UINT8 padding[1024 - sizeof(struct tw_cl_command_header)];
+};
+
+
+/* 9000 Command Packet. */
+struct tw_cl_command_9k {
+ TW_UINT8 res__opcode; /* 3:5 */
+ TW_UINT8 unit;
+ TW_UINT16 lun_l4__req_id; /* 4:12 */
+ TW_UINT8 status;
+ TW_UINT8 sgl_offset; /* offset (in bytes) to sg_list, from the
+ end of sgl_entries */
+ TW_UINT16 lun_h4__sgl_entries;
+ TW_UINT8 cdb[16];
+ TW_UINT8 sg_list[872];/* total struct size =
+ 1024-sizeof(cmd_hdr) */
+};
+
+
+/* Full command packet. */
+struct tw_cl_command_packet {
+ struct tw_cl_command_header cmd_hdr;
+ union {
+ union tw_cl_command_7k cmd_pkt_7k;
+ struct tw_cl_command_9k cmd_pkt_9k;
+ } command;
+};
+
+#pragma pack()
+
+/*
+ * Following cut out of tw_cl_ioctl.h
+ *
+ */
+
+#pragma pack(1)
+
+/* Structure used to handle GET/RELEASE LOCK ioctls. */
+struct tw_cl_lock_packet {
+ TW_UINT32 timeout_msec;
+ TW_UINT32 time_remaining_msec;
+ TW_UINT32 force_flag;
+};
+
+
+/* Structure used to handle GET COMPATIBILITY INFO ioctl. */
+struct tw_cl_compatibility_packet {
+ TW_UINT8 driver_version[32];/* driver version */
+ TW_UINT16 working_srl; /* driver & firmware negotiated srl */
+ TW_UINT16 working_branch; /* branch # of the firmware that the
+ driver is compatible with */
+ TW_UINT16 working_build; /* build # of the firmware that the
+ driver is compatible with */
+};
+
+
+/* Driver understandable part of the ioctl packet built by the API. */
+struct tw_cl_driver_packet {
+ TW_UINT32 control_code;
+ TW_UINT32 status;
+ TW_UINT32 unique_id;
+ TW_UINT32 sequence_id;
+ TW_UINT32 os_status;
+ TW_UINT32 buffer_length;
+};
+
+#pragma pack()
+
+/*
+ * Following cut out of tw_osl_ioctl.h
+ *
+ */
+
+#pragma pack(1)
+/*
+ * We need the structure below to ensure that the first byte of
+ * data_buf is not overwritten by the kernel, after we return
+ * from the ioctl call. Note that cmd_pkt has been reduced
+ * to an array of 1024 bytes even though it's actually 2048 bytes
+ * in size. This is because, we don't expect requests from user
+ * land requiring 2048 (273 sg elements) byte cmd pkts.
+ */
+typedef struct tw_osli_ioctl_no_data_buf {
+ struct tw_cl_driver_packet driver_pkt;
+ TW_VOID *pdata; /* points to data_buf */
+ TW_INT8 padding[488 - sizeof(TW_VOID *)];
+ struct tw_cl_command_packet cmd_pkt;
+} TW_OSLI_IOCTL_NO_DATA_BUF;
+
+#pragma pack()
+
+#define TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH \
+ _IOWR('T', 202, TW_OSLI_IOCTL_NO_DATA_BUF)
+
+#pragma pack(1)
+
+typedef struct tw_osli_ioctl_with_payload {
+ struct tw_cl_driver_packet driver_pkt;
+ TW_INT8 padding[488];
+ struct tw_cl_command_packet cmd_pkt;
+ union {
+ struct tw_cl_event_packet event_pkt;
+ struct tw_cl_lock_packet lock_pkt;
+ struct tw_cl_compatibility_packet compat_pkt;
+ TW_INT8 data_buf[1];
+ } payload;
+} TW_OSLI_IOCTL_WITH_PAYLOAD;
+
+#pragma pack()
+
+#endif
+
+
+#ifndef __unused
+#define __unused __attribute__ ((__unused__))
+#endif
+
+#endif /* OS_FREEBSD_H_ */
--- /dev/null
+/*
+ * 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-6 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.
+*/
+
+/*
+ Developer's note: for testing this file, use an unsupported system,
+ for example: ./configure --build=rs6000-ibm-aix && make
+*/
+
+
+// This is needed for the various HAVE_* macros and PROJECT_* macros.
+#include "config.h"
+
+// These are needed to define prototypes and structures for the
+// functions defined below
+#include "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+
+// This is to include whatever structures and prototypes you define in
+// os_generic.h
+#include "os_generic.h"
+
+// Needed by '-V' option (CVS versioning) of smartd/smartctl. You
+// should have one *_H_CVSID macro appearing below for each file
+// appearing with #include "*.h" above. Please list these (below) in
+// alphabetic/dictionary order.
+const char *os_XXXX_c_cvsid="$Id: os_generic.c,v 1.21 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_GENERIC_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+
+
+// This is here to prevent compiler warnings for unused arguments of
+// functions.
+#define ARGUSED(x) ((void)(x))
+
+// Please eliminate the following block: both the #include and
+// the 'unsupported()' function. They are only here to warn
+// unsuspecting users that their Operating System is not supported! If
+// you wish, you can use a similar warning mechanism for any of the
+// functions in this file that you can not (or choose not to)
+// implement.
+
+
+#ifdef HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+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) {
+ ARGUSED(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) {
+ ARGUSED(devlist);
+ ARGUSED(name);
+ unsupported();
+ return 0;
+}
+
+// Like open(). Return non-negative integer handle, only used by the
+// functions below. type=="ATA" or "SCSI". If you need to store
+// extra information about your devices, create a private internal
+// array within this file (see os_freebsd.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){
+ ARGUSED(pathname);
+ ARGUSED(type);
+ unsupported();
+ return -1;
+}
+
+// Like close(). Acts only on integer handles returned by
+// deviceopen() above.
+int deviceclose(int fd){
+ ARGUSED(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){
+ ARGUSED(fd);
+ ARGUSED(command);
+ ARGUSED(select);
+ ARGUSED(data);
+ unsupported();
+ return -1;
+}
+
+int marvell_command_interface(int fd, smart_command_set command, int select, char *data){
+ ARGUSED(fd);
+ ARGUSED(command);
+ ARGUSED(select);
+ ARGUSED(data);
+ unsupported();
+ return -1;
+}
+
+// Interface to ATA devices behind 3ware escalade/apache RAID
+// controller cards. Same description as ata_command_interface()
+// above except that 0 <= disknum <= 15 specifies the ATA disk
+// attached to the controller, and controller_type specifies the
+// precise type of 3ware controller. See os_linux.c
+int escalade_command_interface(int fd, int disknum, int controller_type, smart_command_set command, int select, char *data){
+ ARGUSED(fd);
+ ARGUSED(disknum);
+ ARGUSED(controller_type);
+ ARGUSED(command);
+ ARGUSED(select);
+ ARGUSED(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) {
+ ARGUSED(fd);
+ ARGUSED(iop);
+ ARGUSED(report);
+ unsupported();
+ return -ENOSYS;
+}
--- /dev/null
+/*
+ * 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-6 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/
+ *
+ */
+
+// In the three following lines, change 'GENERIC' to your OS name
+#ifndef OS_GENERIC_H_
+#define OS_GENERIC_H_
+#define OS_GENERIC_H_CVSID "$Id: os_generic.h,v 1.6 2006/04/12 14:54:28 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_ */
--- /dev/null
+/*
+ * os_linux.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-6 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 "config.h"
+#include "int64.h"
+#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.82 2006/04/12 16:28:56 ballen4705 Exp $";
+
+const char *os_XXXX_c_cvsid="$Id: os_linux.c,v 1.82 2006/04/12 16:28:56 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_LINUX_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 --all /dev/hda (Prints all SMART information)\n\n"
+ " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
+ " (Enables SMART on first disk)\n\n"
+ " smartctl --test=long /dev/hda (Executes extended disk self-test)\n\n"
+ " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
+ " (Prints Self-Test & Attribute errors)\n"
+ " smartctl --all --device=3ware,2 /dev/sda\n"
+ " smartctl --all --device=3ware,2 /dev/twe0\n"
+ " smartctl --all --device=3ware,2 /dev/twa0\n"
+ " (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"
+ " smartctl -a -d 3ware,2 /dev/twa0\n"
+ " smartctl -a -d 3ware,2 /dev/twe0\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,
+ int unknown);
+static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
+
+static int sg_io_state = SG_IO_PRESENT_UNKNOWN;
+
+/* Preferred implementation for issuing SCSI commands in linux. This
+ * function uses the SG_IO ioctl. Return 0 if command issued successfully
+ * (various status values should still be checked). If the SCSI command
+ * cannot be issued then a negative errno value is returned. */
+static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
+ int unknown)
+{
+#ifndef SG_IO
+ ARGUSED(dev_fd); ARGUSED(iop); ARGUSED(report);
+ return -ENOTTY;
+#else
+ struct sg_io_hdr io_hdr;
+
+ if (report > 0) {
+ int k, j;
+ const unsigned char * ucp = iop->cmnd;
+ const char * np;
+ char buff[256];
+ const int sz = (int)sizeof(buff);
+
+ np = scsi_get_opcode_name(ucp[0]);
+ j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
+ for (k = 0; k < (int)iop->cmnd_len; ++k)
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
+ if ((report > 1) &&
+ (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
+ int trunc = (iop->dxfer_len > 256) ? 1 : 0;
+
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
+ "data, len=%d%s:\n", (int)iop->dxfer_len,
+ (trunc ? " [only first 256 bytes shown]" : ""));
+ dStrHex((const char *)iop->dxferp,
+ (trunc ? 256 : iop->dxfer_len) , 1);
+ }
+ else
+ j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
+ pout(buff);
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = iop->cmnd_len;
+ io_hdr.mx_sb_len = iop->max_sense_len;
+ io_hdr.dxfer_len = iop->dxfer_len;
+ io_hdr.dxferp = iop->dxferp;
+ io_hdr.cmdp = iop->cmnd;
+ io_hdr.sbp = iop->sensep;
+ /* sg_io_hdr interface timeout has millisecond units. Timeout of 0
+ defaults to 60 seconds. */
+ io_hdr.timeout = ((0 == iop->timeout) ? 60 : iop->timeout) * 1000;
+ switch (iop->dxfer_dir) {
+ case DXFER_NONE:
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ break;
+ case DXFER_FROM_DEVICE:
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ break;
+ case DXFER_TO_DEVICE:
+ io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ break;
+ default:
+ pout("do_scsi_cmnd_io: bad dxfer_dir\n");
+ return -EINVAL;
+ }
+ iop->resp_sense_len = 0;
+ iop->scsi_status = 0;
+ iop->resid = 0;
+ if (ioctl(dev_fd, SG_IO, &io_hdr) < 0) {
+ if (report && (! unknown))
+ pout(" SG_IO ioctl failed, errno=%d [%s]\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ 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 if (LSCSI_DRIVER_SENSE != masked_driver_status)
+ return -EIO;
+ }
+ if (LSCSI_DRIVER_SENSE == masked_driver_status)
+ iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
+ iop->resp_sense_len = io_hdr.sb_len_wr;
+ if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
+ iop->sensep && (iop->resp_sense_len > 0)) {
+ if (report > 1) {
+ pout(" >>> Sense buffer, len=%d:\n",
+ (int)iop->resp_sense_len);
+ dStrHex((const char *)iop->sensep, iop->resp_sense_len , 1);
+ }
+ }
+ if (report) {
+ if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) {
+ 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, report, 1))) {
+ sg_io_state = SG_IO_PRESENT_YES;
+ return 0;
+ } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res))
+ return res; /* wait until we see a device */
+ sg_io_state = SG_IO_PRESENT_NO;
+ /* drop through by design */
+ case SG_IO_PRESENT_NO:
+ return sisc_cmnd_io(dev_fd, iop, report);
+ case SG_IO_PRESENT_YES:
+ return sg_io_cmnd_io(dev_fd, iop, report, 0);
+ default:
+ pout(">>>> do_scsi_cmnd_io: bad sg_io_state=%d\n", sg_io_state);
+ sg_io_state = SG_IO_PRESENT_UNKNOWN;
+ return -EIO; /* report error and reset state */
+ }
+}
+
+// >>>>>> End of general SCSI specific linux code
+
+
+// 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);
+ pout("Note: /dev/sdX many need to be replaced with /dev/tweN or /dev/twaN\n");
+ 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;
+}
+
+
+
+int marvell_command_interface(int device,
+ smart_command_set command,
+ int select,
+ char *data) {
+ typedef struct {
+ int inlen;
+ int outlen;
+ char cmd[540];
+ } mvsata_scsi_cmd;
+
+ int copydata = 0;
+ mvsata_scsi_cmd smart_command;
+ unsigned char *buff = (unsigned char *)&smart_command.cmd[6];
+ // See struct hd_drive_cmd_hdr in hdreg.h
+ // buff[0]: ATA COMMAND CODE REGISTER
+ // buff[1]: ATA SECTOR NUMBER REGISTER
+ // buff[2]: ATA FEATURES REGISTER
+ // buff[3]: ATA SECTOR COUNT REGISTER
+
+ // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes)
+ memset(&smart_command, 0, sizeof(smart_command));
+ smart_command.inlen = 540;
+ smart_command.outlen = 540;
+ smart_command.cmd[0] = 0xC; //Vendor-specific code
+ smart_command.cmd[4] = 6; //command length
+
+ buff[0] = ATA_SMART_CMD;
+ switch (command){
+ case CHECK_POWER_MODE:
+ buff[0]=ATA_CHECK_POWER_MODE;
+ break;
+ case READ_VALUES:
+ buff[2]=ATA_SMART_READ_VALUES;
+ copydata=buff[3]=1;
+ break;
+ case READ_THRESHOLDS:
+ buff[2]=ATA_SMART_READ_THRESHOLDS;
+ copydata=buff[1]=buff[3]=1;
+ break;
+ case READ_LOG:
+ buff[2]=ATA_SMART_READ_LOG_SECTOR;
+ buff[1]=select;
+ copydata=buff[3]=1;
+ break;
+ case IDENTIFY:
+ buff[0]=ATA_IDENTIFY_DEVICE;
+ copydata=buff[3]=1;
+ break;
+ case PIDENTIFY:
+ buff[0]=ATA_IDENTIFY_PACKET_DEVICE;
+ copydata=buff[3]=1;
+ break;
+ case ENABLE:
+ buff[2]=ATA_SMART_ENABLE;
+ buff[1]=1;
+ break;
+ case DISABLE:
+ buff[2]=ATA_SMART_DISABLE;
+ buff[1]=1;
+ break;
+ case STATUS:
+ case STATUS_CHECK:
+ // this command only says if SMART is working. It could be
+ // replaced with STATUS_CHECK below.
+ buff[2] = ATA_SMART_STATUS;
+ break;
+ case AUTO_OFFLINE:
+ buff[2]=ATA_SMART_AUTO_OFFLINE;
+ buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
+ break;
+ case AUTOSAVE:
+ buff[2]=ATA_SMART_AUTOSAVE;
+ buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!!
+ break;
+ case IMMEDIATE_OFFLINE:
+ buff[2]=ATA_SMART_IMMEDIATE_OFFLINE;
+ buff[1]=select;
+ break;
+ default:
+ pout("Unrecognized command %d in mvsata_os_specific_handler()\n", command);
+ exit(1);
+ break;
+ }
+ // There are two different types of ioctls(). The HDIO_DRIVE_TASK
+ // one is this:
+ // We are now doing the HDIO_DRIVE_CMD type ioctl.
+ if (ioctl(device, SCSI_IOCTL_SEND_COMMAND, (void *)&smart_command))
+ return -1;
+
+ if (command==CHECK_POWER_MODE) {
+ // LEON -- CHECK THIS PLEASE. THIS SHOULD BE THE SECTOR COUNT
+ // REGISTER, AND IT MIGHT BE buff[2] NOT buff[3]. Bruce
+ data[0]=buff[3];
+ return 0;
+ }
+
+ // Always succeed on a SMART status, as a disk that failed returned
+ // buff[4]=0xF4, buff[5]=0x2C, i.e. "Bad SMART status" (see below).
+ if (command == STATUS)
+ return 0;
+ //Data returned is starting from 0 offset
+ if (command == STATUS_CHECK)
+ {
+ // Cyl low and Cyl high unchanged means "Good SMART status"
+ if (buff[4] == 0x4F && buff[5] == 0xC2)
+ return 0;
+ // These values mean "Bad SMART status"
+ if (buff[4] == 0xF4 && buff[5] == 0x2C)
+ return 1;
+ // We haven't gotten output that makes sense; print out some debugging info
+ syserror("Error SMART Status command failed");
+ pout("Please get assistance from %s\n",PACKAGE_BUGREPORT);
+ pout("Register values returned from SMART Status command are:\n");
+ pout("CMD =0x%02x\n",(int)buff[0]);
+ pout("FR =0x%02x\n",(int)buff[1]);
+ pout("NS =0x%02x\n",(int)buff[2]);
+ pout("SC =0x%02x\n",(int)buff[3]);
+ pout("CL =0x%02x\n",(int)buff[4]);
+ pout("CH =0x%02x\n",(int)buff[5]);
+ pout("SEL=0x%02x\n",(int)buff[6]);
+ return -1;
+ }
+
+ if (copydata)
+ memcpy(data, buff, 512);
+ return 0;
+}
+
+
+// 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
--- /dev/null
+/*
+ * os_linux.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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_LINUX_H_CVSID "$Id: os_linux.h,v 1.24 2006/04/12 14:54:28 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_ */
--- /dev/null
+/*
+ * os_netbsd.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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 "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+#include "os_netbsd.h"
+#include <unistd.h>
+
+const char *os_XXXX_c_cvsid = "$Id: os_netbsd.c,v 1.15 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_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
+marvell_command_interface(int fd, smart_command_set command, int select, char *data)
+{ return -1; }
+
+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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = WDSMART_CYL;
+ req.timeout = 1000;
+ break;
+ case DISABLE:
+ req.flags = ATACMD_READ;
+ req.features = WDSM_DISABLE_OPS;
+ req.command = WDCC_SMART;
+ req.cylinder = 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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = 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 = inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = 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 = 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 (req.cylinder == normal)
+ return 0;
+
+ /* These values mean "Bad SMART status" */
+ if (req.cylinder == failed)
+ return 1;
+
+ /* We haven't gotten output that makes sense;
+ * print out some debugging info */
+ snprintf(buf, sizeof(buf),
+ "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
+ (int) req.command, (int) req.features, (int) req.sec_count, (int) req.sec_num,
+ (int) (le16toh(req.cylinder) & 0xff), (int) ((le16toh(req.cylinder) >> 8) & 0xff),
+ (int) req.error);
+ printwarning(BAD_SMART, buf);
+ return 0;
+ }
+ if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) {
+ perror("Failed command");
+ return -1;
+ }
+ if (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 : (1000 * iop->timeout);
+ 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;
+}
--- /dev/null
+/*
+ * os_netbsd.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 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.9 2006/04/12 14:54:28 ballen4705 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_ */
--- /dev/null
+/*
+ * os_openbsd.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 David Snyder <smartmontools-support@lists.sourceforge.net>
+ *
+ * Derived from os_netbsd.c by Sergey Svishchev <smartmontools-support@lists.sourceforge.net>, Copyright (C) 2003-6
+ *
+ * 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 "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+#include "os_openbsd.h"
+
+const char *os_XXXX_c_cvsid = "$Id: os_openbsd.c,v 1.10 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_OPENBSD_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 = "st";
+
+/* Guess device type(ata or scsi) based on device name */
+int
+guess_device_type(const char *dev_name)
+{
+ int len;
+ int dev_prefix_len = strlen(net_dev_prefix);
+
+ if (!dev_name || !(len = strlen(dev_name)))
+ return CONTROLLER_UNKNOWN;
+
+ if (!strncmp(net_dev_prefix, dev_name, dev_prefix_len)) {
+ if (len <= dev_prefix_len)
+ return CONTROLLER_UNKNOWN;
+ else
+ dev_name += dev_prefix_len;
+ }
+ if (!strncmp(net_dev_ata_disk, dev_name, strlen(net_dev_ata_disk)))
+ return CONTROLLER_ATA;
+
+ if (!strncmp(net_dev_scsi_disk, dev_name, strlen(net_dev_scsi_disk)))
+ return CONTROLLER_SCSI;
+
+ if (!strncmp(net_dev_scsi_tape, dev_name, strlen(net_dev_scsi_tape)))
+ return CONTROLLER_SCSI;
+
+ return CONTROLLER_UNKNOWN;
+}
+
+int
+get_dev_names(char ***names, const char *prefix)
+{
+ char *disknames, *p, **mp;
+ int n = 0;
+ int sysctl_mib[2];
+ size_t sysctl_len;
+
+ *names = NULL;
+
+ sysctl_mib[0] = CTL_HW;
+ sysctl_mib[1] = HW_DISKNAMES;
+ if (-1 == sysctl(sysctl_mib, 2, NULL, &sysctl_len, NULL, 0)) {
+ pout("Failed to get value of sysctl `hw.disknames'\n");
+ return -1;
+ }
+ if (!(disknames = 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
+marvell_command_interface(int fd, smart_command_set command, int select, char *data)
+{ return -1; }
+
+int
+ata_command_interface(int fd, smart_command_set command, int select, char *data)
+{
+ struct atareq req;
+ unsigned char inbuf[DEV_BSIZE];
+ int retval, copydata = 0;
+
+ memset(&req, 0, sizeof(req));
+ memset(&inbuf, 0, sizeof(inbuf));
+
+ switch (command) {
+ case READ_VALUES:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_READ_VALUES;
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.timeout = 1000;
+ copydata = 1;
+ break;
+ case READ_THRESHOLDS:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_READ_THRESHOLDS;
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.timeout = 1000;
+ copydata = 1;
+ break;
+ case READ_LOG:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_READ_LOG_SECTOR; /* XXX missing from wdcreg.h */
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.sec_num = select;
+ req.sec_count = 1;
+ req.timeout = 1000;
+ copydata = 1;
+ break;
+ case WRITE_LOG:
+ memcpy(inbuf, data, 512);
+ req.flags = ATACMD_WRITE;
+ req.features = ATA_SMART_WRITE_LOG_SECTOR; /* XXX missing from wdcreg.h */
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.sec_num = select;
+ req.sec_count = 1;
+ req.timeout = 1000;
+ break;
+ case IDENTIFY:
+ req.flags = ATACMD_READ;
+ req.command = WDCC_IDENTIFY;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.timeout = 1000;
+ copydata = 1;
+ break;
+ case PIDENTIFY:
+ req.flags = ATACMD_READ;
+ req.command = ATAPI_IDENTIFY_DEVICE;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.timeout = 1000;
+ copydata = 1;
+ break;
+ case ENABLE:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_ENABLE;
+ req.command = ATAPI_SMART;
+ req.cylinder = htole16(WDSMART_CYL);
+ req.timeout = 1000;
+ break;
+ case DISABLE:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_DISABLE;
+ req.command = ATAPI_SMART;
+ req.cylinder = htole16(WDSMART_CYL);
+ req.timeout = 1000;
+ break;
+ case AUTO_OFFLINE:
+ /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_AUTO_OFFLINE; /* XXX missing from wdcreg.h */
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.sec_num = select;
+ req.sec_count = 1;
+ req.timeout = 1000;
+ break;
+ case AUTOSAVE:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_AUTOSAVE; /* XXX missing from wdcreg.h */
+ req.command = ATAPI_SMART;
+ req.cylinder = htole16(WDSMART_CYL);
+ req.sec_count = 0xf1;
+ /* to enable autosave */
+ req.timeout = 1000;
+ break;
+ case IMMEDIATE_OFFLINE:
+ /* NOTE: According to ATAPI 4 and UP, this command is obsolete */
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_IMMEDIATE_OFFLINE; /* XXX missing from wdcreg.h */
+ req.command = ATAPI_SMART;
+ req.databuf = (caddr_t) inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = htole16(WDSMART_CYL);
+ req.sec_num = select;
+ req.sec_count = 1;
+ req.timeout = 1000;
+ break;
+ case STATUS_CHECK:
+ /* same command, no HDIO in NetBSD */
+ case STATUS:
+ req.flags = ATACMD_READ;
+ req.features = ATA_SMART_STATUS;
+ req.command = ATAPI_SMART;
+ req.cylinder = htole16(WDSMART_CYL);
+ req.timeout = 1000;
+ break;
+ case CHECK_POWER_MODE:
+ req.flags = ATACMD_READREG;
+ req.command = WDCC_CHECK_PWR;
+ req.timeout = 1000;
+ break;
+ default:
+ pout("Unrecognized command %d in ata_command_interface()\n", command);
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (command == STATUS_CHECK) {
+ char buf[512];
+
+ unsigned const short normal = WDSMART_CYL, failed = 0x2cf4;
+
+ if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) {
+ perror("Failed command");
+ return -1;
+ }
+ /* Cyl low and Cyl high unchanged means "Good SMART status" */
+ if (letoh16(req.cylinder) == normal)
+ return 0;
+
+ /* These values mean "Bad SMART status" */
+ if (letoh16(req.cylinder) == failed)
+ return 1;
+
+ /* We haven't gotten output that makes sense;
+ * print out some debugging info */
+ snprintf(buf, sizeof(buf),
+ "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
+ (int) req.command, (int) req.features, (int) req.sec_count, (int) req.sec_num,
+ (int) (letoh16(req.cylinder) & 0xff), (int) ((letoh16(req.cylinder) >> 8) & 0xff),
+ (int) req.error);
+ printwarning(BAD_SMART, buf);
+ return 0;
+ }
+ if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) {
+ perror("Failed command");
+ return -1;
+ }
+ if (command == CHECK_POWER_MODE)
+ data[0] = req.sec_count;
+
+ if (copydata)
+ memcpy(data, inbuf, 512);
+
+ return 0;
+}
+
+int
+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;
+}
--- /dev/null
+/*
+ * os_openbsd.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 David Snyder <smartmontools-support@lists.sourceforge.net>
+ *
+ * Derived from os_netbsd.c by Sergey Svishchev <smartmontools-support@lists.sourceforge.net>, Copyright (C) 2003-6
+ *
+ * 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_OPENBSD_H_
+#define OS_OPENBSD_H_
+
+#define OS_OPENBSD_H_CVSID "$Id: os_openbsd.h,v 1.4 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+/* from NetBSD: atareg.h,v 1.17, by Manuel Bouyer */
+/* Actually fits _perfectly_ into OBSDs wdcreg.h, but... */
+/* Subcommands for SMART (features register) */
+#define WDSMART_CYL 0xc24f
+
+#include <sys/device.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <sys/scsiio.h>
+#include <sys/ataio.h>
+
+#define ata_smart_selftestlog __openbsd_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>
+
+#endif /* OS_OPENBSD_H_ */
--- /dev/null
+/*
+ * os_solaris.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-6 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 "int64.h"
+#include "atacmds.h"
+#include "scsicmds.h"
+#include "utility.h"
+
+// This is to include whatever prototypes you define in os_solaris.h
+#include "os_solaris.h"
+
+#define ARGUSED(x) ((void)(x))
+
+extern long long bytes;
+
+static const char *filenameandversion="$Id: os_solaris.c,v 1.26 2006/04/12 14:54:28 ballen4705 Exp $";
+
+const char *os_XXXX_c_cvsid="$Id: os_solaris.c,v 1.26 2006/04/12 14:54:28 ballen4705 Exp $" \
+ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+
+// The printwarning() function warns about unimplemented functions
+int printedout[2];
+char *unimplemented[2]={
+ "ATA command routine ata_command_interface()",
+ "3ware Escalade Controller command routine escalade_command_interface()",
+};
+
+int printwarning(int which){
+ if (!unimplemented[which])
+ return 0;
+
+ if (printedout[which])
+ return 1;
+
+ printedout[which]=1;
+
+ pout("\n"
+ "#######################################################################\n"
+ "%s NOT IMPLEMENTED under Solaris.\n"
+ "Please contact " PACKAGE_BUGREPORT " if\n"
+ "you want to help in porting smartmontools to Solaris.\n"
+ "#######################################################################\n"
+ "\n",
+ unimplemented[which]);
+
+ return 1;
+}
+
+// print examples for smartctl
+void print_smartctl_examples(){
+ printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
+#ifdef HAVE_GETOPT_LONG
+ printf(
+ " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n"
+ " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n"
+ " (Enables SMART on first disk)\n\n"
+ " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n"
+ " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n"
+ " (Prints Self-Test & Attribute errors)\n"
+ );
+#else
+ printf(
+ " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n"
+ " smartctl -s on -o on -S on /dev/rdsk/c0t0d0s0 (Enables SMART on first disk)\n"
+ " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n"
+ " smartctl -A -l selftest -q errorsonly /dev/rdsk/c0t0d0s0\n"
+ " (Prints Self-Test & Attribute errors)\n"
+ );
+#endif
+ return;
+}
+
+static const char *uscsidrvrs[] = {
+ "sd",
+ "ssd",
+ "st"
+};
+
+static const char *atadrvrs[] = {
+ "cmdk",
+ "dad",
+};
+
+static int
+isdevtype(const char *dev_name, const char *table[], int tsize)
+{
+ char devpath[MAXPATHLEN];
+ int i;
+ char *basename;
+
+ if (realpath(dev_name, devpath) == NULL)
+ return 0;
+
+ if ((basename = strrchr(devpath, '/')) == NULL)
+ return 0;
+
+ basename++;
+
+ for (i = 0; i < tsize; i++) {
+ int l = strlen(table[i]);
+ if (strncmp(basename, table[i], l) == 0 && basename[l] == '@')
+ return 1;
+ }
+ return 0;
+}
+
+static int
+isscsidev(const char *path)
+{
+ return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *));
+}
+
+static int
+isatadev(const char *path)
+{
+ return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *));
+}
+
+// tries to guess device type given the name (a path)
+int guess_device_type (const char* dev_name) {
+ if (isscsidev(dev_name))
+ return CONTROLLER_SCSI;
+ else if (isatadev(dev_name))
+ return CONTROLLER_ATA;
+ else
+ return CONTROLLER_UNKNOWN;
+}
+
+struct pathlist {
+ char **names;
+ int nnames;
+ int maxnames;
+};
+
+static int
+addpath(const char *path, struct pathlist *res)
+{
+ if (++res->nnames > res->maxnames) {
+ res->maxnames += 16;
+ res->names = 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 marvell_command_interface(int fd, smart_command_set command, int select, char *data){
+ ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
+ return -1;
+}
+
+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. See
+ * os_solaris_ata.s for further details. x86 Solaris seems not to
+ * provide similar or alternative interface... */
+ if (printwarning(0))
+ return -1;
+#endif
+ return -1;
+}
+
+// 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);
+}
--- /dev/null
+/*
+ * os_solaris.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2003-6 SAWADA Keiji <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-6 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_SOLARIS_H_CVSID "$Id: os_solaris.h,v 1.12 2006/04/12 14:54:28 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_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_ */
--- /dev/null
+!
+! os_solaris_ata.s
+!
+! Home page of code is: http://smartmontools.sourceforge.net
+!
+! Copyright (C) 2003-6 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 "solaris-ata-in.c"
+ .section ".rodata"
+ .align 8
+.LLC0:
+ .asciz "$Id: os_solaris_ata.s,v 1.5 2006/04/12 14:54:28 ballen4705 Exp $"
+ .global os_solaris_ata_s_cvsid
+ .section ".data"
+ .align 4
+ .type os_solaris_ata_s_cvsid, #object
+ .size os_solaris_ata_s_cvsid, 4
+os_solaris_ata_s_cvsid:
+ .long .LLC0
+ .section ".text"
+ .align 4
+ .type ata_cmd, #function
+ .proc 04
+ata_cmd:
+ !#PROLOGUE# 0
+ save %sp, -184, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ st %i2, [%fp+76]
+ st %i3, [%fp+80]
+ st %i4, [%fp+84]
+ st %i5, [%fp+88]
+ ld [%fp+92], %g1
+ st %g1, [%fp-76]
+ ld [%fp-76], %g1
+ and %g1, 3, %g1
+ cmp %g1, 0
+ be .LL2
+ nop
+ mov -2, %g1
+ st %g1, [%fp-80]
+ b .LL1
+ nop
+.LL2:
+ add %fp, -56, %g1
+ mov %g1, %o0
+ mov 0, %o1
+ mov 36, %o2
+ call memset, 0
+ nop
+ add %fp, -72, %g1
+ mov %g1, %o0
+ mov 0, %o1
+ mov 16, %o2
+ call memset, 0
+ nop
+ ld [%fp+72], %g1
+ stb %g1, [%fp-72]
+ mov 1, %g1
+ stb %g1, [%fp-71]
+ mov 1, %g1
+ stb %g1, [%fp-70]
+ ld [%fp+76], %g1
+ stb %g1, [%fp-69]
+ ld [%fp+84], %g1
+ sll %g1, 9, %g1
+ st %g1, [%fp-68]
+ ld [%fp+80], %g1
+ st %g1, [%fp-60]
+ mov 10, %g1
+ sth %g1, [%fp-52]
+ ld [%fp+88], %g1
+ cmp %g1, 0
+ be .LL3
+ nop
+ mov 14, %g1
+ st %g1, [%fp-84]
+ b .LL4
+ nop
+.LL3:
+ mov 6, %g1
+ st %g1, [%fp-84]
+.LL4:
+ ld [%fp-84], %g1
+ st %g1, [%fp-48]
+ ld [%fp+88], %g1
+ sll %g1, 9, %g1
+ st %g1, [%fp-44]
+ ld [%fp+88], %g1
+ sll %g1, 9, %g1
+ st %g1, [%fp-40]
+ ld [%fp+88], %g1
+ cmp %g1, 0
+ be .LL5
+ nop
+ ld [%fp+92], %g1
+ st %g1, [%fp-88]
+ b .LL6
+ nop
+.LL5:
+ st %g0, [%fp-88]
+.LL6:
+ ld [%fp-88], %g1
+ st %g1, [%fp-36]
+ add %fp, -72, %g1
+ st %g1, [%fp-32]
+ add %fp, -56, %g1
+ ld [%fp+68], %o0
+ mov 1481, %o1
+ mov %g1, %o2
+ call ioctl, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-80]
+.LL1:
+ ld [%fp-80], %i0
+ ret
+ restore
+ .size ata_cmd, .-ata_cmd
+ .align 4
+ .global ata_identify
+ .type ata_identify, #function
+ .proc 04
+ata_identify:
+ !#PROLOGUE# 0
+ save %sp, -648, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ add %fp, -536, %g1
+ st %g1, [%sp+92]
+ ld [%fp+68], %o0
+ mov 236, %o1
+ mov 0, %o2
+ mov 0, %o3
+ mov 1, %o4
+ mov 1, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ add %fp, -536, %g1
+ ld [%fp+72], %o0
+ mov %g1, %o1
+ mov 512, %o2
+ call memcpy, 0
+ nop
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL8
+ nop
+ mov -1, %g1
+ st %g1, [%fp-540]
+ b .LL9
+ nop
+.LL8:
+ st %g0, [%fp-540]
+.LL9:
+ ld [%fp-540], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size ata_identify, .-ata_identify
+ .align 4
+ .global ata_pidentify
+ .type ata_pidentify, #function
+ .proc 04
+ata_pidentify:
+ !#PROLOGUE# 0
+ save %sp, -648, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ add %fp, -536, %g1
+ st %g1, [%sp+92]
+ ld [%fp+68], %o0
+ mov 161, %o1
+ mov 0, %o2
+ mov 0, %o3
+ mov 1, %o4
+ mov 1, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ add %fp, -536, %g1
+ ld [%fp+72], %o0
+ mov %g1, %o1
+ mov 512, %o2
+ call memcpy, 0
+ nop
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL11
+ nop
+ mov -1, %g1
+ st %g1, [%fp-540]
+ b .LL12
+ nop
+.LL11:
+ st %g0, [%fp-540]
+.LL12:
+ ld [%fp-540], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size ata_pidentify, .-ata_pidentify
+ .align 4
+ .global smart_read_data
+ .type smart_read_data, #function
+ .proc 04
+smart_read_data:
+ !#PROLOGUE# 0
+ save %sp, -648, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ add %fp, -536, %g1
+ st %g1, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 208, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ mov 0, %o4
+ mov 1, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ add %fp, -536, %g1
+ ld [%fp+72], %o0
+ mov %g1, %o1
+ mov 512, %o2
+ call memcpy, 0
+ nop
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL14
+ nop
+ mov -1, %g1
+ st %g1, [%fp-540]
+ b .LL15
+ nop
+.LL14:
+ st %g0, [%fp-540]
+.LL15:
+ ld [%fp-540], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_read_data, .-smart_read_data
+ .align 4
+ .global smart_read_thresholds
+ .type smart_read_thresholds, #function
+ .proc 04
+smart_read_thresholds:
+ !#PROLOGUE# 0
+ save %sp, -648, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ add %fp, -536, %g1
+ st %g1, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 209, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 769, %o3
+ mov 1, %o4
+ mov 1, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ add %fp, -536, %g1
+ ld [%fp+72], %o0
+ mov %g1, %o1
+ mov 512, %o2
+ call memcpy, 0
+ nop
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL17
+ nop
+ mov -1, %g1
+ st %g1, [%fp-540]
+ b .LL18
+ nop
+.LL17:
+ st %g0, [%fp-540]
+.LL18:
+ ld [%fp-540], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_read_thresholds, .-smart_read_thresholds
+ .align 4
+ .global smart_auto_save
+ .type smart_auto_save, #function
+ .proc 04
+smart_auto_save:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 210, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ ld [%fp+72], %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL20
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL21
+ nop
+.LL20:
+ st %g0, [%fp-24]
+.LL21:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_auto_save, .-smart_auto_save
+ .align 4
+ .global smart_immediate_offline
+ .type smart_immediate_offline, #function
+ .proc 04
+smart_immediate_offline:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ ld [%fp+72], %g1
+ and %g1, 255, %o5
+ sethi %hi(12733440), %g1
+ or %g1, 768, %g1
+ or %o5, %g1, %g1
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 212, %o2
+ mov %g1, %o3
+ mov 0, %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL23
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL24
+ nop
+.LL23:
+ st %g0, [%fp-24]
+.LL24:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_immediate_offline, .-smart_immediate_offline
+ .align 4
+ .global smart_read_log
+ .type smart_read_log, #function
+ .proc 04
+smart_read_log:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ st %i2, [%fp+76]
+ st %i3, [%fp+80]
+ ld [%fp+72], %g1
+ and %g1, 255, %o5
+ sethi %hi(12733440), %g1
+ or %g1, 768, %g1
+ or %o5, %g1, %o5
+ ld [%fp+80], %g1
+ st %g1, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 213, %o2
+ mov %o5, %o3
+ ld [%fp+76], %o4
+ ld [%fp+76], %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL26
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL27
+ nop
+.LL26:
+ st %g0, [%fp-24]
+.LL27:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_read_log, .-smart_read_log
+ .align 4
+ .global smart_enable
+ .type smart_enable, #function
+ .proc 04
+smart_enable:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 216, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ mov 0, %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL29
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL30
+ nop
+.LL29:
+ st %g0, [%fp-24]
+.LL30:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_enable, .-smart_enable
+ .align 4
+ .global smart_disable
+ .type smart_disable, #function
+ .proc 04
+smart_disable:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 217, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ mov 0, %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL32
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL33
+ nop
+.LL32:
+ st %g0, [%fp-24]
+.LL33:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_disable, .-smart_disable
+ .align 4
+ .global smart_status
+ .type smart_status, #function
+ .proc 04
+smart_status:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 218, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ mov 0, %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL35
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL36
+ nop
+.LL35:
+ st %g0, [%fp-24]
+.LL36:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_status, .-smart_status
+ .align 4
+ .global smart_status_check
+ .type smart_status_check, #function
+ .proc 04
+smart_status_check:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 218, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ mov 0, %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL38
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL37
+ nop
+.LL38:
+ st %g0, [%fp-24]
+.LL37:
+ ld [%fp-24], %i0
+ ret
+ restore
+ .size smart_status_check, .-smart_status_check
+ .align 4
+ .global smart_auto_offline
+ .type smart_auto_offline, #function
+ .proc 04
+smart_auto_offline:
+ !#PROLOGUE# 0
+ save %sp, -128, %sp
+ !#PROLOGUE# 1
+ st %i0, [%fp+68]
+ st %i1, [%fp+72]
+ st %g0, [%sp+92]
+ ld [%fp+68], %o0
+ mov 176, %o1
+ mov 219, %o2
+ sethi %hi(12733440), %g1
+ or %g1, 768, %o3
+ ld [%fp+72], %o4
+ mov 0, %o5
+ call ata_cmd, 0
+ nop
+ mov %o0, %g1
+ st %g1, [%fp-20]
+ ld [%fp-20], %g1
+ cmp %g1, 0
+ be .LL40
+ nop
+ mov -1, %g1
+ st %g1, [%fp-24]
+ b .LL41
+ nop
+.LL40:
+ st %g0, [%fp-24]
+.LL41:
+ ld [%fp-24], %g1
+ mov %g1, %i0
+ ret
+ restore
+ .size smart_auto_offline, .-smart_auto_offline
+ .ident "GCC: (GNU) 3.4.2"
--- /dev/null
+/*
+ * os_win32.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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 "int64.h"
+#include "atacmds.h"
+#include "extern.h"
+extern smartmonctrl * con; // con->permissive,reportataioctl
+#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.33 2006/04/07 15:02:19 chrfranke Exp $"
+ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
+
+
+#ifndef HAVE_GET_OS_VERSION_STR
+#error define of HAVE_GET_OS_VERSION_STR missing in config.h
+#endif
+
+// Return build host and OS version as static string
+const char * get_os_version_str()
+{
+ static char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1+sizeof("-2003r2-sp2.1")+13];
+ char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1;
+ const int vlen = sizeof(vstr)-(sizeof(SMARTMONTOOLS_BUILD_HOST)-3);
+
+ OSVERSIONINFOEXA vi;
+ const char * w;
+
+ // remove "-pc" to avoid long lines
+ assert(!strncmp(SMARTMONTOOLS_BUILD_HOST+5, "pc-", 3));
+ strcpy(vstr, "i686-"); strcpy(vstr+5, SMARTMONTOOLS_BUILD_HOST+5+3);
+ assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
+
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi))
+ return vstr;
+ }
+
+ if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)
+ return vstr;
+
+ switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {
+ case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:
+ w = (vi.szCSDVersion[1] == 'B' ||
+ vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break;
+ case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:
+ w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break;
+ case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break;
+ //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
+ case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break;
+ case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break;
+ case VER_PLATFORM_WIN32_NT <<16|0x0500| 1:
+ w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
+ : "xp-mc"); break;
+ case VER_PLATFORM_WIN32_NT <<16|0x0500| 2:
+ w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
+ : "2003r2"); break;
+ case VER_PLATFORM_WIN32_NT <<16|0x0600| 0: w = "vista"; break;
+ default: w = 0; break;
+ }
+
+ if (!w)
+ snprintf(vptr, vlen, "-%s%lu.%lu",
+ (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),
+ vi.dwMajorVersion, vi.dwMinorVersion);
+ else if (vi.wServicePackMinor)
+ snprintf(vptr, vlen, "-%s-sp%u.%u", w, vi.wServicePackMajor, vi.wServicePackMinor);
+ else if (vi.wServicePackMajor)
+ snprintf(vptr, vlen, "-%s-sp%u", w, vi.wServicePackMajor);
+ else
+ snprintf(vptr, vlen, "-%s", w);
+ return vstr;
+}
+
+
+static int ata_open(int drive);
+static void ata_close(int fd);
+static int ata_scan(unsigned long * drives);
+
+static int aspi_open(unsigned adapter, unsigned id);
+static void aspi_close(int fd);
+static int aspi_scan(unsigned long * drives);
+
+
+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[3];
+ int i, j, n, nmax, sz;
+ const char * path;
+
+ drives[0] = drives[1] = drives[2] = 0;
+ if (!strcmp(type, "ATA")) {
+ // bit i set => drive i present
+ n = ata_scan(drives);
+ path = "/dev/hda";
+ nmax = 10;
+ }
+ else if (!strcmp(type, "SCSI")) {
+ // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present
+ n = aspi_scan(drives);
+ path = "/dev/scsi00";
+ nmax = 10*8;
+ }
+ else
+ return -1;
+
+ if (n <= 0)
+ return 0;
+
+ // Alloc devlist
+ 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 < nmax && !(drives[j >> 5] & (1L << (j & 0x1f))))
+ j++;
+ assert(j < nmax);
+ if (nmax <= 10) {
+ assert(j <= 9);
+ s[sz-2] += j; // /dev/hd[a-j]
+ }
+ else {
+ assert((j >> 3) <= 9);
+ s[sz-3] += (j >> 3); // /dev/scsi[0-9].....
+ 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);
+}
+
+static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
+{
+ pout(" Input : "); print_ide_regs(ri, 0);
+ if (ro) {
+ pout(" Output: "); print_ide_regs(ro, 1);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+// call SMART_* 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;
+ const char * name;
+
+ 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) {
+ code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
+ inpar.cBufferSize = size_out = 512;
+ }
+ else {
+ code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
+ if (regs->bFeaturesReg == ATA_SMART_STATUS)
+ size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
+ // Note: cBufferSize must be 0 on Win9x
+ else
+ size_out = 0;
+ }
+
+ memset(&outbuf, 0, sizeof(outbuf));
+
+ if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
+ outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
+ // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()
+ long err = GetLastError();
+ if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) {
+ pout(" %s failed, Error=%ld\n", name, err);
+ print_ide_regs_io(regs, NULL);
+ }
+ errno = ( err == ERROR_INVALID_FUNCTION /*9x*/
+ || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ ? ENOSYS : EIO);
+ return -1;
+ }
+ // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
+
+ outpar = (const SENDCMDOUTPARAMS *)outbuf;
+
+ if (outpar->DriverStatus.bDriverError) {
+ if (con->reportataioctl) {
+ pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
+ outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
+ print_ide_regs_io(regs, NULL);
+ }
+ errno = EIO;
+ return -1;
+ }
+
+ if (con->reportataioctl > 1) {
+ pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
+ num_out, outpar->cBufferSize);
+ print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
+ (const IDEREGS *)(outpar->bBuffer) : NULL));
+ }
+
+ if (datasize)
+ memcpy(data, outpar->bBuffer, 512);
+ else if (regs->bFeaturesReg == ATA_SMART_STATUS)
+ *regs = *(const IDEREGS *)(outpar->bBuffer);
+
+ 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;
+ const unsigned char magic = 0xcf;
+ assert(sizeof(ATA_PASS_THROUGH)-1 == 12);
+ assert(IOCTL_IDE_PASS_THROUGH == 0x04d028);
+
+ if (!buf) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ buf->IdeReg = *regs;
+ buf->DataBufferSize = datasize;
+ if (datasize)
+ buf->DataBuffer[0] = magic;
+
+ if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
+ buf, size, buf, size, &num_out, NULL)) {
+ long err = GetLastError();
+ if (con->reportataioctl)
+ pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
+ VirtualFree(buf, 0, MEM_RELEASE);
+ errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
+ return -1;
+ }
+
+ // Check ATA status
+ if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
+ if (con->reportataioctl) {
+ pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
+ print_ide_regs_io(regs, &buf->IdeReg);
+ }
+ VirtualFree(buf, 0, MEM_RELEASE);
+ errno = EIO;
+ return -1;
+ }
+
+ // Check and copy data
+ if (datasize) {
+ if ( num_out != size
+ || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
+ if (con->reportataioctl) {
+ pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
+ num_out, buf->DataBufferSize);
+ print_ide_regs_io(regs, &buf->IdeReg);
+ }
+ VirtualFree(buf, 0, MEM_RELEASE);
+ errno = EIO;
+ return -1;
+ }
+ memcpy(data, buf->DataBuffer, datasize);
+ }
+
+ if (con->reportataioctl > 1) {
+ pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
+ num_out, buf->DataBufferSize);
+ print_ide_regs_io(regs, &buf->IdeReg);
+ }
+ *regs = buf->IdeReg;
+
+ // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
+ VirtualFree(buf, 0, MEM_RELEASE);
+ return 0;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+// ATA PASS THROUGH via SCSI PASS THROUGH for NT4 only
+// Only used for SMART commands not supported by SMART_* IOCTLs
+
+// Declarations from:
+// http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddscsi.h?rev=1.2
+
+#define IOCTL_SCSI_PASS_THROUGH \
+ CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+#define SCSI_IOCTL_DATA_UNSPECIFIED 2
+// undocumented SCSI opcode to for ATA passthrough
+#define SCSIOP_ATA_PASSTHROUGH 0xCC
+
+typedef struct _SCSI_PASS_THROUGH {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ ULONG/*_PTR*/ DataBufferOffset;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
+{
+ typedef struct {
+ SCSI_PASS_THROUGH spt;
+ ULONG Filler;
+ UCHAR ucSenseBuf[32];
+ UCHAR ucDataBuf[512];
+ } SCSI_PASS_THROUGH_WITH_BUFFERS;
+
+ SCSI_PASS_THROUGH_WITH_BUFFERS sb;
+ IDEREGS * cdbregs;
+ unsigned int size;
+ DWORD num_out;
+ const unsigned char magic = 0xcf;
+
+ assert(sizeof(SCSI_PASS_THROUGH) == 44);
+ assert(IOCTL_SCSI_PASS_THROUGH == 0x04d004);
+
+ memset(&sb, 0, sizeof(sb));
+ sb.spt.Length = sizeof(SCSI_PASS_THROUGH);
+ //sb.spt.PathId = 0;
+ sb.spt.TargetId = 1;
+ //sb.spt.Lun = 0;
+ sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;
+ sb.spt.TimeOutValue = 10;
+ sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
+ size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
+ sb.spt.DataBufferOffset = size;
+
+ if (datasize) {
+ if (datasize > sizeof(sb.ucDataBuf)) {
+ errno = EINVAL;
+ return -1;
+ }
+ sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
+ sb.spt.DataTransferLength = datasize;
+ size += datasize;
+ sb.ucDataBuf[0] = magic;
+ }
+ else {
+ sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
+ //sb.spt.DataTransferLength = 0;
+ }
+
+ // Use pseudo SCSI command followed by registers
+ sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;
+ cdbregs = (IDEREGS *)(sb.spt.Cdb+2);
+ *cdbregs = *regs;
+
+ if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,
+ &sb, size, &sb, size, &num_out, NULL)) {
+ long err = GetLastError();
+ if (con->reportataioctl)
+ pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);
+ errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
+ return -1;
+ }
+
+ // Cannot check ATA status, because command does not return IDEREGS
+
+ // Check and copy data
+ if (datasize) {
+ if ( num_out != size
+ || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {
+ if (con->reportataioctl) {
+ pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);
+ print_ide_regs_io(regs, NULL);
+ }
+ errno = EIO;
+ return -1;
+ }
+ memcpy(data, sb.ucDataBuf, datasize);
+ }
+
+ if (con->reportataioctl > 1) {
+ pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);
+ print_ide_regs_io(regs, NULL);
+ }
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+static HANDLE h_ata_ioctl = 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;
+ // SMARTVSD.VXD present?
+ strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");
+ if (!access(path, 0)) {
+ // Yes, standard IDE driver used?
+ HANDLE h;
+ if ( (h = CreateFileA("\\\\.\\ESDI_506",
+ GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE
+ && GetLastError() == ERROR_FILE_NOT_FOUND ) {
+ pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");
+ return ENOENT;
+ }
+ else {
+ if (h != INVALID_HANDLE_VALUE) // should not happen
+ CloseHandle(h);
+ pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");
+ return ENOSYS;
+ }
+ }
+ else {
+ // 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);
+ }
+ else {
+ path[len] = 0;
+ pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);
+ }
+ return ENOSYS;
+ }
+}
+
+
+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 (err == ERROR_FILE_NOT_FOUND)
+ errno = (win9x ? smartvsd_error() : ENOENT);
+ else if (err == ERROR_ACCESS_DENIED) {
+ if (!win9x)
+ pout("Administrator rights are necessary to access physical drives.\n");
+ errno = EACCES;
+ }
+ else
+ errno = EIO;
+ 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;
+ }
+ }
+
+ if (con->reportataioctl > 1)
+ pout("%s: SMART_GET_VERSION (%ld bytes):\n"
+ " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
+ devpath, num_out, vers.bVersion, vers.bRevision,
+ vers.fCapabilities, vers.bIDEDeviceMap);
+
+ // 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, fill bitmask of drives present, return #drives
+
+static int ata_scan(unsigned long * drives)
+{
+ int win9x = ((GetVersion() & 0x80000000) != 0);
+ int cnt = 0, 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 (con->reportataioctl > 1)
+ pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());
+ 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)) {
+ if (con->reportataioctl)
+ pout(" %s: SMART_GET_VERSION failed, Error=%ld\n", devpath, GetLastError());
+ CloseHandle(h);
+ if (win9x)
+ break; // Should not happen
+ continue; // Non ATA disk or no SMART ioctl support (possibly SCSI disk)
+ }
+ CloseHandle(h);
+
+ if (con->reportataioctl)
+ pout(" %s: SMART_GET_VERSION (%ld bytes):\n"
+ " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
+ devpath, num_out, vers.bVersion, vers.bRevision,
+ vers.fCapabilities, vers.bIDEDeviceMap);
+
+ if (win9x) {
+ // Check ATA device presence, remove ATAPI devices
+ drives[0] = (vers.bIDEDeviceMap & 0xf) & ~((vers.bIDEDeviceMap >> 4) & 0xf);
+ cnt = (drives[0]&1) + ((drives[0]>>1)&1) + ((drives[0]>>2)&1) + ((drives[0]>>3)&1);
+ break;
+ }
+
+ // ATA drive exists and driver supports SMART ioctl
+ drives[0] |= (1L << i);
+ cnt++;
+ }
+
+ return cnt;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+// 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, try_ioctl;
+
+ if (!(0 <= fd && fd <= 3)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ // CMD,CYL default to SMART, changed by P?IDENTIFY and CHECK_POWER_MODE
+ memset(®s, 0, sizeof(regs));
+ regs.bCommandReg = ATA_SMART_CMD;
+ regs.bCylHighReg = SMART_CYL_HI; regs.bCylLowReg = SMART_CYL_LOW;
+ copydata = 0;
+ try_ioctl = 0x01; // 0x01=SMART_*, 0x02=IDE_PASS_THROUGH [, 0x04=ATA_PASS_THROUGH]
+
+ switch (command) {
+ case WRITE_LOG:
+ // TODO. Not supported by SMART IOCTL (no data out ioctl available),
+ // also not supported by IOCTL_IDE_PASS_THROUGH (data out not working)
+ errno = ENOSYS;
+ return -1;
+ case CHECK_POWER_MODE:
+ regs.bCommandReg = ATA_CHECK_POWER_MODE;
+ regs.bCylLowReg = regs.bCylHighReg = 0;
+ try_ioctl = 0x02; // IOCTL_IDE_PASS_THROUGH
+ // Note: returns SectorCountReg in data[0]
+ break;
+ 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;
+ // Read log only supported on Win9x, retry with pass through command
+ try_ioctl = 0x03; // SMART_RCV_DRIVE_DATA, then IOCTL_IDE_PASS_THROUGH
+ copydata = 1;
+ break;
+ case IDENTIFY:
+ // Note: WinNT4/2000/XP return identify data cached during boot
+ // (true for SMART_RCV_DRIVE_DATA and IOCTL_IDE_PASS_THROUGH)
+ 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;
+ if (select == ABORT_SELF_TEST) // Abort only supported on Win9x, try
+ try_ioctl = 0x03; // SMART_SEND_DRIVE_COMMAND, then IOCTL_IDE_PASS_THROUGH
+ break;
+ default:
+ pout("Unrecognized command %d in win32_ata_command_interface()\n"
+ "Please contact " PACKAGE_BUGREPORT "\n", command);
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (try_ioctl & 0x01) {
+ if (smart_ioctl(h_ata_ioctl, fd, ®s, data, (copydata?512:0))) {
+ if (!(try_ioctl & 0x02) || errno != ENOSYS)
+ return -1;
+ // CAUTION: smart_ioctl() MUST NOT change "regs" Parameter in this case
+ }
+ else
+ try_ioctl = 0;
+ }
+
+ if (try_ioctl & 0x02) {
+ errno = 0;
+ if ((GetVersion() & 0x8000ffff) == 0x00000004) {
+ // Special case WinNT4
+ if (command == CHECK_POWER_MODE) { // SCSI_PASS_THROUGH does not return regs!
+ errno = ENOSYS;
+ return -1;
+ }
+ if (ata_via_scsi_pass_through_ioctl(h_ata_ioctl, ®s, data, (copydata?512:0)))
+ return -1;
+ }
+ else {
+ if (ide_pass_through_ioctl(h_ata_ioctl, ®s, data, (copydata?512:0)))
+ return -1;
+ }
+ try_ioctl = 0;
+ }
+ assert(!try_ioctl);
+
+ switch (command) {
+ case CHECK_POWER_MODE:
+ // Return power mode from SectorCountReg in data[0]
+ data[0] = regs.bSectorCountReg;
+ return 0;
+
+ case 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;
+
+ default:
+ return 0;
+ }
+ /*NOTREACHED*/
+}
+
+
+#ifndef HAVE_ATA_IDENTIFY_IS_CACHED
+#error define of HAVE_ATA_IDENTIFY_IS_CACHED missing in config.h
+#endif
+
+// Return true if OS caches the ATA identify sector
+int ata_identify_is_cached(int fd)
+{
+ ARGUSED(fd);
+ // WinNT4/2000/XP => true, Win9x/ME => false
+ return ((GetVersion() & 0x80000000) == 0);
+}
+
+
+// Print not implemeted warning once
+static void pr_not_impl(const char * what, int * warned)
+{
+ if (*warned)
+ return;
+ pout(
+ "#######################################################################\n"
+ "%s\n"
+ "NOT IMPLEMENTED under Win32.\n"
+ "Please contact " PACKAGE_BUGREPORT " if\n"
+ "you want to help in porting smartmontools to Win32.\n"
+ "#######################################################################\n"
+ "\n", what
+ );
+ *warned = 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)
+{
+ static int warned = 0;
+ ARGUSED(fd); ARGUSED(disknum); ARGUSED(escalade_type); ARGUSED(command); ARGUSED(select); ARGUSED(data);
+ pr_not_impl("3ware Escalade Controller command routine escalade_command_interface()", &warned);
+ errno = ENOSYS;
+ return -1;
+}
+
+// Interface to ATA devices behind Marvell chip-set based controllers. See os_linux.c
+int marvell_command_interface(int fd, smart_command_set command, int select, char * data)
+{
+ static int warned = 0;
+ ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data);
+ pr_not_impl("Marvell chip-set command routine marvell_command_interface()", &warned);
+ 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: Timed out\n", srb->h.adapter);
+ aspi_entry = 0;
+ h_aspi_dll = INVALID_HANDLE_VALUE;
+ errno = EIO;
+ return -1;
+ }
+ if (con->reportscsiioctl > 1)
+ pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);
+ 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;
+ }
+ if (con->reportscsiioctl > 1) {
+ // Print full path of WNASPI32.DLL
+ char path[MAX_PATH];
+ if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))
+ strcpy(path, "*unknown*");
+ pout("Using ASPI interface \"%s\"\n", path);
+ }
+
+ // 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)();
+ if (con->reportscsiioctl > 1)
+ pout("GetASPI32SupportInfo() returns 0x%04x\n", info);
+ 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;
+ }
+
+ if (con->reportscsiioctl)
+ pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
+
+#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, unsigned timeout)
+{
+ 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, timeout*1000L);
+ if (rc != WAIT_OBJECT_0) {
+ if (rc == WAIT_TIMEOUT) {
+ pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",
+ srb->h.adapter, srb->i.target_id, timeout);
+ }
+ 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)
+{
+ ASPI_SRB srb;
+ 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 %u does not exist (%u Adapter%s detected).\n",
+ adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));
+ if (!is_permissive()) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+
+ // Device present ?
+ memset(&srb, 0, sizeof(srb));
+ srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;
+ srb.h.adapter = adapter; srb.i.target_id = id;
+ if (aspi_call(&srb)) {
+ errno = EIO;
+ return -1;
+ }
+ if (srb.h.status != ASPI_STATUS_NO_ERROR) {
+ pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);
+ if (!is_permissive()) {
+ errno = (srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);
+ return -1;
+ }
+ }
+ else if (con->reportscsiioctl)
+ pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);
+
+ 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, fill bitmask [adapter:0-9][id:0-7] of drives present,
+// return #drives
+
+static int aspi_scan(unsigned long * drives)
+{
+ int cnt = 0;
+ unsigned ad;
+
+ if (!aspi_entry_valid()) {
+ if (aspi_open_dll(con->reportscsiioctl/*default is quiet*/))
+ return 0;
+ }
+
+ for (ad = 0; ad < num_aspi_adapters; ad++) {
+ ASPI_SRB srb; unsigned id;
+
+ if (ad > 9) {
+ if (con->reportscsiioctl)
+ pout(" ASPI Adapter %u: Ignored\n", ad);
+ continue;
+ }
+
+ // 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;
+
+ if (srb.h.status != ASPI_STATUS_NO_ERROR) {
+ if (con->reportscsiioctl)
+ pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);
+ continue;
+ }
+
+ if (con->reportscsiioctl) {
+ int i;
+ for (i = 1; i < 16 && srb.q.adapter_id[i]; i++)
+ if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))
+ srb.q.adapter_id[i] = '?';
+ pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);
+ }
+
+ 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;
+ if (srb.h.status != ASPI_STATUS_NO_ERROR) {
+ if (con->reportscsiioctl > 1)
+ pout(" ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);
+ continue;
+ }
+ if (con->reportscsiioctl)
+ pout(" ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
+ if (srb.t.devtype == 0x00/*HDD*/) {
+ drives[ad >> 2] |= (1L << (((ad & 0x3) << 3) + id));
+ cnt++;
+ }
+ }
+ }
+ return cnt;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+// 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, (iop->timeout ? iop->timeout : 60))) {
+ // 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;
+}
--- /dev/null
+/*
+ * os_win32/daemon_win32.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.10 2006/04/12 14:54:28 ballen4705 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;
+ if (sig >= 0)
+ make_name(name, sig);
+ else
+ name[0] = 0;
+ if (exists)
+ *exists = FALSE;
+ if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) {
+ if (errmsg)
+ fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError());
+ return 0;
+ }
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ if (!exists) {
+ if (errmsg)
+ fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name);
+ CloseHandle(h);
+ return 0;
+ }
+ *exists = TRUE;
+ }
+ return h;
+}
+
+
+static HANDLE open_event(int sig)
+{
+ char name[EVT_NAME_LEN];
+ make_name(name, sig);
+ return OpenEventA(EVENT_MODIFY_STATE, FALSE, name);
+}
+
+
+static int event_exists(int sig)
+{
+ char name[EVT_NAME_LEN];
+ HANDLE h;
+ make_name(name, sig);
+ if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name)))
+ return 0;
+ CloseHandle(h);
+ return 1;
+}
+
+
+static int sig_event(int sig)
+{
+ char name[EVT_NAME_LEN];
+ HANDLE h;
+ make_name(name, sig);
+ if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) {
+ make_name(name, EVT_RUNNING);
+ if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name)))
+ return -1;
+ CloseHandle(h);
+ return 0;
+ }
+ SetEvent(h);
+ CloseHandle(h);
+ return 1;
+}
+
+
+static void daemon_help(FILE * f, const char * ident, const char * message)
+{
+ fprintf(f,
+ "%s: %s.\n"
+ "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n",
+ ident, message, ident);
+ fflush(f);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Parent Process
+
+
+static BOOL WINAPI parent_console_handler(DWORD event)
+{
+ switch (event) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ return TRUE; // Ignore
+ }
+ return FALSE; // continue with next handler ...
+}
+
+
+static int parent_main(HANDLE rev)
+{
+ HANDLE dev;
+ HANDLE ht[2];
+ char * cmdline;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD rc, exitcode;
+
+ // Ignore ^C, ^BREAK in parent
+ SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/);
+
+ // Create event used by child to signal daemon_detach()
+ if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) {
+ CloseHandle(rev);
+ return 101;
+ }
+
+ // Restart process with same args
+ cmdline = GetCommandLineA();
+ memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
+
+ if (!CreateProcessA(
+ NULL, cmdline,
+ NULL, NULL, TRUE/*inherit*/,
+ 0, NULL, NULL, &si, &pi)) {
+ fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError());
+ CloseHandle(rev); CloseHandle(dev);
+ return 101;
+ }
+ CloseHandle(pi.hThread);
+
+ // Wait for daemon_detach() or exit()
+ ht[0] = dev; ht[1] = pi.hProcess;
+ rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE);
+ if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) {
+ fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc);
+ TerminateProcess(pi.hProcess, 200);
+ }
+ CloseHandle(rev); CloseHandle(dev);
+
+ // Get exit code
+ if (!GetExitCodeProcess(pi.hProcess, &exitcode))
+ exitcode = 201;
+ else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK
+ exitcode = 0;
+
+ CloseHandle(pi.hProcess);
+ return exitcode;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Child Process
+
+
+static int svc_mode; // Running as service?
+static int svc_paused; // Service paused?
+
+static void service_report_status(int state, int waithint);
+
+
+// Tables of signal handler and corresponding events
+typedef void (*sigfunc_t)(int);
+
+#define MAX_SIG_HANDLERS 8
+
+static int num_sig_handlers = 0;
+static sigfunc_t sig_handlers[MAX_SIG_HANDLERS];
+static int sig_numbers[MAX_SIG_HANDLERS];
+static HANDLE sig_events[MAX_SIG_HANDLERS];
+
+static HANDLE sighup_handle, sigint_handle, sigbreak_handle;
+static HANDLE sigterm_handle, sigusr1_handle;
+
+static HANDLE running_event;
+
+static int reopen_stdin, reopen_stdout, reopen_stderr;
+
+
+// Handler for windows console events
+
+static BOOL WINAPI child_console_handler(DWORD event)
+{
+ // Caution: runs in a new thread
+ // TODO: Guard with a mutex
+ HANDLE h = 0;
+ switch (event) {
+ case CTRL_C_EVENT: // <CONTROL-C> (SIGINT)
+ h = sigint_handle; break;
+ case CTRL_BREAK_EVENT: // <CONTROL-Break> (SIGBREAK/SIGQUIT)
+ case CTRL_CLOSE_EVENT: // User closed console or abort via task manager
+ h = sigbreak_handle; break;
+ case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM)
+ case CTRL_SHUTDOWN_EVENT:
+ h = sigterm_handle; break;
+ }
+ if (!h)
+ return FALSE; // continue with next handler
+ // Signal event
+ if (!SetEvent(h))
+ return FALSE;
+ return TRUE;
+}
+
+
+static void child_exit(void)
+{
+ int i;
+ char * cmdline;
+ HANDLE rst;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ for (i = 0; i < num_sig_handlers; i++)
+ CloseHandle(sig_events[i]);
+ num_sig_handlers = 0;
+ CloseHandle(running_event); running_event = 0;
+
+ // Restart?
+ if (!(rst = open_event(EVT_RESTART)))
+ return; // No => normal exit
+
+ // Yes => Signal exit and restart process
+ Sleep(500);
+ SetEvent(rst);
+ CloseHandle(rst);
+ Sleep(500);
+
+ cmdline = GetCommandLineA();
+ memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
+
+ if (!CreateProcessA(
+ NULL, cmdline,
+ NULL, NULL, TRUE/*inherit*/,
+ 0, NULL, NULL, &si, &pi)) {
+ fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError());
+ }
+ CloseHandle(pi.hThread); CloseHandle(pi.hProcess);
+}
+
+static int child_main(HANDLE hev,int (*main_func)(int, char **), int argc, char **argv)
+{
+ // Keep EVT_RUNNING open until exit
+ running_event = hev;
+
+ // Install console handler
+ SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
+
+ // Install restart handler
+ atexit(child_exit);
+
+ // Continue in main_func() to do the real work
+ return main_func(argc, argv);
+}
+
+
+// Simulate signal()
+
+sigfunc_t daemon_signal(int sig, sigfunc_t func)
+{
+ int i;
+ HANDLE h;
+ if (func == SIG_DFL || func == SIG_IGN)
+ return func; // TODO
+ for (i = 0; i < num_sig_handlers; i++) {
+ if (sig_numbers[i] == sig) {
+ sigfunc_t old = sig_handlers[i];
+ sig_handlers[i] = func;
+ return old;
+ }
+ }
+ if (num_sig_handlers >= MAX_SIG_HANDLERS)
+ return SIG_ERR;
+ if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL)))
+ return SIG_ERR;
+ sig_events[num_sig_handlers] = h;
+ sig_numbers[num_sig_handlers] = sig;
+ sig_handlers[num_sig_handlers] = func;
+ switch (sig) {
+ case SIGHUP: sighup_handle = h; break;
+ case SIGINT: sigint_handle = h; break;
+ case SIGTERM: sigterm_handle = h; break;
+ case SIGBREAK: sigbreak_handle = h; break;
+ case SIGUSR1: sigusr1_handle = h; break;
+ }
+ num_sig_handlers++;
+ return SIG_DFL;
+}
+
+
+// strsignal()
+
+const char * daemon_strsignal(int sig)
+{
+ switch (sig) {
+ case SIGHUP: return "SIGHUP";
+ case SIGINT: return "SIGINT";
+ case SIGTERM: return "SIGTERM";
+ case SIGBREAK:return "SIGBREAK";
+ case SIGUSR1: return "SIGUSR1";
+ case SIGUSR2: return "SIGUSR2";
+ default: return "*UNKNOWN*";
+ }
+}
+
+
+// Simulate sleep()
+
+void daemon_sleep(int seconds)
+{
+ do {
+ if (num_sig_handlers <= 0) {
+ Sleep(seconds*1000L);
+ }
+ else {
+ // Wait for any signal or timeout
+ DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events,
+ FALSE/*OR*/, seconds*1000L);
+ if (rc != WAIT_TIMEOUT) {
+ if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) {
+ fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc);
+ Sleep(seconds*1000L);
+ return;
+ }
+ // Call Handler
+ sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]);
+ break;
+ }
+ }
+ } while (svc_paused);
+}
+
+
+// Disable/Enable console
+
+void daemon_disable_console()
+{
+ SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/);
+ reopen_stdin = reopen_stdout = reopen_stderr = 0;
+ if (isatty(fileno(stdin))) {
+ fclose(stdin); reopen_stdin = 1;
+ }
+ if (isatty(fileno(stdout))) {
+ fclose(stdout); reopen_stdout = 1;
+ }
+ if (isatty(fileno(stderr))) {
+ fclose(stderr); reopen_stderr = 1;
+ }
+ FreeConsole();
+ SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
+}
+
+int daemon_enable_console(const char * title)
+{
+ BOOL ok;
+ SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/);
+ ok = AllocConsole();
+ SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
+ if (!ok)
+ return -1;
+ if (title)
+ SetConsoleTitleA(title);
+ if (reopen_stdin)
+ freopen("conin$", "r", stdin);
+ if (reopen_stdout)
+ freopen("conout$", "w", stdout);
+ if (reopen_stderr)
+ freopen("conout$", "w", stderr);
+ reopen_stdin = reopen_stdout = reopen_stderr = 0;
+ return 0;
+}
+
+
+// Detach daemon from console & parent
+
+int daemon_detach(const char * ident)
+{
+ if (!svc_mode) {
+ if (ident) {
+ // Print help
+ FILE * f = ( isatty(fileno(stdout)) ? stdout
+ : isatty(fileno(stderr)) ? stderr : NULL);
+ if (f)
+ daemon_help(f, ident, "now detaches from console into background mode");
+ }
+ // Signal detach to parent
+ if (sig_event(EVT_DETACHED) != 1) {
+ if (!debugging())
+ return -1;
+ }
+ daemon_disable_console();
+ }
+ else {
+ // Signal end of initialization to service control manager
+ service_report_status(SERVICE_RUNNING, 0);
+ reopen_stdin = reopen_stdout = reopen_stderr = 1;
+ }
+
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// 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;
+ char temp_path[MAX_PATH];
+ DWORD flags, num_io, exitcode;
+ int use_file, state, i;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO si; PROCESS_INFORMATION pi;
+ HANDLE self = GetCurrentProcess();
+
+ if (GetVersion() & 0x80000000L) {
+ // Win9x/ME: A calling process never receives EOF if output of COMMAND.COM or
+ // any other DOS program is redirected via a pipe. Using a temp file instead.
+ use_file = 1; flags = DETACHED_PROCESS;
+ }
+ else {
+ // NT4/2000/XP: If DETACHED_PROCESS is used, CMD.EXE opens a new console window
+ // for each external command in a redirected .BAT file.
+ // Even (DETACHED_PROCESS|CREATE_NO_WINDOW) does not work.
+ use_file = 0; flags = CREATE_NO_WINDOW;
+ }
+
+ // 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/*inherit*/, inpsize*2+13))
+ return -1;
+ if (!DuplicateHandle(self, h, self, &pipe_inp_w,
+ 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
+ CloseHandle(pipe_inp_r);
+ return -1;
+ }
+
+ memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ if (!use_file) {
+ // Create stdout pipe with inheritable write side
+ if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) {
+ CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
+ return -1;
+ }
+ }
+ else {
+ // Create temp file with inheritable write handle
+ char temp_dir[MAX_PATH];
+ if (!GetTempPathA(sizeof(temp_dir), temp_dir))
+ strcpy(temp_dir, ".");
+ if (!GetTempFileNameA(temp_dir, "out"/*prefix*/, 0/*create unique*/, temp_path)) {
+ CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
+ return -1;
+ }
+ if ((h = CreateFileA(temp_path, GENERIC_READ|GENERIC_WRITE,
+ 0/*no sharing*/, &sa/*inherit*/, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
+ CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
+ return -1;
+ }
+ if (!DuplicateHandle(self, h, self, &pipe_out_w,
+ GENERIC_WRITE, TRUE/*inherit*/, 0)) {
+ CloseHandle(h); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
+ return -1;
+ }
+ }
+
+ if (!DuplicateHandle(self, h, self, &pipe_out_r,
+ GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
+ CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
+ return -1;
+ }
+
+ // Create stderr handle as dup of stdout write side
+ 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/file 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*/,
+ flags/*DETACHED_PROCESS or CREATE_NO_WINDOW*/,
+ 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);
+
+ exitcode = 42;
+ for (state = 0; state < 2; state++) {
+ // stdout pipe: read pipe first
+ // stdout file: wait for process first
+ if (state == use_file) {
+ // Copy stdout to output buffer until full, rest to /dev/null
+ // convert \r\n => \n
+ if (use_file)
+ SetFilePointer(pipe_out_r, 0, NULL, FILE_BEGIN);
+ 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);
+ if (use_file)
+ DeleteFileA(temp_path);
+ }
+ else {
+ // Wait for process exitcode
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pi.hProcess);
+ }
+ }
+ return exitcode;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Initd Functions
+
+static int wait_signaled(HANDLE h, int seconds)
+{
+ int i;
+ for (i = 0; ; ) {
+ if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0)
+ return 0;
+ if (++i >= seconds)
+ return -1;
+ fputchar('.'); fflush(stdout);
+ }
+}
+
+
+static int wait_evt_running(int seconds, int exists)
+{
+ int i;
+ if (event_exists(EVT_RUNNING) == exists)
+ return 0;
+ for (i = 0; ; ) {
+ Sleep(1000);
+ if (event_exists(EVT_RUNNING) == exists)
+ return 0;
+ if (++i >= seconds)
+ return -1;
+ fputchar('.'); fflush(stdout);
+ }
+}
+
+
+static int is_initd_command(char * s)
+{
+ if (!strcmp(s, "status"))
+ return EVT_RUNNING;
+ if (!strcmp(s, "stop"))
+ return SIGTERM;
+ if (!strcmp(s, "reload"))
+ return SIGHUP;
+ if (!strcmp(s, "sigusr1"))
+ return SIGUSR1;
+ if (!strcmp(s, "sigusr2"))
+ return SIGUSR2;
+ if (!strcmp(s, "restart"))
+ return EVT_RESTART;
+ return -1;
+}
+
+
+static int initd_main(const char * ident, int argc, char **argv)
+{
+ int rc;
+ if (argc < 2)
+ return -1;
+ if ((rc = is_initd_command(argv[1])) < 0)
+ return -1;
+ if (argc != 2) {
+ printf("%s: no arguments allowed for command %s\n", ident, argv[1]);
+ return 1;
+ }
+
+ switch (rc) {
+ default:
+ case EVT_RUNNING:
+ printf("Checking for %s:", ident); fflush(stdout);
+ rc = event_exists(EVT_RUNNING);
+ puts(rc ? " running" : " not running");
+ return (rc ? 0 : 1);
+
+ case SIGTERM:
+ printf("Stopping %s:", ident); fflush(stdout);
+ rc = sig_event(SIGTERM);
+ if (rc <= 0) {
+ puts(rc < 0 ? " not running" : " error");
+ return (rc < 0 ? 0 : 1);
+ }
+ rc = wait_evt_running(10, 0);
+ puts(!rc ? " done" : " timeout");
+ return (!rc ? 0 : 1);
+
+ case SIGHUP:
+ printf("Reloading %s:", ident); fflush(stdout);
+ rc = sig_event(SIGHUP);
+ puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running");
+ return (rc > 0 ? 0 : 1);
+
+ case SIGUSR1:
+ case SIGUSR2:
+ printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout);
+ rc = sig_event(rc);
+ puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running");
+ return (rc > 0 ? 0 : 1);
+
+ case EVT_RESTART:
+ {
+ HANDLE rst;
+ printf("Stopping %s:", ident); fflush(stdout);
+ if (event_exists(EVT_DETACHED)) {
+ puts(" not detached, cannot restart");
+ return 1;
+ }
+ if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) {
+ puts(" error");
+ return 1;
+ }
+ rc = sig_event(SIGTERM);
+ if (rc <= 0) {
+ puts(rc < 0 ? " not running" : " error");
+ CloseHandle(rst);
+ return 1;
+ }
+ rc = wait_signaled(rst, 10);
+ CloseHandle(rst);
+ if (rc) {
+ puts(" timeout");
+ return 1;
+ }
+ puts(" done");
+ Sleep(100);
+
+ printf("Starting %s:", ident); fflush(stdout);
+ rc = wait_evt_running(10, 1);
+ puts(!rc ? " done" : " error");
+ return (!rc ? 0 : 1);
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Windows Service Functions
+
+int daemon_winsvc_exitcode; // Set by app to exit(code)
+
+static SERVICE_STATUS_HANDLE svc_handle;
+static SERVICE_STATUS svc_status;
+
+
+// Report status to SCM
+
+static void service_report_status(int state, int seconds)
+{
+ // TODO: Avoid race
+ static DWORD checkpoint = 1;
+ static DWORD accept_more = SERVICE_ACCEPT_PARAMCHANGE; // Win2000/XP
+ 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|accept_more;
+ break;
+ }
+ if (!SetServiceStatus(svc_handle, &svc_status)) {
+ if (svc_status.dwControlsAccepted & accept_more) {
+ // Retry without SERVICE_ACCEPT_PARAMCHANGE (WinNT4)
+ svc_status.dwControlsAccepted &= ~accept_more;
+ accept_more = 0;
+ SetServiceStatus(svc_handle, &svc_status);
+ }
+ }
+}
+
+
+// Control the service, called by SCM
+
+static void WINAPI service_control(DWORD ctrlcode)
+{
+ switch (ctrlcode) {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ service_report_status(SERVICE_STOP_PENDING, 30);
+ svc_paused = 0;
+ SetEvent(sigterm_handle);
+ break;
+ case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP
+ service_report_status(svc_status.dwCurrentState, 0);
+ svc_paused = 0;
+ SetEvent(sighup_handle); // reload
+ break;
+ case SERVICE_CONTROL_PAUSE:
+ service_report_status(SERVICE_PAUSED, 0);
+ svc_paused = 1;
+ break;
+ case SERVICE_CONTROL_CONTINUE:
+ service_report_status(SERVICE_RUNNING, 0);
+ {
+ int was_paused = svc_paused;
+ svc_paused = 0;
+ SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck
+ }
+ break;
+ case SERVICE_CONTROL_INTERROGATE:
+ default: // unknown
+ service_report_status(svc_status.dwCurrentState, 0);
+ break;
+ }
+}
+
+
+// Exit handler for service
+
+static void service_exit(void)
+{
+ // Close signal events
+ int i;
+ for (i = 0; i < num_sig_handlers; i++)
+ CloseHandle(sig_events[i]);
+ num_sig_handlers = 0;
+
+ // Set exitcode
+ if (daemon_winsvc_exitcode) {
+ svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode;
+ }
+ // Report stopped
+ service_report_status(SERVICE_STOPPED, 0);
+}
+
+
+// Variables for passing main(argc, argv) from daemon_main to service_main()
+static int (*svc_main_func)(int, char **);
+static int svc_main_argc;
+static char ** svc_main_argv;
+
+// Main function for service, called by service dispatcher
+
+static void WINAPI service_main(DWORD argc, LPSTR * argv)
+{
+ char path[MAX_PATH], *p;
+ 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; long err;
+ SC_HANDLE hm, hs;
+
+ if (argc < 2)
+ return -1;
+ if (!strcmp(argv[1], "install"))
+ remove = 0;
+ else if (!strcmp(argv[1], "remove")) {
+ if (argc != 2) {
+ printf("%s: no arguments allowed for command remove\n", ident);
+ return 1;
+ }
+ remove = 1;
+ }
+ else
+ return -1;
+
+ printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout);
+
+ // Open SCM
+ if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) {
+ if ((err = GetLastError()) == ERROR_ACCESS_DENIED)
+ puts(" access to SCManager denied");
+ else if (err == ERROR_CALL_NOT_IMPLEMENTED)
+ puts(" services not implemented on this version of Windows");
+ else
+ printf(" cannot open SCManager, Error=%ld\n", err);
+ return 1;
+ }
+
+ if (!remove) {
+ char path[MAX_PATH+100];
+ int i;
+ // Get program path
+ if (!GetModuleFileNameA(NULL, path, MAX_PATH)) {
+ printf(" unknown program path, Error=%ld\n", GetLastError());
+ CloseServiceHandle(hm);
+ return 1;
+ }
+ // 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*/))) {
+ if ((err = GetLastError()) == ERROR_SERVICE_EXISTS)
+ puts(" the service is already installed");
+ else if (err == ERROR_SERVICE_MARKED_FOR_DELETE)
+ puts(" service is still running and marked for deletion\n"
+ "Stop the service and retry install");
+ else
+ printf(" failed, Error=%ld\n", err);
+ CloseServiceHandle(hm);
+ return 1;
+ }
+ // Set optional description
+ if (svc_opts->descript)
+ svcadm_setdesc(hs, svc_opts->descript);
+ }
+ else {
+ // Open
+ if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) {
+ puts(" not found");
+ CloseServiceHandle(hm);
+ return 1;
+ }
+ // TODO: Stop service if running
+ // Remove
+ if (!DeleteService(hs)) {
+ if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE)
+ puts(" service is still running and marked for deletion\n"
+ "Stop the service to remove it");
+ else
+ printf(" failed, Error=%ld\n", err);
+ CloseServiceHandle(hs); CloseServiceHandle(hm);
+ return 1;
+ }
+ }
+ puts(" done");
+ CloseServiceHandle(hs); CloseServiceHandle(hm);
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Main Function
+
+// This function must be called from main()
+// main_func is the function doing the real work
+
+int daemon_main(const char * ident, const daemon_winsvc_options * svc_opts,
+ int (*main_func)(int, char **), int argc, char **argv )
+{
+ int rc;
+#ifdef _DEBUG
+ // Enable Debug heap checks
+ _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)
+ |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters
+ if ((rc = initd_main(ident, argc, argv)) >= 0)
+ return rc;
+ // Check for [install|remove] parameters
+ if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0)
+ return rc;
+
+ // Run as service if svc_opts.cmd_opt is given as first(!) argument
+ svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt));
+
+ if (!svc_mode) {
+ // Daemon: Try to simulate a Unix-like daemon
+ HANDLE rev;
+ BOOL exists;
+
+ // Create main event to detect process type:
+ // 1. new: parent process => start child and wait for detach() or exit() of child.
+ // 2. exists && signaled: child process => do the real work, signal detach() to parent
+ // 3. exists && !signaled: already running => exit()
+ if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists)))
+ return 100;
+
+ if (!exists && !debugging()) {
+ // Event new => parent process
+ return parent_main(rev);
+ }
+
+ if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) {
+ // Event was signaled => In child process
+ return child_main(rev, main_func, argc, argv);
+ }
+
+ // Event no longer signaled => Already running!
+ daemon_help(stdout, ident, "already running");
+ CloseHandle(rev);
+ return 1;
+ }
+ else {
+ // Service: Start service_main() via SCM
+ SERVICE_TABLE_ENTRY service_table[] = {
+ { (char*)svc_opts->svcname, service_main }, { NULL, NULL }
+ };
+
+ svc_main_func = main_func;
+ svc_main_argc = argc;
+ svc_main_argv = argv;
+ if (!StartServiceCtrlDispatcher(service_table)) {
+ printf("%s: cannot dispatch service, Error=%ld\n"
+ "Option \"%s\" cannot be used to start %s as a service from console.\n"
+ "Use \"%s install ...\" to install the service\n"
+ "and \"net start %s\" to start it.\n",
+ ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident);
+
+#ifdef _DEBUG
+ if (debugging())
+ service_main(argc, argv);
+#endif
+ return 100;
+ }
+ Sleep(1000);
+ ExitThread(0); // Do not redo exit() processing
+ /*NOTREACHED*/
+ return 0;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Test Program
+
+#ifdef TEST
+
+static volatile sig_atomic_t caughtsig = 0;
+
+static void sig_handler(int sig)
+{
+ caughtsig = sig;
+}
+
+static void test_exit(void)
+{
+ printf("Main exit\n");
+}
+
+int test_main(int argc, char **argv)
+{
+ int i;
+ int debug = 0;
+ char * cmd = 0;
+
+ printf("PID=%ld\n", GetCurrentProcessId());
+ for (i = 0; i < argc; i++) {
+ printf("%d: \"%s\"\n", i, argv[i]);
+ if (!strcmp(argv[i],"-d"))
+ debug = 1;
+ }
+ if (argc > 1 && argv[argc-1][0] != '-')
+ cmd = argv[argc-1];
+
+ daemon_signal(SIGINT, sig_handler);
+ daemon_signal(SIGBREAK, sig_handler);
+ daemon_signal(SIGTERM, sig_handler);
+ daemon_signal(SIGHUP, sig_handler);
+ daemon_signal(SIGUSR1, sig_handler);
+ daemon_signal(SIGUSR2, sig_handler);
+
+ atexit(test_exit);
+
+ if (!debug) {
+ printf("Preparing to detach...\n");
+ Sleep(2000);
+ daemon_detach("test");
+ printf("Detached!\n");
+ }
+
+ for (;;) {
+ daemon_sleep(1);
+ printf("."); fflush(stdout);
+ if (caughtsig) {
+ if (caughtsig == SIGUSR2) {
+ debug ^= 1;
+ if (debug)
+ daemon_enable_console("Daemon[Debug]");
+ else
+ daemon_disable_console();
+ }
+ else if (caughtsig == SIGUSR1 && cmd) {
+ char inpbuf[200], outbuf[1000]; int rc;
+ strcpy(inpbuf, "Hello\nWorld!\n");
+ rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf));
+ if (!debug)
+ daemon_enable_console("Command output");
+ printf("\"%s\" returns %d\n", cmd, rc);
+ if (rc >= 0)
+ printf("output:\n%s.\n", outbuf);
+ fflush(stdout);
+ if (!debug) {
+ Sleep(10000); daemon_disable_console();
+ }
+ }
+ printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout);
+ if (caughtsig == SIGTERM || caughtsig == SIGBREAK)
+ break;
+ caughtsig = 0;
+ }
+ }
+ printf("\nExiting on signal %d\n", caughtsig);
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ static const daemon_winsvc_options svc_opts = {
+ "-s", "test", "Test Service", "Service to test daemon_win32.c Module"
+ };
+
+ return daemon_main("testd", &svc_opts, test_main, argc, argv);
+}
+
+#endif
--- /dev/null
+/*
+ * os_win32/daemon_win32.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.6 2006/04/12 14:54:28 ballen4705 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
--- /dev/null
+/*
+ * os_win32/hostname_win32.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.4 2006/04/12 14:54:28 ballen4705 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 (!(GetComputerNameExA_p = (BOOL (WINAPI *)(int, LPSTR, LPDWORD))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, PULONG);
+ DWORD ret;
+ if (!(hdll = LoadLibraryA("IPHlpApi.dll")))
+ return ERROR_NOT_SUPPORTED;
+ if (!(GetNetworkParams_p = (DWORD (WINAPI *)(PFIXED_INFO, PULONG))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
--- /dev/null
+/*
+ * os_win32/hostname_win32.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.3 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+int gethostname(char * name, int len);
+int getdomainname(char * name, int len);
+
+#endif // HOSTNAME_WIN32_H
--- /dev/null
+/*
+ * os_win32/syslog.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.4 2006/04/12 14:54:28 ballen4705 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 */
--- /dev/null
+/*
+ * os_win32/syslog_win32.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2004-6 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.6 2006/04/12 14:54:29 ballen4705 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
--- /dev/null
+/* 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);
+\f
+/* 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
+ };
+\f
+/* 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;
+ }
+ }
+}
+\f
+/* 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
+\f
+/* 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 */
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+#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 */
+\f
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+\f
+/* 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]]] */
+\f
+/* 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;
+\f
+/* 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;
+\f
+/* 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;
+\f
+/* 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 */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
--- /dev/null
+/* 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);
+\f
+/* 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;
+ }
+}
+\f
+/* 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;
+}
+\f
+
+/* 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);
+}
--- /dev/null
+/* 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);
+\f
+
+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 */
--- /dev/null
+/* 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);
+\f
+/* 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
+\f
+/* 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 */
+\f
+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 */
+
+\f
+/* 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;
+}
+
+\f
+/* 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);
+}
--- /dev/null
+/*
+ * scsicmds.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
+ *
+ * Additional SCSI work:
+ * Copyright (C) 2003-6 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.85 2006/04/12 14:54:28 ballen4705 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 */
+ {READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */
+ {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)
+{
+ switch (sinfo->sense_key) {
+ case SCSI_SK_NOT_READY:
+ if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
+ return SIMPLE_ERR_NO_MEDIUM;
+ else if (SCSI_ASC_NOT_READY == sinfo->asc) {
+ if (0x1 == sinfo->ascq)
+ return SIMPLE_ERR_BECOMING_READY;
+ else
+ return SIMPLE_ERR_NOT_READY;
+ } else
+ return SIMPLE_ERR_NOT_READY;
+ case SCSI_SK_MEDIUM_ERROR:
+ case SCSI_SK_HARDWARE_ERROR:
+ return SIMPLE_ERR_MEDIUM_HARDWARE;
+ case SCSI_SK_ILLEGAL_REQUEST:
+ if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)
+ return SIMPLE_ERR_BAD_OPCODE;
+ else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc)
+ return SIMPLE_ERR_BAD_FIELD;
+ else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)
+ return SIMPLE_ERR_BAD_PARAM;
+ else
+ return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */
+ case SCSI_SK_UNIT_ATTENTION:
+ return SIMPLE_ERR_TRY_AGAIN;
+ default:
+ 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";
+ case SIMPLE_ERR_MEDIUM_HARDWARE:
+ return "medium or hardware error (serious)";
+ 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-3 sections 6.6 and 7.2 (rec 22a).
+ N.B. Sets PC==1 to fetch "current cumulative" log pages.
+ If known_resp_len > 0 then a single fetch is done for this response
+ length. If known_resp_len == 0 then twin fetches are performed, the
+ first to deduce the response length, then send the same command again
+ requesting the deduced response length. This protects certain fragile
+ HBAs. The twin fetch technique should not be used with the TapeAlert
+ log page since it clears its state flags after each fetch. */
+int scsiLogSense(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-3 sections 6.9 and 7.4 (rev 22a) [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-3 sections 6.7 and 7.4 (rev 22a) */
+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] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
+ memset(&io_hdr, 0, sizeof(io_hdr));
+ memset(cdb, 0, sizeof(cdb));
+ io_hdr.dxfer_dir = DXFER_TO_DEVICE;
+ io_hdr.dxfer_len = hdr_plus_1_pg;
+ io_hdr.dxferp = pBuf;
+ cdb[0] = MODE_SELECT;
+ cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
+ cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */
+ io_hdr.cmnd = cdb;
+ io_hdr.cmnd_len = sizeof(cdb);
+ io_hdr.sensep = sense;
+ io_hdr.max_sense_len = sizeof(sense);
+ io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
+
+ 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-3 sections 6.10 and 7.4 (rev 22a) [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. SPC-3 sections 6.8 and 7.4 (rev 22a) */
+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] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
+ memset(&io_hdr, 0, sizeof(io_hdr));
+ memset(cdb, 0, sizeof(cdb));
+ io_hdr.dxfer_dir = DXFER_TO_DEVICE;
+ io_hdr.dxfer_len = hdr_plus_1_pg;
+ io_hdr.dxferp = pBuf;
+ cdb[0] = MODE_SELECT_10;
+ cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
+ cdb[8] = hdr_plus_1_pg; /* make sure only one page sent */
+ io_hdr.cmnd = cdb;
+ io_hdr.cmnd_len = sizeof(cdb);
+ io_hdr.sensep = sense;
+ io_hdr.max_sense_len = sizeof(sense);
+ io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
+
+ 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-3 sections 6.4 and 7.6 (rev 22a) */
+int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen)
+{
+ struct scsi_sense_disect sinfo;
+ struct scsi_cmnd_io io_hdr;
+ 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] = INQUIRY;
+ 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);
+ return scsiSimpleSenseFilter(&sinfo);
+}
+
+/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
+ * (unlikely), 2 if command not supported, 3 if field in command not
+ * supported, 5 if response indicates that EVPD bit ignored or returns
+ * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
+int scsiInquiryVpd(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-3 section 6.27 (rev 22a) */
+int scsiRequestSense(int device, struct scsi_sense_disect * sense_info)
+{
+ struct scsi_cmnd_io io_hdr;
+ UINT8 cdb[6];
+ UINT8 sense[32];
+ 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);
+ 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) && (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-3 section 6.28 (rev 22a) */
+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);
+ /* worst case is an extended foreground self test on a big disk */
+ io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST;
+
+ 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-3 section 6.18 (rev 22a) */
+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-3 section 6.33 (rev 22a) */
+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;
+}
+
+/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
+ * command not supported, 3 if field in command not supported or returns
+ * negated errno. SBC-2 section 5.12 (rev 16) */
+int scsiReadDefect10(int device, int req_plist, int req_glist, int dl_format,
+ UINT8 *pBuf, int bufLen)
+{
+ struct scsi_cmnd_io io_hdr;
+ struct scsi_sense_disect sinfo;
+ UINT8 cdb[10];
+ UINT8 sense[32];
+ 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] = READ_DEFECT_10;
+ cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) |
+ ((req_glist << 3) & 0x8) | (dl_format & 0x7));
+ cdb[7] = (bufLen >> 8) & 0xff;
+ cdb[8] = bufLen & 0xff;
+ io_hdr.cmnd = cdb;
+ io_hdr.cmnd_len = sizeof(cdb);
+ io_hdr.sensep = sense;
+ io_hdr.max_sense_len = sizeof(sense);
+ io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
+
+ 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);
+}
+
+/* Offset into mode sense (6 or 10 byte) response that actual mode page
+ * starts at (relative to resp[0]). Returns -1 if problem */
+int scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
+{
+ int resp_len, bd_len;
+ int offset = -1;
+
+ if (resp) {
+ if (10 == modese_len) {
+ resp_len = (resp[0] << 8) + resp[1] + 2;
+ bd_len = (resp[6] << 8) + resp[7];
+ offset = bd_len + 8;
+ } else {
+ resp_len = resp[0] + 1;
+ bd_len = resp[3];
+ offset = bd_len + 4;
+ }
+ if ((offset + 2) > len) {
+ pout("scsiModePageOffset: raw_curr too small, offset=%d "
+ "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
+ offset = -1;
+ } else if ((offset + 2) > resp_len) {
+ if ((resp_len > 2) || con->reportscsiioctl)
+ 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;
+ rout[3] &= 0xef; /* for disks mask out DPOFUA bit */
+ } else {
+ resp_len = rout[0] + 1;
+ rout[2] &= 0xef; /* for disks mask out DPOFUA bit */
+ }
+ sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
+ if (enabled) {
+ rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
+ if (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];
+ int res;
+
+ memset(tBuf, 0, sizeof(tBuf));
+ /* Build SMART Off-line Immediate Diag Header */
+ tBuf[0] = 0x80; /* Page Code */
+ tBuf[1] = 0x00; /* Reserved */
+ tBuf[2] = 0x00; /* Page Length MSB */
+ tBuf[3] = 0x04; /* Page Length LSB */
+ tBuf[4] = 0x03; /* SMART Revision */
+ tBuf[5] = 0x00; /* Reserved */
+ tBuf[6] = 0x00; /* Off-line Immediate Time MSB */
+ tBuf[7] = 0x00; /* Off-line Immediate Time LSB */
+ res = scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8);
+ if (res)
+ pout("IBM offline test failed [%s]\n", scsiErrString(res));
+ return res;
+}
+
+int scsiSmartDefaultSelfTest(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Default self test failed [%s]\n", scsiErrString(res));
+ return res;
+}
+
+int scsiSmartShortSelfTest(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Short offline self test failed [%s]\n", scsiErrString(res));
+ return res;
+}
+
+int scsiSmartExtendSelfTest(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Long (extended) offline self test failed [%s]\n",
+ scsiErrString(res));
+ return res;
+}
+
+int scsiSmartShortCapSelfTest(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Short foreground self test failed [%s]\n", scsiErrString(res));
+ return res;
+}
+
+int scsiSmartExtendCapSelfTest(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Long (extended) foreground self test failed [%s]\n",
+ scsiErrString(res));
+ return res;
+}
+
+int scsiSmartSelfTestAbort(int device)
+{
+ int res;
+
+ res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0);
+ if (res)
+ pout("Abort self test failed [%s]\n", scsiErrString(res));
+ return res;
+}
+
+/* Returns 0 and the expected duration of an extended self test (in seconds)
+ if successful; any other return value indicates a failure. */
+int scsiFetchExtendedSelfTestTime(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;
+ case 0x8009:
+ nmep->gotTFE_H = 1;
+ k = pl - 4;
+ xp = ucp + 4;
+ if (k > szof) {
+ xp += (k - szof);
+ k = szof;
+ }
+ nmep->counterTFE_H = 0;
+ for (j = 0; j < k; ++j) {
+ if (j > 0)
+ nmep->counterTFE_H <<= 8;
+ nmep->counterTFE_H |= xp[j];
+ }
+ break;
+ case 0x8015:
+ nmep->gotPE_H = 1;
+ k = pl - 4;
+ xp = ucp + 4;
+ if (k > szof) {
+ xp += (k - szof);
+ k = szof;
+ }
+ nmep->counterPE_H = 0;
+ for (j = 0; j < k; ++j) {
+ if (j > 0)
+ nmep->counterPE_H <<= 8;
+ nmep->counterPE_H |= xp[j];
+ }
+ break;
+ default:
+ nmep->gotExtraPC = 1;
+ break;
+ }
+ num -= pl;
+ ucp += pl;
+ }
+}
+
+/* Counts number of failed self-tests. Also encodes the poweron_hour
+ of the most recent failed self-test. Return value is negative if
+ this function has a problem (typically -1), otherwise the bottom 8
+ bits are the number of failed self tests and the 16 bits above that
+ are the poweron hour of the most recent failure. Note: aborted self
+ tests (typically by the user) and self tests in progress are not
+ considered failures. See Working Draft SCSI Primary Commands - 3
+ (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
+int scsiCountFailedSelfTests(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;
+ buff[3] &= 0xef; /* for disks mask out DPOFUA bit */
+ } else {
+ resp_len = buff[0] + 1;
+ buff[2] &= 0xef; /* for disks mask out DPOFUA bit */
+ }
+ sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
+ if (enabled)
+ buff[offset + 2] |= 0x2; /* set GLTSD bit */
+ else
+ buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
+ if (10 == modese_len)
+ err = scsiModeSelect10(device, sp, buff, resp_len);
+ else if (6 == modese_len)
+ err = scsiModeSelect(device, sp, buff, resp_len);
+ return err;
+}
+
+/* Returns a negative value if failed to fetch Protocol specific port mode
+ page or it was malformed. Returns transport protocol identifier when
+ value >= 0 . */
+int scsiFetchTransportProtocol(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;
+}
+
+
+/* This is Linux specific code to look for the libata ATA-SCSI
+ simulator in the vendor device identification page.
+ Returns 1 if found else 0. */
+int isLinuxLibAta(unsigned char * vpd_di_buff, int len)
+{
+ int k, id_len, c_set, assoc, id_type, i_len;
+ unsigned char * ucp;
+ unsigned char * ip;
+
+ if (len < 4) {
+ /* Device identification VPD page length too short */
+ return 0;
+ }
+ len -= 4;
+ ucp = vpd_di_buff + 4;
+ for (k = 0; k < len; k += id_len, ucp += id_len) {
+ i_len = ucp[3];
+ id_len = i_len + 4;
+ if ((k + id_len) > len) {
+ /* short descriptor, badly formed */
+ return 0;
+ }
+ ip = ucp + 4;
+ c_set = (ucp[0] & 0xf);
+ assoc = ((ucp[1] >> 4) & 0x3);
+ id_type = (ucp[1] & 0xf);
+ if ((0 == id_type) && (2 == c_set) && (0 == assoc) &&
+ (0 == strncmp((const char *)ip,
+ "Linux ATA-SCSI simulator", i_len))) {
+ return 1;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * scsicmds.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
+ *
+ * Additional SCSI work:
+ * Copyright (C) 2003-6 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.57 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.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
+#ifndef READ_DEFECT_10
+#define READ_DEFECT_10 0x37
+#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;
+ UINT8 gotTFE_H;
+ uint64_t counterTFE_H; /* Track following errors [Hitachi] */
+ UINT8 gotPE_H;
+ uint64_t counterPE_H; /* Positioning errors [Hitachi] */
+};
+
+/* SCSI Peripheral types (of interest) */
+#define SCSI_PT_DIRECT_ACCESS 0x0
+#define SCSI_PT_SEQUENTIAL_ACCESS 0x1
+#define SCSI_PT_CDROM 0x5
+#define SCSI_PT_MEDIUM_CHANGER 0x8
+#define SCSI_PT_ENCLOSURE 0xd
+
+/* ANSI SCSI-3 Log Pages retrieved by LOG SENSE. */
+#define SUPPORTED_LPAGES 0x00
+#define BUFFER_OVERRUN_LPAGE 0x01
+#define WRITE_ERROR_COUNTER_LPAGE 0x02
+#define READ_ERROR_COUNTER_LPAGE 0x03
+#define READ_REVERSE_ERROR_COUNTER_LPAGE 0x04
+#define VERIFY_ERROR_COUNTER_LPAGE 0x05
+#define NON_MEDIUM_ERROR_LPAGE 0x06
+#define LAST_N_ERROR_LPAGE 0x07
+#define FORMAT_STATUS_LPAGE 0x08
+#define 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_MEDIUM_ERROR 0x3
+#define SCSI_SK_HARDWARE_ERROR 0x4
+#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 */
+#define SIMPLE_ERR_MEDIUM_HARDWARE 9 /* medium or hardware error */
+
+
+/* defines for functioncode parameter in SENDDIAGNOSTIC function */
+#define SCSI_DIAG_NO_SELF_TEST 0x00
+#define SCSI_DIAG_DEF_SELF_TEST 0xff
+#define SCSI_DIAG_BG_SHORT_SELF_TEST 0x01
+#define SCSI_DIAG_BG_EXTENDED_SELF_TEST 0x02
+#define SCSI_DIAG_FG_SHORT_SELF_TEST 0x05
+#define SCSI_DIAG_FG_EXTENDED_SELF_TEST 0x06
+#define SCSI_DIAG_ABORT_SELF_TEST 0x04
+
+
+/* SCSI command timeout values (units are seconds) */
+#define SCSI_TIMEOUT_DEFAULT 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);
+
+int scsiReadDefect10(int device, int req_plist, int req_glist, int dl_format,
+ 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);
+
+
+/* This is Linux specific and will be generalized later. */
+int isLinuxLibAta(unsigned char * vpd_di_buff, int len);
+
+#endif
+
--- /dev/null
+/*
+ * scsiprint.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
+ *
+ * Additional SCSI work:
+ * Copyright (C) 2003-6 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.107 2006/04/12 16:18:57 ballen4705 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_LONG_LEN 8192
+#define LOG_RESP_TAPE_ALERT_LEN 0x144
+
+/* Log pages supported */
+static int gSmartLPage = 0; /* Informational Exceptions log page */
+static int gTempLPage = 0;
+static int gSelfTestLPage = 0;
+static int gStartStopLPage = 0;
+static int gReadECounterLPage = 0;
+static int gWriteECounterLPage = 0;
+static int gVerifyECounterLPage = 0;
+static int gNonMediumELPage = 0;
+static int gLastNErrorLPage = 0;
+static int 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 READ_ERROR_COUNTER_LPAGE:
+ gReadECounterLPage = 1;
+ break;
+ case WRITE_ERROR_COUNTER_LPAGE:
+ gWriteECounterLPage = 1;
+ break;
+ case VERIFY_ERROR_COUNTER_LPAGE:
+ gVerifyECounterLPage = 1;
+ break;
+ case LAST_N_ERROR_LPAGE:
+ gLastNErrorLPage = 1;
+ break;
+ case NON_MEDIUM_ERROR_LPAGE:
+ gNonMediumELPage = 1;
+ break;
+ case TEMPERATURE_LPAGE:
+ gTempLPage = 1;
+ break;
+ case STARTSTOP_CYCLE_COUNTER_LPAGE:
+ gStartStopLPage = 1;
+ break;
+ case SELFTEST_RESULTS_LPAGE:
+ gSelfTestLPage = 1;
+ break;
+ case IE_LPAGE:
+ gSmartLPage = 1;
+ break;
+ case TAPE_ALERTS_LPAGE:
+ gTapeAlertsLPage = 1;
+ break;
+ case SEAGATE_CACHE_LPAGE:
+ gSeagateCacheLPage = 1;
+ break;
+ case SEAGATE_FACTORY_LPAGE:
+ gSeagateFactoryLPage = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
+ (or at least something to report). */
+static int scsiGetSmartData(int device, int attribs)
+{
+ UINT8 asc;
+ UINT8 ascq;
+ UINT8 currenttemp = 0;
+ UINT8 triptemp = 0;
+ const char * cp;
+ int err = 0;
+
+ PRINT_ON(con);
+ if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
+ ¤ttemp, &triptemp)) {
+ /* error message already announced */
+ PRINT_OFF(con);
+ return -1;
+ }
+ PRINT_OFF(con);
+ cp = scsiGetIEString(asc, ascq);
+ if (cp) {
+ err = -2;
+ 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);
+ }
+ return err;
+}
+
+
+// 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;
+}
+
+static 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);
+ if (0xffffffff != recommendedStartStop)
+ pout("Recommended maximum start stop count: %u times\n",
+ recommendedStartStop);
+ }
+}
+
+static void scsiPrintGrownDefectListLen(int device)
+{
+ int err, dl_format, dl_len, div;
+
+ memset(gBuf, 0, 4);
+ if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */,
+ 4 /* bytes from index */, gBuf, 4))) {
+ if (con->reportscsiioctl > 0) {
+ PRINT_ON(con);
+ pout("Read defect list (10) Failed: %s\n", scsiErrString(err));
+ PRINT_OFF(con);
+ }
+ return;
+ }
+ if (0x8 != (gBuf[1] & 0x18)) {
+ PRINT_ON(con);
+ pout("Read defect list: asked for grown list but didn't get it\n");
+ PRINT_OFF(con);
+ return;
+ }
+ div = 0;
+ dl_format = (gBuf[1] & 0x7);
+ switch (dl_format) {
+ case 0: /* short block */
+ div = 4;
+ break;
+ case 3: /* long block */
+ case 4: /* bytes from index */
+ case 5: /* physical sector */
+ div = 8;
+ break;
+ default:
+ PRINT_ON(con);
+ pout("defect list format %d unknown\n", dl_format);
+ PRINT_OFF(con);
+ break;
+ }
+ dl_len = (gBuf[2] << 8) + gBuf[3];
+ if (0 == dl_len)
+ pout("Elements in grown defect list: 0\n");
+ else {
+ if (0 == div)
+ pout("Grown defect list length=%d bytes [unknown "
+ "number of elements]\n", dl_len);
+ else
+ pout("Elements in grown defect list: %d\n", dl_len / div);
+ }
+}
+
+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, good, bad;
+ 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/Hitachi 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;
+ good = 0;
+ bad = 0;
+ while (num > 3) {
+ pc = (ucp[0] << 8) | ucp[1];
+ pl = ucp[3] + 4;
+ switch (pc) {
+ case 0: case 8:
+ ++good;
+ break;
+ default:
+ ++bad;
+ break;
+ }
+ num -= pl;
+ ucp += pl;
+ }
+ if ((good < 2) || (bad > 4)) { /* heuristic */
+ if (con->reportscsiioctl > 0) {
+ PRINT_ON(con);
+ pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
+ "unexpected parameters, skip\n");
+ PRINT_OFF(con);
+ }
+ return;
+ }
+ pout("Vendor (Seagate/Hitachi) factory information\n");
+ num = len - 4;
+ ucp = &gBuf[0] + 4;
+ while (num > 3) {
+ pc = (ucp[0] << 8) | ucp[1];
+ pl = ucp[3] + 4;
+ good = 0;
+ switch (pc) {
+ case 0: pout(" number of hours powered up");
+ good = 1;
+ break;
+ case 8: pout(" number of minutes until next internal SMART test");
+ good = 1;
+ break;
+ default:
+ if (con->reportscsiioctl > 0) {
+ PRINT_ON(con);
+ pout("Vendor (Seagate/Hitachi) factory lpage: "
+ "unknown parameter code [0x%x]\n", pc);
+ PRINT_OFF(con);
+ }
+ break;
+ }
+ if (good) {
+ k = pl - 4;
+ xp = ucp + 4;
+ if (k > (int)sizeof(ull)) {
+ xp += (k - (int)sizeof(ull));
+ k = (int)sizeof(ull);
+ }
+ ull = 0;
+ for (j = 0; j < k; ++j) {
+ if (j > 0)
+ ull <<= 8;
+ ull |= xp[j];
+ }
+ if (0 == pc)
+ pout(" = %.2f\n", 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 (gReadECounterLPage && (0 == scsiLogSense(device,
+ READ_ERROR_COUNTER_LPAGE, gBuf, LOG_RESP_LEN, 0))) {
+ scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]);
+ found[0] = 1;
+ }
+ if (gWriteECounterLPage && (0 == scsiLogSense(device,
+ WRITE_ERROR_COUNTER_LPAGE, gBuf, LOG_RESP_LEN, 0))) {
+ scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]);
+ found[1] = 1;
+ }
+ if (gVerifyECounterLPage && (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 by Total "
+ "Correction Gigabytes Total\n");
+ pout(" ECC rereads/ errors "
+ "algorithm processed uncorrected\n");
+ pout(" fast | delayed rewrites corrected "
+ "invocations [10^9 bytes] errors\n");
+ for (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("\nError Counter logging not supported\n");
+ if (gNonMediumELPage && (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);
+ if (nme.gotTFE_H)
+ pout("Track following error count [Hitachi]: %8"PRIu64"\n",
+ nme.counterTFE_H);
+ if (nme.gotPE_H)
+ pout("Positioning error count [Hitachi]: %8"PRIu64"\n",
+ nme.counterPE_H);
+ }
+ if (gLastNErrorLPage && (0 == scsiLogSense(device,
+ LAST_N_ERROR_LPAGE, gBuf, LOG_RESP_LONG_LEN, 0))) {
+ unsigned char * ucp;
+ int num, k, pc, pl;
+
+ num = (gBuf[2] << 8) + gBuf[3] + 4;
+ num = (num < LOG_RESP_LONG_LEN) ? num : LOG_RESP_LONG_LEN;
+ ucp = gBuf + 4;
+ num -= 4;
+ if (num < 4)
+ pout("\nNo error events logged\n");
+ else {
+ pout("\nLast n error events log page\n");
+ for (k = num; k > 0; k -= pl, ucp += pl) {
+ if (k < 3) {
+ pout(" <<short Last n error events log page>>\n");
+ break;
+ }
+ pl = ucp[3] + 4;
+ pc = (ucp[0] << 8) + ucp[1];
+ if (pl > 4) {
+ if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
+ pout(" Error event %d:\n", pc);
+ pout(" [binary]:\n");
+ dStrHex((const char *)ucp + 4, pl - 4, 1);
+ } else if (ucp[2] & 0x1) {
+ pout(" Error event %d:\n", pc);
+ pout(" %.*s\n", pl - 4, (const char *)(ucp + 4));
+ } else {
+ if (con->reportscsiioctl > 0) {
+ pout(" Error event %d:\n", pc);
+ pout(" [data counter??]:\n");
+ dStrHex((const char *)ucp + 4, pl - 4, 1);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static const char * self_test_code[] = {
+ "Default ",
+ "Background short",
+ "Background long ",
+ "Reserved(3) ",
+ "Abort background",
+ "Foreground short",
+ "Foreground long ",
+ "Reserved(7) "
+};
+
+static const char * self_test_result[] = {
+ "Completed ",
+ "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 SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
+// Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
+// 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
+// FAILSMART is returned.
+static int scsiPrintSelfTest(int device)
+{
+ int num, k, n, res, err, durationSec;
+ int noheader = 1;
+ int retval = 0;
+ 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 FAILSMART;
+ }
+ if (gBuf[0] != SELFTEST_RESULTS_LPAGE) {
+ PRINT_ON(con);
+ pout("Self-test Log Sense Failed, page mismatch\n");
+ PRINT_OFF(con);
+ return FAILSMART;
+ }
+ // 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 FAILSMART;
+ }
+ // loop through the twenty possible entries
+ for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
+ int i;
+
+ // timestamp in power-on hours (or zero if test in progress)
+ n = (ucp[6] << 8) | ucp[7];
+
+ // The spec says "all 20 bytes will be zero if no test" but
+ // DG has found otherwise. So this is a heuristic.
+ if ((0 == n) && (0 == ucp[4]))
+ break;
+
+ // only print header if needed
+ if (noheader) {
+ pout("\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]);
+
+ // check the self-test result nibble, using the self-test results
+ // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
+ switch ((res = ucp[4] & 0xf)) {
+ case 0x3:
+ // an unknown error occurred while the device server
+ // was processing the self-test and the device server
+ // was unable to complete the self-test
+ retval|=FAILSMART;
+ break;
+ case 0x4:
+ // the self-test completed with a failure in a test
+ // segment, and the test segment that failed is not
+ // known
+ retval|=FAILLOG;
+ break;
+ case 0x5:
+ // the first segment of the self-test failed
+ retval|=FAILLOG;
+ break;
+ case 0x6:
+ // the second segment of the self-test failed
+ retval|=FAILLOG;
+ break;
+ case 0x7:
+ // another segment of the self-test failed and which
+ // test is indicated by the contents of the SELF-TEST
+ // NUMBER field
+ retval|=FAILLOG;
+ break;
+ default:
+ break;
+ }
+ pout(" %s", self_test_result[res]);
+
+ // self-test number identifies test that failed and consists
+ // of either the number of the segment that failed during
+ // the test, or the number of the test that failed and the
+ // number of the segment in which the test was run, using a
+ // vendor-specific method of putting both numbers into a
+ // single byte.
+ if (ucp[5])
+ pout(" %3d", (int)ucp[5]);
+ else
+ pout(" -");
+
+ // print time that the self-test was completed
+ if (n==0 && res==0xf)
+ // self-test in progress
+ pout(" NOW");
+ else
+ pout(" %5d", n);
+
+ // construct 8-byte integer address of first failure
+ for (i = 0; i < 8; i++) {
+ ull <<= 8;
+ ull |= ucp[i+8];
+ }
+ // print Address of First Failure, if sensible
+ if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) {
+ char buff[32];
+
+ // was hex but change to decimal to conform with ATA
+ snprintf(buff, sizeof(buff), "%"PRIu64, ull);
+ // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
+ pout("%18s", buff);
+ } else
+ pout(" -");
+
+ // if sense key nonzero, then print it, along with
+ // additional sense code and additional sense code qualifier
+ if (ucp[16] & 0xf)
+ pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
+ else
+ pout(" [- - -]\n");
+ }
+
+ // if header never printed, then there was no output
+ if (noheader)
+ pout("No self-tests have been logged\n");
+ else
+ 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 retval;
+}
+
+static const char * peripheral_dt_arr[] = {
+ "disk",
+ "tape",
+ "printer",
+ "processor",
+ "optical disk(4)",
+ "CD/DVD",
+ "scanner",
+ "optical disk(7)",
+ "medium changer",
+ "communications",
+ "graphics(10)",
+ "graphics(11)",
+ "storage array",
+ "enclosure",
+ "simplified disk",
+ "optical card reader"
+};
+
+static const char * transport_proto_arr[] = {
+ "Fibre channel (FCP-2)",
+ "Parallel SCSI (SPI-4)",
+ "SSA",
+ "IEEE 1394 (SBP-2)",
+ "RDMA (SRP)",
+ "iSCSI",
+ "SAS",
+ "ADT",
+ "0x8",
+ "0x9",
+ "0xa",
+ "0xb",
+ "0xc",
+ "0xd",
+ "0xe",
+ "0xf"
+};
+
+/* Returns 0 on success, 1 on general error and 2 for early, clean exit */
+static int scsiGetDriveInfo(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, req_len, avail_len, val;
+ int is_tape = 0;
+ int peri_dt = 0;
+ int returnval=0;
+
+ memset(gBuf, 0, 96);
+ req_len = 36;
+ if ((err = scsiStdInquiry(device, gBuf, req_len))) {
+ PRINT_ON(con);
+ pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
+ pout("Retrying with a 64 byte Standard Inquiry\n");
+ PRINT_OFF(con);
+ /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
+ req_len = 64;
+ if ((err = scsiStdInquiry(device, gBuf, req_len))) {
+ PRINT_ON(con);
+ pout("Standard Inquiry (64 bytes) failed [%s]\n",
+ scsiErrString(err));
+ PRINT_OFF(con);
+ return 1;
+ }
+ }
+ avail_len = gBuf[4] + 5;
+ len = (avail_len < req_len) ? avail_len : req_len;
+ peri_dt = gBuf[0] & 0x1f;
+ if (peripheral_type)
+ *peripheral_type = peri_dt;
+ if (! 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);
+
+ if (0 == strncmp(manufacturer, "3ware", 5) || 0 == strncmp(manufacturer, "AMCC", 4) ) {
+ pout("please try adding '-d 3ware,N'\n");
+ pout("you may also need to change device to /dev/twaN or /dev/tweN\n");
+ return 2;
+ } else if ((len >= 42) &&
+ (0 == strncmp((const char *)(gBuf + 36), "MVSATA", 6))) {
+ pout("please try '-d marvell'\n");
+ return 2;
+ } else if ((avail_len >= 96) && (0 == strncmp(manufacturer, "ATA", 3))) {
+ /* <<<< This is Linux specific code to detect SATA disks using a
+ SCSI-ATA command translation layer. This may be generalized
+ later when the t10.org SAT project matures. >>>> */
+ req_len = 96;
+ memset(gBuf, 0, req_len);
+ if ((err = scsiInquiryVpd(device, 0x83, gBuf, req_len))) {
+ PRINT_ON(con);
+ pout("Inquiry for VPD page 0x83 [device id] failed [%s]\n",
+ scsiErrString(err));
+ PRINT_OFF(con);
+ return 1;
+ }
+ avail_len = ((gBuf[2] << 8) + gBuf[3]) + 4;
+ len = (avail_len < req_len) ? avail_len : req_len;
+ if (isLinuxLibAta(gBuf, len)) {
+ pout("\nIn Linux, SATA disks accessed via libata are "
+ "only supported by smartmontools\n"
+ "for kernel versions 2.6.15 and above. Try "
+ "an additional '-d ata' argument.\n");
+ return 2;
+ }
+ }
+
+ /* 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;
+}
+
+static 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;
+
+ res = scsiGetDriveInfo(fd, &peripheral_type, con->driveinfo);
+ if (res) {
+ if (2 == res)
+ return 0;
+ else
+ 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 */
+ if ((res = scsiGetSmartData(fd, con->smartvendorattrib))) {
+ if (-2 == res)
+ returnval |= FAILSTATUS;
+ else
+ returnval |= FAILSMART;
+ }
+ }
+ }
+ 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) {
+ scsiPrintGrownDefectListLen(fd);
+ if (gSeagateCacheLPage)
+ scsiPrintSeagateCacheLPage(fd);
+ if (gSeagateFactoryLPage)
+ scsiPrintSeagateFactoryLPage(fd);
+ }
+ }
+ if (con->smarterrorlog) {
+ if (! checkedSupportedLogPages)
+ scsiGetSupportedLogPages(fd);
+ 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|=res);
+ }
+ if (con->smartexeoffimmediate) {
+ if (scsiSmartDefaultSelfTest(fd))
+ return returnval | FAILSMART;
+ pout("Default Self Test Successful\n");
+ }
+ if (con->smartshortcapselftest) {
+ if (scsiSmartShortCapSelfTest(fd))
+ return returnval | FAILSMART;
+ pout("Short Foreground Self Test Successful\n");
+ }
+ if (con->smartshortselftest ) {
+ if (scsiSmartShortSelfTest(fd))
+ return returnval | FAILSMART;
+ pout("Short Background Self Test has begun\n");
+ pout("Use smartctl -X to abort test\n");
+ }
+ if (con->smartextendselftest) {
+ if (scsiSmartExtendSelfTest(fd))
+ return returnval | FAILSMART;
+ 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))
+ return returnval | FAILSMART;
+ pout("Extended Foreground Self Test Successful\n");
+ }
+ if (con->smartselftestabort) {
+ if (scsiSmartSelfTestAbort(fd))
+ return returnval | FAILSMART;
+ pout("Self Test returned without error\n");
+ }
+ return returnval;
+}
--- /dev/null
+/*
+ * scsiprint.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
+ *
+ * Additional SCSI work:
+ * Copyright (C) 2003-6 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.20 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+int scsiPrintMain(int fd);
+
+#endif
--- /dev/null
+.ig
+ Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+
+ $Id: smartctl.8.in,v 1.78 2006/04/12 15:45:38 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/local/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\-7 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.
+For SATA disks accessed with libata, use \fB"/dev/sd[a\-z]"\fP
+and append \fB"\-d ata"\fP. For disks behind 3ware controllers
+you may need \fB"/dev/sd[a\-z]"\fP or \fB"/dev/twe[0\-9]"\fP
+or \fB"/dev/twa[0\-9]"\fP: see details below.
+More general paths (such as devfs ones) may also be specified.
+.IP \fBDARWIN\fP: 9
+Use the forms \fB/dev/disk[0\-9]\fP or equivalently \fBdisk[0\-9]\fP or equivalently
+\fB/dev/rdisk[0\-9]\fP. Long forms are also available: please use \'\-h\' to see some
+examples. Note that there is currently no Darwin SCSI support.
+.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/OPENBSD\fP: 9
+Use the form \fB"/dev/wd[0\-9]+c"\fP for IDE/ATA
+devices. For SCSI disk and tape devices, use the device names
+\fB"/dev/sd[0\-9]+c"\fP and \fB"/dev/st[0\-9]+c"\fP respectively.
+Be sure to specify the correct "whole disk" partition letter for
+your architecture.
+.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
+"\\\\.\\PhysicalDrive[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.
+.IP \fBOS/2,eComStation\fP: 9
+Use the form \fB"/dev/hd[a\-z]"\fP for IDE/ATA devices.
+.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.) Indicates if the drive is
+in the smartmontools database (see \'\-v\' options below). If so, the
+drive model family may also be printed.
+.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, \fImarvell\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.
+
+Under Linux, to look at SATA disks behind Marvell SATA controllers
+(using Marvell's \'linuxIAL\' driver rather than libata driver) use \'\-d marvell\'. Such
+controllers show up as Marvell Technology Group Ltd. SATA I or II controllers
+using lspci, or using lspci -n show a vendor ID 0x11ab and a device ID of
+either 0x5040, 0x5041, 0x5080, 0x5081, 0x6041 or 0x6081. The \'linuxIAL\' driver
+seems not (yet?) available in the Linux kernel source tree, but should be available
+from system vendors (ftp://ftp.aslab.com/ is known to provide a patch with the driver).
+
+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. \fBNote that the /dev/sda-z form is deprecated\fP starting
+with the Linux 2.6 kernel series and may not be supported by the Linux
+kernel in the near future. The final form, which refers to devices
+/dev/twa0-15, must be used with 3ware 9000 series controllers, which
+use the 3w-9xxx driver.
+
+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 and FreeBSD.
+
+.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 decimal notation. On Linux systems the smartmontools
+web page has instructions about how to convert this LBA address to the
+name of the disk file containing the erroneous block.
+
+.I selftest [SCSI]
+\- the self\-test log for a SCSI device has a slightly different format
+than for an ATA device. For each of the most recent twenty
+self\-tests, it shows the type of test and the status (final or in
+progress) of the test. SCSI standards use the terms "foreground" and
+"background" (rather than ATA\'s corresponding "captive" and
+"off\-line") and "short" and "long" (rather than ATA\'s corresponding
+"short" and "extended") to describe the type of the test. The printed
+segment number is only relevant when a test fails in the third or
+later test segment. It identifies the test that failed and consists
+of either the number of the segment that failed during the test, or
+the number of the test that failed and the number of the segment in
+which the test was run, using a vendor\-specific method of putting both
+numbers into a single byte. The Logical Block Address (LBA) of the
+first error is printed in hexadecimal notation. On Linux systems the
+smartmontools web page has instructions about how to convert this LBA
+address to the name of the disk file containing the erroneous block.
+If provided, the SCSI Sense Key (SK), Additional Sense Code (ASC) and
+Additional Sense Code Qualifier (ASQ) are also printed. The self tests
+can be run using the \'\-t\' option described below (using the ATA
+test terminology).
+
+.I 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:
+\fBhttp://www.guzu.net/linux/hddtemp.db\fP
+
+.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. An indication that your Samsung disk needs this
+option is that the self-test log is printed correctly, but there are a
+very large number of errors in the SMART error log. This is because
+the error count is byte swapped. Thus a disk with five errors
+(0x0005) will appear to have 20480 errors (0x5000).
+
+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.
+
+The \'\-P showall\' option takes up to two optional arguments to
+match a specific drive type and firmware version. The command:
+.nf
+ smartctl \-P showall
+.fi
+lists all entries, the command:
+.nf
+ smartctl \-P showall \'MODEL\'
+.fi
+lists all entries matching MODEL, and the command:
+.nf
+ smartctl \-P showall \'MODEL\' \'FIRMWARE\'
+.fi
+lists all entries for this MODEL and a specific FIRMWARE version.
+
+.TP
+.B SMART RUN/ABORT OFFLINE TEST AND SELF\-TEST OPTIONS:
+.TP
+.B \-t TEST, \-\-test=TEST
+Executes TEST immediately. The \'\-C\' option can be used in
+conjunction with this option to run the short or long (and also for
+ATA devices, selective or conveyance) self\-tests in captive mode
+(known as "foreground mode" for SCSI devices). Note that only one
+test type can be run at a time, so only one test type should be
+specified per command line. Note also that if a computer is shutdown
+or power cycled during a self\-test, no harm should result. The
+self\-test will either be aborted or will resume automatically.
+
+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 \-a \-d 3ware,0 /dev/twe0
+.fi
+Examine all SMART data for the first ATA disk connected to a 3ware
+RAID 6000/7000/8000 controller card.
+.PP
+.nf
+.B smartctl \-a \-d 3ware,0 /dev/twa0
+.fi
+Examine all SMART data for the first ATA disk connected to a 3ware
+RAID 9000 controller card.
+.PP
+.nf
+.B smartctl \-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 and Cygwin package)
+\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)
+\fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface)
+\fBPhil Williams\fP (User interface and drive database)
+\fBYuri Dario\fP (OS/2, eComStation interface)
+.fi
+Many other individuals have made smaller contributions and corrections.
+
+.PP
+.SH CREDITS
+.fi
+This code was derived from the smartsuite package, written by Michael
+Cornwell, and from the previous UCSC smartsuite package. It extends
+these to cover ATA\-5 disks. This code was originally developed as a
+Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory
+(now part of the Storage Systems Research Center), Jack Baskin School
+of Engineering, University of California, Santa
+Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP .
+.SH
+HOME PAGE FOR SMARTMONTOOLS:
+.fi
+Please see the following web site for updates, further documentation, bug
+reports and patches: \fBhttp://smartmontools.sourceforge.net/\fP
+
+.SH
+SEE ALSO:
+\fBsmartd\fP(8), \fBbadblocks\fP(8), \fBide\-smart\fP(8).
+.SH
+REFERENCES FOR SMART
+.fi
+An introductory article about smartmontools is \fIMonitoring Hard
+Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004,
+pages 74-77. This is \fBhttp://www.linuxjournal.com/article.php?sid=6983\fP
+online.
+
+If you would like to understand better how SMART works, and what it
+does, a good place to start is with Sections 4.8 and 6.54 of the first
+volume of the \'AT Attachment with Packet Interface-7\' (ATA/ATAPI-7)
+specification. This documents the SMART functionality which the
+\fBsmartmontools\fP utilities provide access to. You can find
+Revision 4b of this document at
+\fBhttp://www.t13.org/docs2004/d1532v1r4b-ATA-ATAPI-7.pdf\fP .
+Earlier and later versions of this Specification are available from
+the T13 web site \fBhttp://www.t13.org/\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.78 2006/04/12 15:45:38 ballen4705 Exp $
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
--- /dev/null
+/*
+ * smartctl.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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 <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "config.h"
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000)
+#include <unistd.h>
+#endif
+
+#include "int64.h"
+#include "atacmds.h"
+#include "ataprint.h"
+#include "extern.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
+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.143 2006/04/12 14:54:28 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(){
+#ifdef HAVE_GET_OS_VERSION_STR
+ const char * ver = get_os_version_str();
+#else
+ const char * ver = SMARTMONTOOLS_BUILD_HOST;
+#endif
+ pout("smartctl version %s [%s] Copyright (C) 2002-6 Bruce Allen\n", PACKAGE_VERSION, ver);
+ 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);
+ 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, marvell, 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, marvell, 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 if (!strcmp(optarg,"marvell")) {
+ con->controller_type = CONTROLLER_MARVELL_SATA;
+ 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")) {
+ if (optind < argc) { // -P showall MODEL [FIRMWARE]
+ int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
+ EXIT(cnt); // report #matches
+ }
+ if (showallpresets())
+ EXIT(FAILCMD); // report regexp syntax error
+ EXIT(0);
+ } else {
+ badarg = TRUE;
+ }
+ break;
+ case 't':
+ if (!strcmp(optarg,"offline")) {
+ 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_3WARE_9000_CHAR:
+ mode="ATA_3WARE_9000";
+ break;
+ case CONTROLLER_3WARE_678K_CHAR:
+ mode="ATA_3WARE_678K";
+ break;
+ default:
+ mode="ATA";
+ 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_UNKNOWN:
+ // we should never fall into this branch!
+ pout("Smartctl: please specify device type with the -d option.\n");
+ UsageSummary();
+ retval = FAILCMD;
+ break;
+ case CONTROLLER_SCSI:
+ retval = scsiPrintMain(fd);
+ break;
+ default:
+ retval = ataPrintMain(fd);
+ break;
+ }
+
+ return retval;
+}
--- /dev/null
+/*
+ * smartctl.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.23 2006/04/12 14:54:28 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
--- /dev/null
+.ig
+Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+
+$Id: smartd.8.in,v 1.100 2006/04/12 13:55:44 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 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/local/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-7 and earlier standards (see
+\fBREFERENCES\fP below).
+
+\fBsmartd\fP will attempt to enable SMART monitoring on ATA devices
+(equivalent to \fBsmartctl -s on\fP) and polls these and SCSI devices
+every 30 minutes (configurable), logging SMART errors and changes of
+SMART Attributes via the SYSLOG interface. The default location for
+these SYSLOG notifications and warnings is \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/usr/local/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 \fBINT\fP signal
+(normally generated from a shell with CONTROL\-C) is treated in the
+same way as a \fBHUP\fP signal: it makes \fBsmartd\fP reload its
+configuration file. To exit \fBsmartd\fP use CONTROL-\e
+(Cygwin: 2x CONTROL\-C, Windows: CONTROL\-Break).
+
+On startup, in the absence of the configuration file
+\fB/usr/local/etc/smartd.conf\fP, the \fBsmartd\fP daemon first scans for all
+devices that support SMART. The scanning is done as follows:
+.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/OPENBSD:\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 \fBDARWIN:\fP 9
+The IOService plane is scanned for ATA block storage devices.
+.IP \fBWINDOWS:\fP 9
+Examine all entries \fB"/dev/hd[a-j]"\fP ("\\\\.\\PhysicalDrive[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-9][0-7]"\fP (ASPI adapter 0-9, ID 0-7) for SCSI
+devices on all versions of Windows.
+.IP \fBCYGWIN\fP: 9
+See "WINDOWS" above.
+.IP \fBOS/2,eComStation\fP: 9
+Use the form \fB"/dev/hd[a\-z]"\fP for IDE/ATA devices.
+.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/usr/local/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 /usr/local/etc/smartd.conf\'
+can be used to verify the existence of the default configuration file.
+
+By using \'\-\' for FILE, the configuration is read from standard
+input. This is useful for commands like:
+.nf
+.B echo /dev/hdb \-m user@home \-M test | smartd \-c \- \-q onecheck
+.fi
+to perform quick and simple checks without a configuration file.
+
+.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 /usr/local/etc/smartd.conf, and then exits.
+These Directives are also described later in this man page. They may
+appear in the configuration file following the device name.
+.TP
+.B \-h, \-\-help, \-\-usage
+Prints usage message to STDOUT and exits.
+.TP
+.B \-i N, \-\-interval=N
+Sets the interval between disk checks to \fIN\fP seconds, where
+\fIN\fP is a decimal integer. The minimum allowed value is ten and
+the maximum is the largest positive integer that can be represented on
+your system (often 2^31-1). The default is 1800 seconds.
+
+Note that the superuser can make \fBsmartd\fP check the status of the
+disks at any time by sending it the \fBSIGUSR1\fP signal, for example
+with the command:
+.nf
+.B kill -SIGUSR1 <pid>
+.fi
+where \fB<pid>\fP is the process id number of \fBsmartd\fP. One may
+also use:
+.nf
+.B killall -USR1 smartd
+.fi
+for the same purpose.
+.fi
+(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: Support for \fBsyslogd\fP as described above is available starting with Cygwin 1.5.15.
+On older releases or if no local \fBsyslogd\fP is running, the \'\-l\' option has no effect.
+In this case, all \fBsyslog\fP messages are written to Windows event log
+or to file \fBC:/CYGWIN_SYSLOG.TXT\fP if the event log is not available.
+
+Windows: Some \fBsyslog\fP functionality is implemented
+internally in \fBsmartd\fP as follows: If no \'\-l\' option
+(or \'\-l daemon\') is specified, messages are written to Windows
+event log or to file \fB./smartd.log\fP if event log is not available
+(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 /usr/local/etc/smartd.conf at startup or whenever it
+is reloaded.
+
+.I nodevstartup
+\- Exit if there are no devices to monitor at startup. But continue
+to run if no devices are found whenever the configuration file is
+reloaded.
+
+.I never
+\- Only exit if a fatal error occurs (no remaining system memory,
+invalid command line arguments). In this mode, even if there are no
+devices to monitor, or if the configuration file
+\fB/usr/local/etc/smartd.conf\fP has errors, \fBsmartd\fP will continue to run,
+waiting to load a configuration file listing valid devices.
+
+.I onecheck
+\- Start \fBsmartd\fP in debug mode, then register devices, then check
+device\'s SMART status once, and then exit with zero exit status if all
+of these steps worked correctly.
+
+This last option is intended for \'distribution-writers\' who want to
+create automated scripts to determine whether or not to automatically
+start up \fBsmartd\fP after installing smartmontools. After starting
+\fBsmartd\fP with this command-line option, the distribution\'s install
+scripts should wait a reasonable length of time (say ten seconds). If
+\fBsmartd\fP has not exited with zero status by that time, the script
+should send \fBsmartd\fP a SIGTERM or SIGKILL and assume that
+\fBsmartd\fP will not operate correctly on the host. Conversely, if
+\fBsmartd\fP exits with zero status, then it is safe to run
+\fBsmartd\fP in normal daemon mode. If \fBsmartd\fP is unable to
+monitor any devices or encounters other problems then it will return
+with non-zero exit status.
+
+.I showtests
+\- Start \fBsmartd\fP in debug mode, then register devices, then write
+a list of future scheduled self tests to stdout, and then exit with zero
+exit status if all of these steps worked correctly.
+Device's SMART status is not checked.
+
+This option is intended to test whether the '-s REGEX' directives in
+smartd.conf will have the desired effect. The output lists the next test
+schedules, limited to 5 tests per type and device. This is followed by a
+summary of all tests of each device within the next 90 days.
+.TP
+.B \-r TYPE, \-\-report=TYPE
+Intended primarily to help
+.B smartmontools
+developers understand the behavior of
+.B smartmontools
+on non-conforming or poorly-conforming hardware. This option reports
+details of
+\fBsmartd\fP
+transactions with the device. The option can be used multiple times.
+When used just once, it shows a record of the ioctl() transactions
+with the device. When used more than once, the detail of these ioctl()
+transactions are reported in greater detail. The valid arguments to
+this option are:
+
+.I ioctl
+\- report all ioctl() transactions.
+
+.I ataioctl
+\- report only ioctl() transactions with ATA devices.
+
+.I scsiioctl
+\- report only ioctl() transactions with SCSI devices.
+
+Any argument may include a positive integer to specify the level of
+detail that should be reported. The argument should be followed by a
+comma then the integer with no spaces. For example, \fIataioctl,2\fP
+The default level is 1, so \'\-r ataioctl,1\' and \'\-r ataioctl\' are
+equivalent.
+
+.TP
+.B \-\-service
+Cygwin and Windows only: Enables \fBsmartd\fP to run as a Windows service.
+
+On Cygwin, this option simply prevents fork'ing into background mode to
+allow running \fBsmartd\fP as service via cygrunsrv, see NOTES below.
+
+On Windows, this option enables the buildin service support.
+The option must be specified in the service command line as the first
+argument. It should not be used from console.
+See NOTES below for details.
+
+.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/usr/local/etc/rc.d/init.d/smartd\fP which is responsible for starting and
+stopping the daemon via the normal init interface. Using this script,
+you can start \fBsmartd\fP by giving the command:
+.nf
+.B /usr/local/etc/rc.d/init.d/smartd start
+.fi
+and stop it by using the command:
+.nf
+.B /usr/local/etc/rc.d/init.d/smartd stop
+
+.fi
+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 /usr/local/etc/smartd.conf
+In the absence of a configuration file, under Linux
+\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 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]+.
+Under NetBSD/OpenBSD,
+\fBsmartd\fP
+will try to open all existing ATA devices (with entries in /dev)
+.B /dev/wd[0-9]+c
+and all existing SCSI devices
+.B /dev/sd[0-9]+c.
+Under Solaris \fBsmartd\fP will try to open 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.
+Under Windows \fBsmartd\fP will try to open all entries \fB"/dev/hd[a-j]"\fP ("\\\\.\\PhysicalDrive[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-9][0-7]"\fP (ASPI adapter 0-9, ID 0-7) for SCSI
+devices on all versions of Windows.
+Under Darwin, \fBsmartd\fP will open any ATA block storage device.
+
+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 /usr/local/etc/smartd.conf.
+This file contains a list of devices to monitor, with one device per
+line. An example file is included with the
+.B smartmontools
+distribution. You will find this sample configuration file in
+\fB/usr/local/share/doc/smartmontools-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 file
+.B # /usr/local/etc/smartd.conf for monitoring three
+.B # ATA disks, three SCSI disks, six ATA disks
+.B # behind two 3ware controllers and one SATA disk
+.B #
+.nf
+.B # First ATA disk on two different interfaces. On
+.B # the second disk, start a long self-test every
+.B # Sunday between 3 and 4 am.
+.B #
+.B \ \ /dev/hda -a -m admin@example.com,root@localhost
+.B \ \ /dev/hdc -a -I 194 -I 5 -i 12 -s L/../../7/03
+.B #
+.nf
+.B # SCSI disks. Send a TEST warning email to admin on
+.B # startup.
+.B #
+.B \ \ /dev/sda
+.B \ \ /dev/sdb -m admin@example.com -M test
+.B #
+.nf
+.B # Strange device. It\'s SCSI. Start a scheduled
+.B # long self test between 5 and 6 am Monday/Thursday
+.B \ \ /dev/weird -d scsi -s L/../../(1|4)/05
+.B #
+.nf
+.B # Linux-specific: SATA disk using the libata
+.B # driver. This requires a 2.6.15 or greater
+.B # kernel. The device entry is SCSI but the
+.B # underlying disk understands ATA SMART commands
+.B \ \ /dev/sda -a -d ata
+.B #
+.nf
+.B # Four ATA disks on a 3ware 6/7/8000 controller.
+.B # Start short self-tests daily between midnight and 1am,
+.B # 1-2, 2-3, and 3-4 am. Starting with the Linux 2.6
+.B # kernel series, /dev/sdX is deprecated in favor of
+.B # /dev/tweN. For example replace /dev/sdc by /dev/twe0
+.B # and /dev/sdd by /dev/twe1.
+.B \ \ /dev/sdc -d 3ware,0 -a -s S/../.././00
+.B \ \ /dev/sdc -d 3ware,1 -a -s S/../.././01
+.B \ \ /dev/sdd -d 3ware,2 -a -s S/../.././02
+.B \ \ /dev/sdd -d 3ware,3 -a -s S/../.././03
+.B #
+.nf
+.B # Two ATA disks on a 3ware 9000 controller.
+.B # Start long self-tests Sundays between midnight and
+.B # 1am and 2-3 am
+.B \ \ /dev/twa0 -d 3ware,0 -a -s L/../../7/00
+.B \ \ /dev/twa0 -d 3ware,1 -a -s L/../../7/02
+.B #
+.nf
+.B # 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 /usr/local/etc/smartd.conf
+configuration file. Note that
+.B these are NOT command-line options for
+\fBsmartd\fP.
+The Directives below may appear in any order, following the device
+name.
+
+.B For an ATA device,
+if no Directives appear, then the device will be monitored
+as if the \'\-a\' Directive (monitor all SMART properties) had been given.
+
+.B If a SCSI disk is listed,
+it will be monitored at the maximum implemented level: roughly
+equivalent to using the \'\-H \-l selftest\' options for an ATA disk.
+So with the exception of \'\-d\', \'\-m\', \'\-l selftest\', \'\-s\', and
+\'\-M\', the Directives below are ignored for SCSI disks. For SCSI
+disks, the \'\-m\' Directive sends a warning email if the SMART status
+indicates a disk failure or problem, if the SCSI inquiry about disk
+status fails, or if new errors appear in the self-test log.
+
+.B If a 3ware controller is used
+then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?
+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,
+\fImarvell\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 marvell
+\- Under Linux, interact with SATA disks behind Marvell chip-set
+controllers (using the Marvell rather than libata driver).
+
+.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[,q]
+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.
+
+When a periodic test is skipped, \fBsmartd\fP normally writes an
+informal log message. The message can be suppressed by appending
+the option \',q\' to POWERMODE (like \'\-n standby,q\').
+This prevents a laptop disk from spinning up due to this message.
+
+.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 or the '-q showtests' command-line option to verify
+that you constructed \fBREGEXP\fP correctly. The matching order
+(\fBL\fP before \fBS\fP before \fBC\fP before \fBO\fP) ensures that
+if multiple test types are all scheduled for the same hour, the
+longer test type has precedence. This is usually the desired behavior.
+
+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 more than one of the
+following three \-M Directives are given (example: \-M once \-M daily)
+then the final one (in the example, \-M daily) is used.
+
+The valid arguments to the \-M Directive are (one of the following
+three):
+
+.I once
+\- send only one warning email for each type of disk problem detected. This
+is the default.
+
+.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.
+
+In addition, one may add zero or more of the following Directives:
+
+.I test
+\- send a single test email
+immediately upon
+\fBsmartd\fP
+startup. This allows one to verify that email is delivered correctly.
+
+.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/local/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 one sentence summary warning email message string from
+\fBsmartd\fP.
+This message string contains space characters and is NOT quoted. So to
+use $SMARTD_MESSAGE in a bash script you should probably enclose it in
+double quotes.
+.IP \fBSMARTD_FULLMESSAGE\fP 4
+is set to the contents of the entire email warning message string from
+\fBsmartd\fP.
+This message string contains space and return characters and is NOT quoted. So to
+use $SMARTD_FULLMESSAGE in a bash script you should probably enclose it in
+double quotes.
+.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/local/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:
+\fBhttp://www.guzu.net/linux/hddtemp.db\fP
+
+.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/local/sbin/smartctl -a -d $SMART_DEVICETYPE $SMARTD_DEVICE >> /root/msg
+
+# Now email the message to the user at address ADD:
+/bin/mail -s "$SMARTD_SUBJECT" $SMARTD_ADDRESS < /root/msg
+\fP
+.fi
+
+Example 2: This script is for use with \'\-m <nomailer> \-M exec
+PATH\'. It warns all users about a disk problem, waits 30 seconds, and
+then powers down the machine.
+
+.nf
+\fB
+#! /bin/bash
+
+# Warn all users of a problem
+wall \'Problem detected with disk: \' "$SMARTD_DEVICESTRING"
+wall \'Warning message from smartd is: \' "$SMARTD_MESSAGE"
+wall \'Shutting down machine in 30 seconds... \'
+
+# Wait half a minute
+sleep 30
+
+# Power down the machine
+/sbin/shutdown -hf now
+\fP
+.fi
+
+Some example scripts are distributed with the smartmontools package,
+in /usr/local/share/doc/smartmontools-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:
+
+
+The Cygwin Version of \fBsmartd\fP can be run as a service via the
+cygrunsrv tool. The start-up script provides Cygwin-specific commands
+to install and remove the service:
+.nf
+.B /usr/local/etc/rc.d/init.d/smartd install [options]
+.B /usr/local/etc/rc.d/init.d/smartd remove
+.fi
+The service can be started and stopped by the start-up script as usual
+(see \fBEXAMPLES\fP above).
+
+
+The Windows Version of \fBsmartd\fP has buildin support for services:
+
+\'\fBsmartd install [options]\fP\' installs a service
+named "smartd" (display name "SmartD Service") using the command line
+\'/installpath/smartd.exe --service [options]\'.
+
+\'\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 /usr/local/etc/smartd.conf\fP that are too long.
+Please report this problem to \fB smartmontools-support@lists.sourceforge.net\fP.
+.TP
+.B 10
+An inconsistency was found in \fBsmartd\fP\'s internal data
+structures. This should never happen. It must be due to either a
+coding or compiler bug. \fIPlease\fP report such failures to
+smartmontools-support@lists.sourceforge.net.
+.TP
+.B 16:
+A device explicitly listed in
+.B /usr/local/etc/smartd.conf
+can\'t be monitored.
+.TP
+.B 17:
+\fBsmartd\fP
+didn\'t find any devices to monitor.
+.TP
+.B 254:
+When in daemon mode,
+\fBsmartd\fP
+received a SIGINT or SIGQUIT. (Note that in debug mode, SIGINT has
+the same effect as SIGHUP, and makes \fBsmartd\fP reload its
+configuration file. SIGQUIT has the same effect as SIGTERM and causes
+\fBsmartd\fP to exit with zero exit status.
+.TP
+.B 132 and above
+\fBsmartd\fP
+was killed by a signal that is not explicitly listed above. The exit
+status is then 128 plus the signal number. For example if
+\fBsmartd\fP
+is killed by SIGKILL (signal 9) then the exit status is 137.
+
+.PP
+.SH 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 and Cygwin package)
+\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)
+\fBDavid Snyder and Sergey Svishchev\fP (OpenBSD 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: \fBhttp://smartmontools.sourceforge.net/\fP
+
+.SH SEE ALSO:
+\fBsmartd.conf\fP(5), \fBsmartctl\fP(8), \fBsyslogd\fP(8),
+\fBsyslog.conf\fP(5), \fBbadblocks\fP(8), \fBide\-smart\fP(8), \fBregex\fP(7).
+
+.SH
+REFERENCES FOR SMART
+.fi
+An introductory article about smartmontools is \fIMonitoring Hard
+Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004,
+pages 74-77. This is \fBhttp://www.linuxjournal.com/article.php?sid=6983\fP
+online.
+
+If you would like to understand better how SMART works, and what it
+does, a good place to start is with Sections 4.8 and 6.54 of the first
+volume of the \'AT Attachment with Packet Interface-7\' (ATA/ATAPI-7)
+specification. This documents the SMART functionality which the
+\fBsmartmontools\fP utilities provide access to. You can find
+Revision 4b of this document at
+\fBhttp://www.t13.org/docs2004/d1532v1r4b-ATA-ATAPI-7.pdf\fP .
+Earlier and later versions of this Specification are available from
+the T13 web site \fBhttp://www.t13.org/\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/#references\fP .
+
+.SH
+CVS ID OF THIS PAGE:
+$Id: smartd.8.in,v 1.100 2006/04/12 13:55:44 ballen4705 Exp $
--- /dev/null
+/*
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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
+
+#ifdef __CYGWIN__
+// From <windows.h>:
+// BOOL WINAPI FreeConsole(void);
+int __stdcall FreeConsole(void);
+#include <io.h> // setmode()
+#endif // __CYGWIN__
+
+// locally included files
+#include "int64.h"
+#include "atacmds.h"
+#include "ataprint.h"
+#include "extern.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.362 2006/04/12 16:18:57 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;
+#endif
+const char *smartd_c_cvsid="$Id: smartd.c,v 1.362 2006/04/12 16:18:57 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;
+
+#ifdef __CYGWIN__
+// command-line: running as service, so don't fork()
+static int is_service=0;
+#endif
+
+// 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
+#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 1024
+
+// 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],fullmessage[1024];
+ char original[256], further[256], nisdomain[256], subject[256],dates[DATEANDEPOCHLEN];
+ char environ_strings[11][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_MARVELL_SATA:
+ exportenv(environ_strings[8], "SMARTD_DEVICETYPE", "marvell");
+ 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);
+ }
+
+ snprintf(fullmessage, 1024,
+ "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",
+ hostname, domainname, nisdomain, message, further, original, additional);
+ exportenv(environ_strings[10], "SMARTD_FULLMESSAGE", fullmessage);
+
+ // 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"
+ "%sENDMAIL\n", subject, address, fullmessage);
+ 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);
+
+#ifdef __CYGWIN__
+ // Cygwin's setsid() does not detach the process from Windows console
+ FreeConsole();
+#endif // __CYGWIN__
+
+ // 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;
+
+#ifndef __CYGWIN__
+ old_umask = umask(0077); // rwx------
+#else
+ // Cygwin: smartd service runs on system account, ensure PID file can be read by admins
+ old_umask = umask(0033); // rwxr--r--
+#endif
+ 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(){
+#ifdef HAVE_GET_OS_VERSION_STR
+ const char * ver = get_os_version_str();
+#else
+ const char * ver = SMARTMONTOOLS_BUILD_HOST;
+#endif
+ PrintOut(LOG_INFO,"smartd version %s [%s] Copyright (C) 2002-6 Bruce Allen\n", PACKAGE_VERSION, ver);
+ 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, marvell, 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[,q], sleep[,q], standby[,q], idle[,q]\n"
+ " -H Monitor SMART Health Status, report if failed\n"
+ " -s REG Do Self-Test at time(s) given by regular expression REG\n"
+ " -l TYPE Monitor SMART log. 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, showtests";
+ 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");
+#ifndef _WIN32
+ PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n");
+#else
+ PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n");
+#endif
+ 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'));
+#if defined(_WIN32) || defined(__CYGWIN__)
+ PrintOut(LOG_INFO," --service\n");
+ PrintOut(LOG_INFO," Running as windows service (see man page), install with:\n");
+#ifdef _WIN32
+ PrintOut(LOG_INFO," smartd install [options]\n");
+ PrintOut(LOG_INFO," Remove service with:\n");
+ PrintOut(LOG_INFO," smartd remove\n\n");
+#else
+ PrintOut(LOG_INFO," /etc/rc.d/init.d/smartd install [options]\n");
+ PrintOut(LOG_INFO," Remove service with:\n");
+ PrintOut(LOG_INFO," /etc/rc.d/init.d/smartd remove\n\n");
+#endif
+#endif // _WIN32 || __CYGWIN__
+ 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_MARVELL_SATA:
+ 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;
+}
+
+// Returns 1 if device recognised as one we do not want to treat as a general
+// SCSI device. Also returns 1 if INQUIRY fails (all "SCSI" devices should
+// respond to INQUIRY). Otherwise returns 0 (i.e. normal SCSI device).
+static int SCSIFilterKnown(int fd, char * device)
+{
+ char req_buff[256];
+ char di_buff[256];
+ int req_len, avail_len, len;
+
+ memset(req_buff, 0, 96);
+ req_len = 36;
+ if (scsiStdInquiry(fd, (unsigned char *)req_buff, req_len)) {
+ /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
+ /* watch this spot ... other devices could lock up here */
+ req_len = 64;
+ if (scsiStdInquiry(fd, (unsigned char *)req_buff, req_len)) {
+ PrintOut(LOG_INFO, "Device: %s, failed on INQUIRY; skip device\n", device);
+ // device doesn't like INQUIRY commands
+ return 1;
+ }
+ }
+ avail_len = req_buff[4] + 5;
+ len = (avail_len < req_len) ? avail_len : req_len;
+ if (len >= 36) {
+ if (0 == strncmp(req_buff + 8, "3ware", 5) || 0 == strncmp(req_buff + 8, "AMCC", 4) ) {
+ PrintOut(LOG_INFO, "Device %s, please try adding '-d 3ware,N'\n", device);
+ PrintOut(LOG_INFO, "Device %s, you may need to replace %s with /dev/twaN or /dev/tweN\n", device, device);
+ return 1;
+ } else if ((len >= 42) && (0 == strncmp(req_buff + 36, "MVSATA", 6))) {
+ PrintOut(LOG_INFO, "Device %s, please try '-d marvell'\n", device);
+ return 1;
+ } else if ((avail_len >= 96) && (0 == strncmp(req_buff + 8, "ATA", 3))) {
+ /* <<<< This is Linux specific code to detect SATA disks using a
+ SCSI-ATA command translation layer. This may be generalized
+ later when the t10.org SAT project matures. >>>> */
+ req_len = 96;
+ memset(di_buff, 0, req_len);
+ if (scsiInquiryVpd(fd, 0x83, (unsigned char *)di_buff, req_len)) {
+ return 0; // guess it is normal device
+ }
+ avail_len = ((di_buff[2] << 8) + di_buff[3]) + 4;
+ len = (avail_len < req_len) ? avail_len : req_len;
+ if (isLinuxLibAta((unsigned char *)di_buff, len)) {
+ PrintOut(LOG_INFO, "Device %s: SATA disks accessed via libata are "
+ "supported by Linux kernel versions 2.6.15-rc1 and above.\n"
+ "Try adding '-d ata' to the smartd.conf config file line.\n", device);
+ return 1;
+ }
+ }
+ }
+ 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 (cfg->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);
+
+ // early skip if device known and needs to be handled by some other
+ // device type (e.g. '-d 3ware,<n>')
+ if (SCSIFilterKnown(fd, device)) {
+ CloseDevice(fd, device);
+ return 2;
+ }
+
+ // 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
+ // a 'more recent' error might actually be a smaller hour number,
+ // if the hour number has wrapped.
+ // There's still a bug here. You might just happen to run a new test
+ // exactly 32768 hours after the previous failure, and have run exactly
+ // 20 tests between the two, in which case smartd will miss the
+ // new failure.
+ PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n",
+ name, newh);
+ MailWarning(cfg, 3, "Device: %s, new Self-Test Log error at hour timestamp %d\n",
+ name, newh);
+ }
+
+ // Needed since self-test error count may DECREASE. Hour might
+ // also have changed.
+ 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, time_t testtime) {
+ // 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.
+ if (!testtime)
+ FixGlibcTimeZoneBug();
+
+ // construct pattern containing the month, day of month, day of
+ // week, and hour
+ epochnow = (!testtime ? time(NULL) : testtime);
+ 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 (!testtime && 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;
+}
+
+// Print a list of future tests.
+void PrintTestSchedule(cfgfile **atadevices, cfgfile **scsidevices){
+ int i, t;
+ cfgfile * cfg;
+ char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN];
+ time_t now; long seconds;
+ int numdev = numdevata+numdevscsi;
+ typedef int cnt_t[4];
+ cnt_t * testcnts; // testcnts[numdev][4]
+ if (numdev <= 0)
+ return;
+ testcnts = calloc(numdev, sizeof(testcnts[0]));
+ if (!testcnts)
+ return;
+
+ PrintOut(LOG_INFO, "\nNext scheduled self tests (at most 5 of each type per device):\n");
+
+ // FixGlibcTimeZoneBug(); // done in PrintOut()
+ now=time(NULL);
+ dateandtimezoneepoch(datenow, now);
+ for (seconds=0; seconds<3600L*24*90; seconds+=checktime) {
+ // Check for each device whether a test will be run
+ time_t testtime = now + seconds;
+ for (i=0; i<numdev; i++) {
+ cfg = (i<numdevata? atadevices[i] : scsidevices[i-numdevata]);
+ for (t=0; t<(i<numdevata?4:2); t++) {
+ char testtype = "LSCO"[t];
+ if (DoTestNow(cfg, testtype, testtime)) {
+ // Report at most 5 tests of each type
+ if (++testcnts[i][t] <= 5) {
+ dateandtimezoneepoch(date, testtime);
+ PrintOut(LOG_INFO, "Device: %s, will do test %d of type %c at %s\n", cfg->name,
+ testcnts[i][t], testtype, date);
+ }
+ }
+ }
+ }
+ }
+
+ // Report totals
+ dateandtimezoneepoch(date, now+seconds);
+ PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date);
+ for (i=0; i<numdev; i++) {
+ cfg = (i<numdevata? atadevices[i] : scsidevices[i-numdevata]);
+ for (t=0; t<(i<numdevata?4:2); t++) {
+ PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg->name, testcnts[i][t],
+ (testcnts[i][t]==1?"":"s"), "LSCO"[t]);
+ }
+ }
+
+ free(testcnts);
+}
+
+// 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;
+ if (powermode >= 0) {
+ int powermode2 = ataCheckPowerMode(fd);
+ if (powermode2 > powermode)
+ PrintOut(LOG_INFO, "Device: %s, CHECK POWER STATUS spins up disk (0x%02x -> 0x%02x)\n", name, powermode, powermode2);
+ powermode = powermode2;
+ }
+
+ switch (powermode){
+ case -1:
+ // SLEEP
+ mode="SLEEP";
+ if (cfg->powermode>=1)
+ dontcheck=1;
+ break;
+ case 0:
+ // STANDBY
+ mode="STANDBY";
+ if (cfg->powermode>=2)
+ dontcheck=1;
+ break;
+ case 0x80:
+ // IDLE
+ mode="IDLE";
+ if (cfg->powermode>=3)
+ dontcheck=1;
+ break;
+ case 0xff:
+ // ACTIVE/IDLE
+ 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);
+ if (!cfg->powerquiet) // to avoid waking up system disk
+ 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)>0)
+ DoATASelfTest(fd, cfg, 'L');
+ // short test
+ else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S', 0)>0)
+ DoATASelfTest(fd, cfg, 'S');
+ // conveyance test
+ else if (!cfg->testdata->not_cap_conveyance && DoTestNow(cfg, 'C', 0)>0)
+ DoATASelfTest(fd, cfg, 'C');
+ // offline immediate
+ else if (!cfg->testdata->not_cap_offline && DoTestNow(cfg, 'O', 0)>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)>0)
+ DoSCSISelfTest(fd, cfg, 'L');
+ // short background test
+ else if (!cfg->testdata->not_cap_short && DoTestNow(cfg, 'S', 0)>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[,q], sleep[,q], standby[,q], idle[,q]");
+ break;
+ case 's':
+ PrintOut(priority, "valid_regular_expression");
+ break;
+ case 'd':
+ PrintOut(priority, "ata, scsi, marvell, 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, "marvell")) {
+ cfg->controller_port =0;
+ cfg->controller_type = CONTROLLER_MARVELL_SATA;
+ } 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") || !strcmp(arg, "never,q"))
+ cfg->powermode = 0;
+ else if (!strcmp(arg, "sleep") || !strcmp(arg, "sleep,q"))
+ cfg->powermode = 1;
+ else if (!strcmp(arg, "standby") || !strcmp(arg, "standby,q"))
+ cfg->powermode = 2;
+ else if (!strcmp(arg, "idle") || !strcmp(arg, "idle,q"))
+ cfg->powermode = 3;
+ else
+ badarg = 1;
+ cfg->powerquiet = !!strchr(arg, ',');
+ 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;
+ }
+
+#ifdef __CYGWIN__
+ setmode(fileno(fp), O_TEXT); // Allow files with \r\n
+#endif
+
+ // configuration file exists
+ PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile);
+
+ // parse config file line by line
+ 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' },
+#if defined(_WIN32) || defined(__CYGWIN__)
+ { "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,"showtests"))) {
+ quit=4;
+ debugmode=1;
+ } else if (!(strcmp(optarg,"errors"))) {
+ quit=5;
+ } else {
+ badarg = TRUE;
+ }
+ break;
+ case 'l':
+ // set the log facility level
+ if (!strcmp(optarg, "daemon"))
+ facility=LOG_DAEMON;
+ else if (!strcmp(optarg, "local0"))
+ facility=LOG_LOCAL0;
+ else if (!strcmp(optarg, "local1"))
+ facility=LOG_LOCAL1;
+ else if (!strcmp(optarg, "local2"))
+ facility=LOG_LOCAL2;
+ else if (!strcmp(optarg, "local3"))
+ facility=LOG_LOCAL3;
+ else if (!strcmp(optarg, "local4"))
+ facility=LOG_LOCAL4;
+ else if (!strcmp(optarg, "local5"))
+ facility=LOG_LOCAL5;
+ else if (!strcmp(optarg, "local6"))
+ facility=LOG_LOCAL6;
+ else if (!strcmp(optarg, "local7"))
+ facility=LOG_LOCAL7;
+ else
+ badarg = TRUE;
+ break;
+ case 'd':
+ // enable debug mode
+ debugmode = 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;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ case 'S':
+ // running as service
+#ifdef __CYGWIN__ // On Windows, option is already handled by daemon_main(), so ignore it
+ is_service = 1;
+#endif
+ break;
+#endif // _WIN32 || __CYGWIN__
+ 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);
+ }
+
+ if (quit==4) {
+ // user has asked to print test schedule
+ PrintTestSchedule(atadevlist, scsidevlist);
+ EXIT(0);
+ }
+
+ // 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) {
+#ifdef __CYGWIN__
+ if (!is_service) // don't fork() if running as service via cygrunsrv
+#endif
+ 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
--- /dev/null
+# Sample configuration file for smartd. See man smartd.conf.
+
+# Home page is: http://smartmontools.sourceforge.net
+
+# $Id: smartd.conf,v 1.40 2006/04/12 14:00:12 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
+# start a short self-test every day between 2-3am, and a long self test
+# Saturdays between 3-4am.
+#/dev/hda -a -o on -S on -s (S/../.././02|L/../../6/03)
+
+# Monitor SMART status, ATA Error Log, Self-test log, and track
+# changes in all attributes except for attribute 194
+#/dev/hdb -H -l error -l selftest -t -I 194
+
+# Linux-specific example: monitor a SATA (Serial ATA) disk which uses
+# the libata driver. This requires a Linux 2.6.15 or later kernel.
+# Note that the disk is addressed via a SCSI device, but the
+# underlying disk type is actually ATA
+# /dev/sda -a -d ata
+
+# 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. Start extended self-tests Wednesdays between 6-7pm and
+# Sundays between 1-2 am
+#/dev/sda -d scsi -s L/../../3/18
+#/dev/sdb -d scsi -s L/../../7/01
+
+# Monitor 4 ATA disks connected to a 3ware 6/7/8000 controller which uses
+# the 3w-xxxx driver. Start long self-tests Sundays between 1-2, 2-3, 3-4,
+# and 4-5 am.
+# NOTE: starting with the Linux 2.6 kernel series, the /dev/sdX interface
+# is DEPRECATED. Use the /dev/tweN character device interface instead.
+# For example /dev/twe0, /dev/twe1, and so on.
+#/dev/sdc -d 3ware,0 -a -s L/../../7/01
+#/dev/sdc -d 3ware,1 -a -s L/../../7/02
+#/dev/sdc -d 3ware,2 -a -s L/../../7/03
+#/dev/sdc -d 3ware,3 -a -s L/../../7/04
+
+# Monitor 2 ATA disks connected to a 3ware 9000 controller which uses
+# the 3w-9xxx driver. Start long self-tests Tuesdays between 1-2 and 3-4 am
+#/dev/twa0 -d 3ware,0 -a -s L/../../2/01
+#/dev/twa0 -d 3ware,1 -a -s L/../../2/03
+
+# HERE IS A LIST OF DIRECTIVES FOR THIS CONFIGURATION FILE.
+# PLEASE SEE THE smartd.conf MAN PAGE FOR DETAILS
+#
+# -d TYPE Set the device type: ata, scsi, marvell, removable, 3ware,N
+# -T TYPE set the tolerance to one of: normal, permissive
+# -o VAL Enable/disable automatic offline tests (on/off)
+# -S VAL Enable/disable attribute autosave (on/off)
+# -n MODE No check. MODE is one of: never, sleep, standby, idle
+# -H Monitor SMART Health Status, report if failed
+# -l TYPE Monitor SMART log. Type is one of: error, selftest
+# -f Monitor for failure of any 'Usage' Attributes
+# -m ADD Send warning email to ADD for -H, -l error, -l selftest, and -f
+# -M TYPE Modify email warning behavior (see man page)
+# -s REGE Start self-test when type/date matches regular expression (see man page)
+# -p Report changes in 'Prefailure' Normalized Attributes
+# -u Report changes in 'Usage' Normalized Attributes
+# -t Equivalent to -p and -u Directives
+# -r ID Also report Raw values of Attribute ID with -p, -u or -t
+# -R ID Track changes in Attribute ID Raw value with -p, -u or -t
+# -i ID Ignore Attribute ID for -f Directive
+# -I ID Ignore Attribute ID for -p, -u or -t Directive
+# -C ID Report if Current Pending Sector count non-zero
+# -U ID Report if Offline Uncorrectable count non-zero
+# -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.
--- /dev/null
+.ig
+Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+
+$Id: smartd.conf.5.in,v 1.73 2006/04/12 14:03:14 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 /usr/local/etc/smartd.conf
+
+.SH PACKAGE VERSION
+CURRENT_CVS_VERSION released CURRENT_CVS_DATE at CURRENT_CVS_TIME
+
+.SH DESCRIPTION
+\fB/usr/local/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/usr/local/etc/smartd.conf\fP is present,
+\fBsmartd\fP reads it at startup, before \fBfork\fP(2)ing into the
+background. If \fBsmartd\fP subsequently receives a \fBHUP\fP signal,
+it will then re-read the configuration file. If \fBsmartd\fP is
+running in debug mode, then an \fBINT\fP signal will also make it
+re-read the configuration file. This signal can be generated by typing
+\fB\<CONTROL-C\>\fP in the terminal window where \fBsmartd\fP is
+running.
+
+.\" DO NOT MODIFY THIS OR THE FOLLOWING TWO LINES. WHAT FOLLOWS
+.\" IS AUTOMATICALLY INCLUDED FROM THE FILE smartd.8.in
+.\" STARTINCLUDE
+
+.SH CONFIGURATION FILE /usr/local/etc/smartd.conf
+In the absence of a configuration file, under Linux
+\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 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]+.
+Under NetBSD/OpenBSD,
+\fBsmartd\fP
+will try to open all existing ATA devices (with entries in /dev)
+.B /dev/wd[0-9]+c
+and all existing SCSI devices
+.B /dev/sd[0-9]+c.
+Under Solaris \fBsmartd\fP will try to open 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.
+Under Windows \fBsmartd\fP will try to open all entries \fB"/dev/hd[a-j]"\fP ("\\\\.\\PhysicalDrive[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-9][0-7]"\fP (ASPI adapter 0-9, ID 0-7) for SCSI
+devices on all versions of Windows.
+Under Darwin, \fBsmartd\fP will open any ATA block storage device.
+
+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 /usr/local/etc/smartd.conf.
+This file contains a list of devices to monitor, with one device per
+line. An example file is included with the
+.B smartmontools
+distribution. You will find this sample configuration file in
+\fB/usr/local/share/doc/smartmontools-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 file
+.B # /usr/local/etc/smartd.conf for monitoring three
+.B # ATA disks, three SCSI disks, six ATA disks
+.B # behind two 3ware controllers and one SATA disk
+.B #
+.nf
+.B # First ATA disk on two different interfaces. On
+.B # the second disk, start a long self-test every
+.B # Sunday between 3 and 4 am.
+.B #
+.B \ \ /dev/hda -a -m admin@example.com,root@localhost
+.B \ \ /dev/hdc -a -I 194 -I 5 -i 12 -s L/../../7/03
+.B #
+.nf
+.B # SCSI disks. Send a TEST warning email to admin on
+.B # startup.
+.B #
+.B \ \ /dev/sda
+.B \ \ /dev/sdb -m admin@example.com -M test
+.B #
+.nf
+.B # Strange device. It\'s SCSI. Start a scheduled
+.B # long self test between 5 and 6 am Monday/Thursday
+.B \ \ /dev/weird -d scsi -s L/../../(1|4)/05
+.B #
+.nf
+.B # Linux-specific: SATA disk using the libata
+.B # driver. This requires a 2.6.15 or greater
+.B # kernel. The device entry is SCSI but the
+.B # underlying disk understands ATA SMART commands
+.B \ \ /dev/sda -a -d ata
+.B #
+.nf
+.B # Four ATA disks on a 3ware 6/7/8000 controller.
+.B # Start short self-tests daily between midnight and 1am,
+.B # 1-2, 2-3, and 3-4 am. Starting with the Linux 2.6
+.B # kernel series, /dev/sdX is deprecated in favor of
+.B # /dev/tweN. For example replace /dev/sdc by /dev/twe0
+.B # and /dev/sdd by /dev/twe1.
+.B \ \ /dev/sdc -d 3ware,0 -a -s S/../.././00
+.B \ \ /dev/sdc -d 3ware,1 -a -s S/../.././01
+.B \ \ /dev/sdd -d 3ware,2 -a -s S/../.././02
+.B \ \ /dev/sdd -d 3ware,3 -a -s S/../.././03
+.B #
+.nf
+.B # Two ATA disks on a 3ware 9000 controller.
+.B # Start long self-tests Sundays between midnight and
+.B # 1am and 2-3 am
+.B \ \ /dev/twa0 -d 3ware,0 -a -s L/../../7/00
+.B \ \ /dev/twa0 -d 3ware,1 -a -s L/../../7/02
+.B #
+.nf
+.B # 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 /usr/local/etc/smartd.conf
+configuration file. Note that
+.B these are NOT command-line options for
+\fBsmartd\fP.
+The Directives below may appear in any order, following the device
+name.
+
+.B For an ATA device,
+if no Directives appear, then the device will be monitored
+as if the \'\-a\' Directive (monitor all SMART properties) had been given.
+
+.B If a SCSI disk is listed,
+it will be monitored at the maximum implemented level: roughly
+equivalent to using the \'\-H \-l selftest\' options for an ATA disk.
+So with the exception of \'\-d\', \'\-m\', \'\-l selftest\', \'\-s\', and
+\'\-M\', the Directives below are ignored for SCSI disks. For SCSI
+disks, the \'\-m\' Directive sends a warning email if the SMART status
+indicates a disk failure or problem, if the SCSI inquiry about disk
+status fails, or if new errors appear in the self-test log.
+
+.B If a 3ware controller is used
+then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?
+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,
+\fImarvell\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 marvell
+\- Under Linux, interact with SATA disks behind Marvell chip-set
+controllers (using the Marvell rather than libata driver).
+
+.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[,q]
+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.
+
+When a periodic test is skipped, \fBsmartd\fP normally writes an
+informal log message. The message can be suppressed by appending
+the option \',q\' to POWERMODE (like \'\-n standby,q\').
+This prevents a laptop disk from spinning up due to this message.
+
+.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 or the '-q showtests' command-line option to verify
+that you constructed \fBREGEXP\fP correctly. The matching order
+(\fBL\fP before \fBS\fP before \fBC\fP before \fBO\fP) ensures that
+if multiple test types are all scheduled for the same hour, the
+longer test type has precedence. This is usually the desired behavior.
+
+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 more than one of the
+following three \-M Directives are given (example: \-M once \-M daily)
+then the final one (in the example, \-M daily) is used.
+
+The valid arguments to the \-M Directive are (one of the following
+three):
+
+.I once
+\- send only one warning email for each type of disk problem detected. This
+is the default.
+
+.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.
+
+In addition, one may add zero or more of the following Directives:
+
+.I test
+\- send a single test email
+immediately upon
+\fBsmartd\fP
+startup. This allows one to verify that email is delivered correctly.
+
+.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/local/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 one sentence summary warning email message string from
+\fBsmartd\fP.
+This message string contains space characters and is NOT quoted. So to
+use $SMARTD_MESSAGE in a bash script you should probably enclose it in
+double quotes.
+.IP \fBSMARTD_FULLMESSAGE\fP 4
+is set to the contents of the entire email warning message string from
+\fBsmartd\fP.
+This message string contains space and return characters and is NOT quoted. So to
+use $SMARTD_FULLMESSAGE in a bash script you should probably enclose it in
+double quotes.
+.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/local/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:
+\fBhttp://www.guzu.net/linux/hddtemp.db\fP
+
+.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/local/sbin/smartctl -a -d $SMART_DEVICETYPE $SMARTD_DEVICE >> /root/msg
+
+# Now email the message to the user at address ADD:
+/bin/mail -s "$SMARTD_SUBJECT" $SMARTD_ADDRESS < /root/msg
+\fP
+.fi
+
+Example 2: This script is for use with \'\-m <nomailer> \-M exec
+PATH\'. It warns all users about a disk problem, waits 30 seconds, and
+then powers down the machine.
+
+.nf
+\fB
+#! /bin/bash
+
+# Warn all users of a problem
+wall \'Problem detected with disk: \' "$SMARTD_DEVICESTRING"
+wall \'Warning message from smartd is: \' "$SMARTD_MESSAGE"
+wall \'Shutting down machine in 30 seconds... \'
+
+# Wait half a minute
+sleep 30
+
+# Power down the machine
+/sbin/shutdown -hf now
+\fP
+.fi
+
+Some example scripts are distributed with the smartmontools package,
+in /usr/local/share/doc/smartmontools-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 and Cygwin package)
+\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)
+\fBDavid Snyder and Sergey Svishchev\fP (OpenBSD 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.73 2006/04/12 14:03:14 ballen4705 Exp $
--- /dev/null
+/*
+ * smartd.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.76 2006/04/12 14:54: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
+ char powerquiet; // skip powermode 'skipping checks' message
+ 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)
--- /dev/null
+#! /bin/sh
+
+# smartmontools init file for smartd
+# Copyright (C) 2002-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+# $Id: smartd.initd.in,v 1.33 2006/04/12 14:54:28 ballen4705 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"
+
+SMARTD_BIN=/usr/local/sbin/smartd
+
+report_unsupported () {
+ echo "Currently the smartmontools package has no init script for"
+ echo "the $1 OS/distribution. If you can provide one or this"
+ echo "one works after removing some ifdefs, please contact"
+ echo "smartmontools-support@lists.sourceforge.net."
+ exit 1
+}
+
+# Red Hat or Yellow Dog or Mandrake
+if [ -f /etc/redhat-release -o -f /etc/yellowdog-release -o -f /etc/mandrake-release -o -f /etc/whitebox-release -o -f /etc/trustix-release -o -f /etc/tinysofa-release ] ; then
+
+# Source function library
+ . /etc/rc.d/init.d/functions
+
+# Source configuration file. This should define the shell variable smartd_opts
+ [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools
+
+ RETVAL=0
+
+ prog=smartd
+
+ case "$1" in
+ start)
+ echo -n $"Starting $prog: "
+ daemon $SMARTD_BIN $smartd_opts
+ touch /var/lock/subsys/smartd
+ echo
+ ;;
+ stop)
+ echo -n $"Shutting down $prog: "
+ killproc $SMARTD_BIN
+ rm -f /var/lock/subsys/smartd
+ echo
+ ;;
+ reload)
+ echo -n $"Reloading $prog daemon configuration: "
+ killproc $SMARTD_BIN -HUP
+ RETVAL=$?
+ echo
+ ;;
+ report)
+ echo -n $"Checking SMART devices now: "
+ killproc $SMARTD_BIN -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_BIN $smartd_opts
+ echo
+ ;;
+ stop)
+ echo -n "Shutting down smartd: "
+ killall $SMARTD_BIN
+ 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
+ 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
+ SMARTDPID=/var/run/smartd.pid
+ [ -x $SMARTD_BIN ] || 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_BIN -- $smartd_opts; then
+ echo "."
+ else
+ echo " (failed)"
+ RET=1
+ fi
+ ;;
+ stop)
+ echo -n "Stopping S.M.A.R.T. daemon: smartd"
+ start-stop-daemon --stop --quiet --oknodo --pidfile $SMARTDPID
+ echo "."
+ ;;
+ restart|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="$SMARTD_BIN"
+ load_rc_config $name
+ elif [ -r /etc/defaults/rc.conf ]; then
+# Not a 5.x system, try the default location for variables
+ . /etc/defaults/rc.conf
+ source_rc_confs
+ elif [ -r /etc/rc.conf ]; then
+# Worst case, fallback to system config file
+ . /etc/rc.conf
+ fi
+
+ if [ -r /etc/rc.subr ]; then
+# Use new functionality from RC-NG
+ run_rc_command "$1"
+ else
+ PID_FILE=/var/run/smartd.pid
+ case "$1" in
+ start)
+ $SMARTD_BIN -p $PID_FILE $smartd_flags
+ echo -n " smartd"
+ ;;
+ stop)
+ kill `cat $PID_FILE`
+ echo -n " smartd"
+ ;;
+ restart)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ *)
+ 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_BIN -p $PID_FILE $smartd_opts
+ echo -n "smartd "
+ ;;
+ stop)
+ [ -f $PID_FILE ] && kill `cat $PID_FILE`
+ echo -n "smartd "
+ ;;
+ restart)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ *)
+ echo "Usage: smartd {start|stop|restart}"
+ exit 1
+ esac
+
+ exit 0
+
+# Cygwin
+elif uname | grep -i CYGWIN > /dev/null 2>&1 ; then
+
+# The following settings may be changed by the configuration file below
+ # Service Name (must be unique)
+ smartd_svcname=smartd
+ # Service display name
+ smartd_svcdisp="CYGWIN smartd"
+ # Service description
+ smartd_svcdesc="\
+Controls and monitors storage devices using the Self-Monitoring \
+Analysis and Reporting Technology System (S.M.A.R.T.) \
+built into ATA and SCSI Hard Drives. \
+http://smartmontools.sourceforge.net/"
+
+# Source configuration file. This should define the shell variable smartd_opts.
+# Email smartmontools-support@lists.sourceforge.net if there is a better choice
+# of path for Cygwin
+
+ [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools
+
+ PID_FILE=/var/run/smartd.pid
+ RETVAL=0
+
+ # Note: "[ -r $PID_FILE ]" is not used here. On Cygwin, this command may
+ # return success even if the file is present but cannot be read by current user.
+ # If smartd is running as service, smartd.pid is owned by local system account
+ # which is different from any user ever executing this script.
+
+ case "$1" in
+ start)
+ if cygrunsrv -L 2>/dev/null | grep "^${smartd_svcname}$" >/dev/null 2>&1; then
+ echo -n "Starting service $smartd_svcname: "
+ cygrunsrv -S "$smartd_svcname"
+ else
+ echo -n "Starting smartd as daemon: "
+ $SMARTD_BIN -p $PID_FILE $smartd_opts
+ fi
+ RETVAL=$?
+ ;;
+ stop)
+ echo -n "Shutting down smartd: "
+ pid="`cat $PID_FILE 2>/dev/null`" && kill "$pid"
+ RETVAL=$?
+ ;;
+ reload)
+ echo -n "Reloading smartd configuration: "
+ pid="`cat $PID_FILE 2>/dev/null`" && kill -HUP "$pid"
+ RETVAL=$?
+ ;;
+ report)
+ echo -n "Checking SMART devices now: "
+ pid="`cat $PID_FILE 2>/dev/null`" && kill -USR1 "$pid"
+ RETVAL=$?
+ ;;
+ restart)
+ $0 stop
+ sleep 1
+ $0 start
+ exit $?
+ ;;
+ install)
+ shift
+ [ $# -eq 0 ] || smartd_opts="$*"
+ dep=
+ if cygrunsrv -L 2>/dev/null | grep "^syslogd$" >/dev/null 2>&1; then
+ dep="-y syslogd"
+ else
+ echo "Warning: syslogd service not installed, smartd will write to windows event log.";
+ fi
+ echo "Installing service ${smartd_svcname}${smartd_opts+ with options '$smartd_opts'}:"
+ cygrunsrv -I "$smartd_svcname" -d "$smartd_svcdisp" -f "$smartd_svcdesc" $dep \
+ -e CYGWIN="$CYGWIN" -p $SMARTD_BIN -a "--service -p ${PID_FILE}${smartd_opts+ }$smartd_opts"
+ RETVAL=$?
+ ;;
+ remove)
+ echo "Removing service $smartd_svcname:"
+ cygrunsrv -R "$smartd_svcname"
+ RETVAL=$?
+ ;;
+ status)
+ echo -n "Checking smartd status: "
+ if cygrunsrv -L 2>/dev/null | grep "^${smartd_svcname}$" >/dev/null 2>&1; then
+ if cygrunsrv -Q "$smartd_svcname" 2>/dev/null | grep "State *: Running" >/dev/null 2>&1; then
+ echo "running as service '$smartd_svcname'."
+ elif ps -e 2>/dev/null | grep " ${SMARTD_BIN}$" >/dev/null 2>&1; then
+ echo "installed as service '$smartd_svcname' but running as daemon."
+ else
+ echo "installed as service '$smartd_svcname' but not running."
+ RETVAL=1
+ fi
+ elif ps -e 2>/dev/null | grep " ${SMARTD_BIN}$" >/dev/null 2>&1; then
+ echo "running as daemon."
+ else
+ echo "not running."
+ RETVAL=1
+ fi
+ exit $RETVAL
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|reload|report|status}"
+ echo " $0 {install [options]|remove}"
+ exit 1
+ esac
+
+ if [ "$RETVAL" -eq 0 ]; then echo "done"; else echo "ERROR"; fi
+ exit $RETVAL
+
+# Add other OSes HERE, using elif...
+else
+ report_unsupported "Unknown"
+fi
+
+# One should NEVER arrive here, except for a badly written case above,
+# that fails to exit.
+echo "SOMETHING IS WRONG WITH THE SMARTD STARTUP SCRIPT"
+echo "PLEASE CONTACT smartmontools-support@lists.sourceforge.net"
+exit 1
--- /dev/null
+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.36
+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.167 2006/04/12 17:39:32 ballen4705 Exp $
+
+# Copyright (C) 2002-6 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
+# [YD] Yuri Dario
+# [CD] Capser Dik
+# [CF] Christian Franke
+# [GF] Guilhem Frézou
+# [DG] Douglas Gilbert
+# [GG] Guido Guenther
+# [GK] Geoff Keating
+# [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
+# [LW] Leon Woestenberg
+# [RZ] Richard Zybert
+
+
+%changelog
+* Wed Apr 12 2006 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ [BA] Update copyright dates to 2006.
+ [DG] [SCSI] Loosen sanity check on Seagate/Hitachi factory information
+ log page so it is not skipped on recent Seagate SCSI disks.
+ [CF] Added command 'smartd -q showtests' to list test schedules.
+ [CF] Added command 'smartctl -P showall MODEL [FIRMWARE]' to list
+ database entries for specific drives and firmware.
+ [PW] Automatically set -v 9,minutes and -v 194,unknown for Maxtor
+ DiamondMax D540X-4G drives.
+ [DG] [SCSI] suppress various outputs when data fails sanity checks.
+ Correct 'last n error events' log page indexing.
+ [DG] [SCSI] changed smartctl exit status to reflect any problems in
+ the most recent 20 self test logs [Leandro Santi]
+ [DG] [SCSI] Fix process return value when scsiGetSmartData() fails
+ in smartctl [Leandro Santi]
+ [BA] Updated docs and error message to reflect Linux libata
+ support for smartmontools starting with the 2.6.15 kernel
+ series. Also init script support for the 'tinysofa' release.
+ [DG] [SCSI] Mask dpofua bit when changing mode pages. Fix failure
+ of 'smartctl -l error'.
+ [EM] Fixed a problem with FreeBSD and 3Ware 'twe' devices
+ [CF] Fixed a regexp in knowndrives table, added regexp syntax check
+ via 'smartctl -P showall'.
+ [CF] Cygwin & Windows: Fixed memory leak in function calling
+ IOCTL_IDE_PASS_THROUGH. Thanks to Fred Schmidt for the problem
+ report.
+ [CF] Cygwin: added cygrunsrv support and commands "install", "remove"
+ and "status" to smartd.initd.
+ [SS] Fix runtime problems on big-engian NetBSD platforms (patch provided
+ by Martin Husemann)
+ [CF] Cygwin smartd: Open smartd.conf in textmode to allow use of
+ Windows editors.
+ [CF] Cygwin smartd: Added option '--service' to allow smartd running
+ as windows service via cygrunsrv. Useful in conjunction with new
+ syslogd support added in Cygwin 1.5.15.
+ [CF] Windows: Added patch to avoid output of non-ascii timezone names.
+ [EM] Incorporate various patches to provide TWE support and support for
+ multiple 3Ware cards, Power Check Support, and FreeBSD 6.x support.
+ Thanks to Rudolf Cejka, Frank Behrens, and Jung-uk Kim.
+ [DG] Silence gcc 4.0.1 compile warning concerning the difference in
+ "signedness" in pointer assignments. Changes to SCSI code
+ and os_linux.c .
+ [PW] Additions to knowndrives table: added missing drive from Quantum
+ Fireball Plus LM series, added QUANTUM BIGFOOT TS10.0A, added
+ ExcelStor J680 and J880, added Western Digital Caviar RE Serial ATA
+ series, added missing drives from Western Digital Caviar SE series,
+ added Seagate Momentus 4200.2 series, added missing drives from
+ Maxtor DiamondMax 10 series, added Fujitsu MHG and MHH series, and
+ added Hitachi Travelstar 5K100 series.
+ [PW] Additions to knowndrives table: added Fujitsu MHU2100AT, added
+ Fujitsu M1623TAU, added missing drives from Seagate Barracuda
+ 7200.8 series, added Seagate Momentus 5400.2 series, and added
+ QUANTUM FIREBALL CR8.4A.
+ [PW] Additions to knowndrives table: added missing drive from Maxtor
+ MaxLine II series, added Maxtor DiamondMax 2880 Ultra ATA series,
+ added Maxtor DiamondMax 17 VL series, added Hitachi Deskstar 7K80
+ series, and added Hitachi Deskstar 7K400 series.
+ [CF] Windows: Fixed unsupported 'smartctl -X' on Win2000/XP by using
+ IOCTL_IDE_PASS_THROUGH instead.
+
+* Tue Apr 20 2005 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ [CF] Cygwin & Windows smartd: Increased SCSI DEVICESCAN range
+ from ASPI adapter 0-3 to 0-9. Added diagnostic messages.
+ [CF] Windows smartd: Added ability to run .bat files via '-M exec'
+ directive.
+ [CF] Cygwin smartd: Added FreeConsole() after fork() to avoid hang
+ of terminated shell console window.
+ [DG] [SCSI] Add code so 'smartctl -A' outputs the number of elements
+ in the grown defect list. When this number is increasing a
+ disk has problems. N.B. Similar logic should be added to smartd.
+ [CF] Windows smartd: Fixed event handling to allow start of another
+ smartd process when service is already running. Useful for testing
+ service configuration changes in debug mode.
+ [PW] Added following drives to knowndrives table: Western Digital Raptor
+ family, Seagate Barracuda 7200.8 family, Maxtor DiamondMax 2160
+ Ultra ATA and DiamondMax 10 families, Hitachi Travelstar E7K60
+ family, Seagate Medalist 17240, 13030, 10231, 8420, and 4310,
+ TOSHIBA MK4018GAP and MK6022GAX, ExcelStor Technology J360, and
+ Western Digital Caviar AC14300.
+ [PW] Added missing Fujitsu MHTxxxxAT and Seagate Barracuda 7200.7 drives
+ to knowndrives table.
+ [PW] Added QUANTUM FIREBALLP LM10.2 to knowndrives table. Thanks to
+ Mike Fleetwood for submitting the patch.
+ [KS] Solaris/SPARC: fixed not to disable automatic offline test and
+ automatic save attributes incorrectly. Thanks to Roy Badami.
+ [BA] Linux: smartd init script now recognizes 'trustix' distro.
+ [DG] [SCSI] Medium and hardware errors were slipping through
+ unreported. Fix linux SCSI sense reporting via SG_IO ioctl.
+ [DG] [SCSI] Change lba of first failure in selftest output to
+ decimal (was hex) to conform with ATA output.
+ [GK] smartd: Detect most self-test failures even if the hour counter
+ has wrapped.
+ [BA] smartctl: list 'marvell' as option if user give invalid
+ -d argument
+ [CF] Windows: fixed SCSI timeout handling to allow long timeouts
+ for selftests.
+ [CF] Fixed buffer overflow issues in printone() and safe_vsnprintf()
+ which results in crash on -V option (at least on Windows).
+ [DG] [SCSI] Add explicit timeouts to INQUIRY and REQUEST SENSE (that
+ were missed in an earlier patch). Could have impacted freebsd.
+ [DG] When linux detects a sata_via_libata disk suggest that user try
+ '-d ata' (rather then '-d libata). Anticipate kernel change.
+ [YD] Added OS/2 and eComStation platform support.
+ [PW] Added Seagate U4 family, Fujitsu MHJ and MHK families, Seagate
+ Barracuda 5400.1, QUANTUM FIREBALLP KX27.3, QUANTUM FIREBALLP KA10.1,
+ and ExcelStor J340 to knowndrives table.
+ [DG] [SCSI] After report of Hitachi IC35L073UCDY10 disks locking up
+ on log page 0x7 (last n error events), check log page (and some
+ others) is supported (via log page 0x0) before probing.
+ [CF] Added safe_v?snprintf() for platforms using v?snprintf()
+ with non standard behaviour on overflow (Windows, old Linux)
+ [CF] smartd: Added message if check power mode spins up disk.
+ [CF] Windows: Added support for READ_LOG on WinNT4 using undocumented
+ pseudo SCSI command via IOCTL_SCSI_PASS_THROUGH.
+ [CF] smartd: Added ',q' option for '-n' directive to suppress 'skipping
+ checks' log message. This prevents a laptop disk from spinning up
+ due to this message. Thanks to Rob MacLachlan and Manfred Schwarb
+ for pointing out problem & solution.
+ [CF] Windows: Added function get_os_version_str() to show OS flavor in
+ copyright message.
+ [CF] Windows: Added function ata_identify_is_cached() to check for outdated
+ SMART enabled bit in identify data.
+ [CF] Windows: Added fix to prevent linkage of smartd specific win32 modules
+ to smartctl.
+ [PW] Added Fujitsu MPG3153AH, Hitachi Endurastar J4K20/N4K20 (formerly
+ DK23FA-20J), Seagate Momentus family, and Maxtor Fireball 3 family
+ to knowndrives table.
+ [PW] Added missing Maxtor DiamondMax 16, Seagate Barracuda ATA IV, and
+ Western Digital Caviar WDxxxAA/WDxxxBA drives to knowndrives table.
+ [CF] Windows: Added ATA check power mode for smartd -n directive.
+ [CF] Windows: Fixed use of new service status flag which causes hang
+ of smartd service on WinNT4.
+ [CF] Windows: Fixed error checking of IOCTL_IDE_PASS_THROUGH (used
+ for READ_LOG on 2000/XP). Added some diagnostic messages on
+ -r ataioctl[,2]. Thanks to Manfred Schwarb for bug report and testing.
+ [BA] Fixed code bug that made it impossible to enable SMART on
+ disks with failing health status. This would happen if the
+ os_*.c author made STATUS and STATUS_CHECK work the same way.
+ I have corrected this at a higher level; we now handle the
+ case where STATUS and STATUS_CHECK are identical without
+ issues.
+ [LW] Make os_linux.c/marvell_command_interface() always return 0 on STATUS.
+ Needed for a disk having bad SMART status.
+ [CF] smartctl: Added drive family printing.
+ [CF] autogen.sh: Allow automake 1.9, added message if automake
+ version is unknown.
+ [BA] smartctl: use locale-specific separators for printing disk
+ capacity. Also use AC_CHECK_HEADERS not AC_CHECK_HEADER in
+ configure.in.
+ [BA] clean-up of #include structure so that -V options to smartd
+ and smartctl work correctly. Please, don't #include header
+ files into other header files.
+
+* Fri Sep 10 2004 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ [BA] smartctl: ATA disks, if SMART ATTRIBUTE THRESHOLDS page has ID
+ errors with some Attributes having NULL IDs, print Attribute
+ info anyway (but issuing a warning to the user).
+ [DG] [SCSI] Decode Last n error events log page; decode track following
+ and positioning errors [Hitachi]
+ [EM] FreeBSD: another tweak, __packed__ introduced in Version 5.0040
+ [EM] Cleaner tweak of fixes for FreeBSD 4.x.
+ [EM] Fix compilation errors under FreeBSD 4.x, as it is still using
+ and old GCC
+ [EM] Remove 3ware/FreeBSD specific files and just include pieces we need
+ [DG] Add logic in smartd to detect 3ware, Marvell controllers and SATA
+ disks behind an ATA-SCSI simulator (in Linux). If specific device
+ types are not given and they are picked in a general SCSI device
+ scan then warn and skip.
+ [GG] insert correct path to smartd into smartd's init script
+ [BA] Changed all default paths in documentation to reflect /usr/local as
+ default path prefix. This affects on-line man pages, primarily.
+ [DS] Added support for OpenBSD.
+ [BA] Added another environment variable SMART_FULLMESSAGE set by
+ the smartd mailing feature, and modified examplescripts/Example1
+ to illustrate it.
+ [BA] Fixed potentially misleading messages of the form:
+ XXX failed: success
+ [DG] emit warning if SATA disk detected using libata in Linux; then exit
+ [PW] Added Seagate U10 family, Hitachi Travelstar 7K60, Fujitsu MHR2020AT,
+ and QUANTUM FIREBALLP AS20.5 to knowndrives table.
+ [DG] Detect 3ware and Marvell controllers from SCSI INQUIRY vendor string
+ and suggest usage of appropriate '-d' argument in smartctl.
+ [LW] Tested the RELEASE_5_33_WITH_MARVELL_SUPPORT branch on
+ actual Marvell 88SX5041 hardware, with success.
+ Merged into HEAD.
+ [BA] Fixed nasty DEVICESCAN bug
+ [BA] Checked in RELEASE_5_33_WITH_MARVELL_SUPPORT branch with
+ some Marvell support.
+ [BA] Additional modifications of Ed's controller scheme. Fixed
+ broken 3ware support under linux, problems with scanning
+ devices in smartd, and other small problems.
+ [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.
+
+* 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 #8404 at
+ http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8404
+- Added new Directive for Configuration file:
+ -C <N> This sets the time in between disk checks to be <N>
+ seconds apart. Note that although you can give
+ this Directive multiple times on different lines of
+ the configuration file, only the final value that
+ is given has an effect, and applies to all the
+ disks. The default value of <N> is 1800 sec, and
+ the minimum allowed value is ten seconds.
+- Problem wasn't the print format. F.L.W. Meunier <0@pervalidus.net>
+ sent me a gcc 3.2 build and I ran it under a debugger. The
+ problem seems to be with passing the very large (2x512+4) byte
+ data structures as arguments. I never liked this anyway; it was
+ inherited from smartsuite. So I've changed all the heavyweight
+ functions (ATA ones, anyone) to just passing pointers, not hideous
+ kB size structures on the stack. Hopefully this will now build OK
+ under gcc 3.2 with any sensible compilation options.
+- 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
+
--- /dev/null
+/*
+ * utility.c
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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>
+#ifdef _WIN32
+#include <mbstring.h> // _mbsinc()
+#endif
+
+#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.61 2006/04/12 14:54:28 ballen4705 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;
+}
+
+#ifdef _WIN32
+// Fix strings in tzname[] to avoid long names with non-ascii characters.
+// If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
+// national language timezone names returned by GetTimezoneInformation().
+static char * fixtzname(char * dest, int destsize, const char * src)
+{
+ int i = 0, j = 0;
+ while (src[i] && j < destsize-1) {
+ int i2 = (const char *)_mbsinc((const unsigned char *)src+i) - src;
+ if (i2 > i+1)
+ i = i2; // Ignore multibyte chars
+ else {
+ if ('A' <= src[i] && src[i] <= 'Z')
+ dest[j++] = src[i]; // "Pacific Standard Time" => "PST"
+ i++;
+ }
+ }
+ if (j < 2)
+ j = 0;
+ dest[j] = 0;
+ return dest;
+}
+#endif // _WIN32
+
+// This value follows the peripheral device type value as defined in
+// SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
+// the ATA standard for packet devices to define the device type.
+const char *packetdevicetype(int type){
+ if (type<0x10)
+ return packet_types[type];
+
+ if (type<0x20)
+ return "Reserved";
+
+ return "Unknown";
+}
+
+
+// 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;
+#ifdef _WIN32
+ char tzfixbuf[6+1];
+#endif
+
+ FixGlibcTimeZoneBug();
+
+ // Get the time structure. We need this to determine if we are in
+ // daylight savings time or not.
+ tmval=localtime(&tval);
+
+ // Convert to an ASCII string, put in datebuffer
+ // same as: asctime_r(tmval, datebuffer);
+ strncpy(datebuffer, asctime(tmval), DATEANDEPOCHLEN);
+ datebuffer[DATEANDEPOCHLEN-1]='\0';
+
+ // Remove newline
+ lenm1=strlen(datebuffer)-1;
+ datebuffer[lenm1>=0?lenm1:0]='\0';
+
+ // correct timezone name
+ if (tmval->tm_isdst==0)
+ // standard time zone
+ timezonename=tzname[0];
+ else if (tmval->tm_isdst>0)
+ // daylight savings in effect
+ timezonename=tzname[1];
+ else
+ // unable to determine if daylight savings in effect
+ timezonename="";
+
+#ifdef _WIN32
+ // Fix long non-ascii timezone names
+ if (!getenv("TZ"))
+ timezonename=fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename);
+#endif
+
+ // Finally put the information into the buffer as needed.
+ snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename);
+
+ return;
+}
+
+// Date and timezone gets printed into string pointed to by buffer
+void dateandtimezone(char *buffer){
+
+ // Get the epoch (time in seconds since Jan 1 1970)
+ time_t tval=time(NULL);
+
+ dateandtimezoneepoch(buffer, tval);
+ return;
+}
+
+// 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)))
+ goto endmassage;
+
+ // move to first instance of "Id:"
+ while (strcmp(filename,"Id:"))
+ if (!(filename=strtok(NULL, delimiters)))
+ goto endmassage;
+
+ // get filename, skip "v", get version and date
+ if (!( filename=strtok(NULL, delimiters) ) ||
+ !( strtok(NULL, delimiters) ) ||
+ !( version=strtok(NULL, delimiters) ) ||
+ !( date=strtok(NULL, delimiters) ) )
+ goto endmassage;
+
+ sprintf(out,"%-16s revision: %-5s date: %-15s", filename, version, date);
+ retVal = (date-copy)+strlen(date);
+
+ endmassage:
+ 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 bi=0, 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 (bi<CVSMAXLEN && (len=massagecvs(strings,here))){
+ bi+=snprintf(block+bi,CVSMAXLEN-bi,"%s %s\n",(bi==0?"Module:":" uses:"),strings);
+ here+=len;
+ }
+ return;
+}
+
+
+// A replacement for perror() that sends output to our choice of
+// printing. If errno not set then just print message.
+void syserror(const char *message){
+
+ if (errno) {
+ // Get the correct system error message:
+ const char *errormessage=strerror(errno);
+
+ // Check that caller has handed a sensible string, and provide
+ // appropriate output. See perrror(3) man page to understand better.
+ if (message && *message)
+ pout("%s: %s\n",message, errormessage);
+ else
+ pout("%s\n",errormessage);
+ }
+ else if (message && *message)
+ pout("%s\n",message);
+
+ return;
+}
+
+// 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;
+}
+
+// POSIX extended regular expressions interpret unmatched ')' ordinary:
+// "The close-parenthesis shall be considered special in this context
+// only if matched with a preceding open-parenthesis."
+//
+// Actual '(...)' nesting errors remain undetected on strict POSIX
+// implementations (glibc) but an error is reported on others (Cygwin).
+//
+// The check below is rather incomplete because it does not handle
+// e.g. '\)' '[)]'.
+// But it should work for the regex subset used in drive database.
+static int check_regex_nesting(const char * pattern)
+{
+ int level = 0, i;
+ for (i = 0; pattern[i] && level >= 0; i++) {
+ switch (pattern[i]) {
+ case '(': level++; break;
+ case ')': level--; break;
+ }
+ }
+ return level;
+}
+
+// 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))
+ || check_regex_nesting(pattern) < 0 ) {
+ pout("Internal error: unable to compile regular expression \"%s\" ", pattern);
+ if (errorcode)
+ printregexwarning(errorcode, compiled);
+ else
+ pout("Unmatched ')'\n");
+ 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;
+}
+
+
+#ifndef HAVE_WORKING_SNPRINTF
+// Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL),
+// and/or return -1 on overflow (old Linux).
+// Below are sane replacements substituted by #define in utility.h.
+
+#undef vsnprintf
+#if defined(_WIN32) && defined(_MSC_VER)
+#define vsnprintf _vsnprintf
+#endif
+
+int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
+{
+ int i;
+ if (size <= 0)
+ return 0;
+ i = vsnprintf(buf, size, fmt, ap);
+ if (0 <= i && i < size)
+ return i;
+ buf[size-1] = 0;
+ return strlen(buf); // Note: cannot detect for overflow, not necessary here.
+}
+
+int safe_snprintf(char *buf, int size, const char *fmt, ...)
+{
+ int i; va_list ap;
+ va_start(ap, fmt);
+ i = safe_vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+ return i;
+}
+
+#endif
--- /dev/null
+/*
+ * utility.h
+ *
+ * Home page of code is: http://smartmontools.sourceforge.net
+ *
+ * Copyright (C) 2002-6 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.43 2006/04/12 14:54:28 ballen4705 Exp $\n"
+
+#include <time.h>
+#include <sys/types.h> // for regex.h (according to POSIX)
+#include <regex.h>
+
+#ifndef HAVE_WORKING_SNPRINTF
+// Substitute by safe replacement functions
+#include <stdarg.h>
+int safe_snprintf(char *buf, int size, const char *fmt, ...);
+int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap);
+#define snprintf safe_snprintf
+#define vsnprintf safe_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);
+
+// Optional functions of os_*.c
+#ifdef HAVE_GET_OS_VERSION_STR
+// Return build host and OS version as static string
+const char * get_os_version_str(void);
+#endif
+
+// returns 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()
+#define CONTROLLER_MARVELL_SATA 0x07 // SATA drives behind Marvell controllers
+
+
+#endif