├── .gitattributes ├── .gitignore ├── CHANGELOG.TXT ├── LICENSE.txt ├── PYTHON-BUILD-TOOLS.txt ├── README-DE.TXT ├── README-FR.TXT ├── README-RU.TXT ├── README.md ├── ScheduledTask.xml ├── erroraction.cmd ├── erroraction_config.cmd ├── erroraction_config ├── command_runner │ ├── __init__.py │ └── elevate.py ├── cxsetup.py ├── erroraction_config.ico ├── erroraction_config.py ├── erroraction_config.ui ├── nuitkahelper.py └── setup_erroraction_config.py ├── fix_badsectors.cmd ├── smartd.conf ├── smartmontools for Windows includes.iss ├── smartmontools for Windows main.iss ├── smartmontools for Windows strings.iss └── unattended ├── erroraction_config.cmd └── smartd.conf /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | 217 | ################# 218 | ## project files 219 | ################# 220 | 221 | /smartd-pyngui/* 222 | /smartmontools-*.win32-setup* 223 | /VCREDIST -------------------------------------------------------------------------------- /CHANGELOG.TXT: -------------------------------------------------------------------------------- 1 | Smartmontools for Windows package 2 | --------------------------------- 3 | 4 | Known issues 5 | 6 | - Mailsend does not support multibyte chars when sending emails under Windows, so not all special characters can be used in warning emails 7 | - Unattended installations are not possible when upstream package is installed 8 | 9 | Changelog 10 | --------- 11 | 12 | [v7.1-1] 17 Nov 2020 13 | - Updatem upstream release to v7.1 14 | - Interim build to fixup issues #23, #25 #27 and #28 15 | - Updated Python to v3.8.6 16 | - Using Nuitka as app builder now 17 | 18 | [v7.0-1] NEVER RELEASED 19 | - Redevelopped UI 20 | - It is now possible to select a configuration file after the UI has loaded 21 | - Got rid of the ugly console windows 22 | - Removed commandline arguments for UI 23 | - Changed UI developpment from pygubu to PySimpleGUI 24 | - Updated upstream release to v7.0 25 | - Updated python from 3.6.4 to 3.7.1 (no XP support with python > 3.4) 26 | - Switched from cx_freeze to Nuitka (PyInstaller like distributions are prone to be detected as viruses) 27 | 28 | [v6.6-1] 10 Apr 2018 29 | - Updated default configuration to include temperature warnings 30 | - UI now asks for UAC privileges 31 | - Various installer and UI fixes 32 | - Updated upstream release to v6.6 33 | - Updated python from 3.4 to 3.6.4 34 | - Switched from py2exe to cx_freeze 35 | - Resolved issue where special characters like 'ö' could make erroraction_config.py fail 36 | - Prevent earlier python versions to interfere with current installation 37 | - Updated pygubu from 0.9.8.1 to 0.9.8.2 38 | - Faster installation process 39 | 40 | [v6.5-2-dev] 12 May 2017 41 | - General work to render smartmontools-win upstream friendly 42 | - Improved smartd-pyngui to allow saving settings without reloading the service 43 | - Allow smartd-pyngui solo installation for usage with upstream package, with smartd.conf file detection 44 | - Check for upstream service presence before installing smartd service 45 | - Uninstallation checks if current smartd service belongs to smartmontools-win, if not asks if it should be uninstalled 46 | - Multiple improvements and fixes in smartd_pyngui 47 | - Made uncorrectable sectors monitoring options more precise 48 | - Made current pending sectors monitoring options more precise 49 | - Added temperature monitoring options 50 | - Fix selftest regexes weren't corretly generated 51 | - Fix script for -M exec needs singlequotes instead of doublequotes to make smartd -q showtests happy 52 | - Made scrollbars follow resized window 53 | - Updated UI text for disambigution about enery saving 54 | - Initial log file is not overwritten by new installations 55 | - Added more explicit error messages on service failures 56 | - Updated pygubu from 0.9.7.8 to 0.9.8.1 57 | - Updated py2exe to 0.9.2.2 58 | 59 | [v6.5-1] 25 Avr 2017 60 | 61 | - Brand new and shiny python GUI for smartd.conf 62 | - New GUI to configure erroraction_config.cmd parameters 63 | - Greatly simplified commandline options 64 | - Custom smartd.conf file can now be distributed directly with the installer executuable (see README for more info) 65 | - Custom erroraction_config.cmd file can now be distributed directly with the installer executable (also see README for more info) 66 | - Previous smartd.conf files are now kept 67 | - Updated upstream release to v6.5-1 68 | - Installer now uses 64 bits binaries on 64 bit systems (following upstream) 69 | - Added optional annoymous install statistics 70 | - Updated mailsend to v1.19 71 | - Improved erroraction.cmd script to detect privileges, and autodetect drives, and add smartd error diagnostics 72 | - Fixed mail password cannot contain exclamation mark (batch hell) 73 | - Added more preflight checks on erroraction script 74 | - Added smartd details to smart log 75 | - Fixed scheduled tests can be disabled in installer 76 | - Fixed scheduled_send.cmd didn't get deleted on uninstall 77 | - Removed a lot of the installer logic from Inno Setup 78 | - Removed old SendEmail support 79 | - Removed legacy smart service uninstall from v5.x series 80 | - Removed russian translation (outdated and not maintained, translators welcome) 81 | - Re-enconded iss files without UTF BOM (issues with Inno Script Studio 5.5.9) 82 | 83 | [v6.4-4] from 06 Apr 2016 84 | 85 | - Updated German translation (Thanks to Wolfgang Stöggl, https://github.com/c72578) 86 | - Updated to Inno Setup building tools to v5.5.9 87 | - Converted all iss files to UTF-8 88 | 89 | [v6.4-3] from 14/07/2015 90 | 91 | - Fixed mail attachment mimetype using mailsend (Thanks to Georges M. Zwingelstein, https://github.com/GMZwinge) 92 | - Fixed mail passwords containing spaces didn't work 93 | - Fixed sendemail didn't work properly 94 | - Added scheduled_send.cmd file (arbitrary file to schedule a erroraction.cmd --test) with ScheduledTask.xml file 95 | - Added --test option to erroraction.cmd to check if service is running and send an email / display local message depending on config 96 | 97 | [v6.4-2] from 04/06/2015 98 | 99 | - Updated the long tests default execution hour accordingly with the new documentation 100 | 101 | [v6.4-1] from 04/06/2015 102 | 103 | - Updated to upstream release v6.4-1 104 | - Fixed a bug where selftests syntax gets incorrect if command line regex is empty 105 | - Updated german translation strings, thanks to Wieland Hoffmann (https://github.com/mineo) 106 | - Updated test email strings 107 | 108 | [v6.3-2] from 06/03/2015 109 | 110 | - Fixed some typos with SSL/TLS mail encryption preventing message sending (Thanks to spacekpe, https://github.com/spacekpe) 111 | - Fixed SMTP_USER and SMTP_PASSWORD to accept special characters (Thanks to spacekpe, https://github.com/spacekpe) 112 | 113 | [v6.3-1] from 13/08/2014 114 | 115 | - Updated to upstream release v6.3-1 116 | - Improved email sending (fixes gmail issues, see README) 117 | - ATTENTION: command line parameters have changed 118 | - Added new commandline mailer from https://github.com/muquit/mailsend 119 | - SendEmail remains as alternative mailer 120 | - Blat supported only stays in erroraction script 121 | - Fixed registry entries path for contextual menu on drives (thanks to Martin Hecklinger) 122 | - Updated Inno Setup building tools to v5.5.5 123 | 124 | [v6.2-3] from 27/05/2014 125 | 126 | - Improved sendemail syntax 127 | 128 | [v6.2-2] from 20/05/2014 129 | 130 | - Improved computer name detection (thanks to tristangrimaux) 131 | - Added a basic (and use at your own risk) script that handles bad sectors 132 | - Updated Inno Setup to 5.5.4 133 | - Fixed and error with smtp password on silent installs 134 | 135 | [v6.2-1] from 27/07/2013 136 | 137 | - Updated to upstream release v6.2-1 138 | - Removed interactive service fix (upstream fixed it) 139 | - Fixed a bug with silent mail parameters (thanks to Matthäus Banach for pointing that out) 140 | - Added the intial log to the test mail as attachment (Feature asked by Ilya Kisleyko) 141 | - Added Russian translation (thanks to Ilya Kisleyko) 142 | - Improved intial log creation 143 | - Changed execution order so initial log file can use manual drive list 144 | - Added (very) basic password obfuscation in configuration file 145 | - Suppress test mail status window if /silent or /verysilent parameter supplied 146 | - Fixed some typos and missing stuff in documentation 147 | - Fixed two missing parameters (thanks to Ilya Kiskeyk for pointing that out) 148 | 149 | [v6.1-4] from 20/06/2013 150 | 151 | - Fixed a typo that prevented smtp authentication in erroraction script (thanks to Boi Feddern at c't Magazin fuer Computertechnik for pointing that out) 152 | 153 | [v6.1-3] from 12/06/2013 154 | 155 | - Fixed a bug where erroraction script writes empty smart log files 156 | 157 | [v6.1-2] from 20/05/2013 158 | 159 | - Upgrades should generally work cleaner and handle previous service uninstallation 160 | - Upgrades on Windows XP should now work without need to stop the smart service manually 161 | - Updated installer logic (cannot install warning support without selection service installation) 162 | - Updated documentation --warningmessage 163 | - Service installation now uses upstream setup (which also installs smartd as delayed start service in NT6x) 164 | - Restart Manager disabled because upstream's service event log integration needed to restart a lot of stuff while upgrading (trying to keep anything upgradable without reboot required) 165 | - Upstream service type is changed to "Non interactive" to prevent errors in event log 166 | - Updated Inno Setup building tools to v 5.5.3 167 | - Minor bugfixes 168 | 169 | [v6.1-1] from 02/03/2013 (non public release, too much beta stuff for production) 170 | 171 | - Updated upstream release to version 6.1 172 | - As upstream started using erroraction like scripting, i updated mine accordingly. 173 | - Local personalized messages supported via Christian Franke's very nice wtssendmessage.exe tool (ohh Yeah) 174 | 175 | [v6.0-7] from 13/03/2013 176 | 177 | - Update log format: Insert version in head. Insert spacer after log so next log is visually more separated from last one 178 | 179 | [v6.0-6] from 27/02/2013 180 | 181 | - No binary updates, only documentation fixes, therefore version number stays the same 182 | - Updated documentation and translations (special thanks to Titus for the German translation that was desperately needed) 183 | 184 | [v6.0-6] from 18/02/2013 185 | 186 | - Fixed some typos in the documentation and in the program 187 | - The first smartmontools run is saved in a file containing smartmontools version 188 | - Changed the default behavior (no local alert messages). This can be overriden by checking GUI entry or CLI parameter 189 | 190 | [v6.0-5] from 03/02/2013 191 | 192 | - Made the test message more explicit so general antispam filters (tested with Exchange integrated filter) won't mark them as spam 193 | - Fixed an issue with smartd.conf file generation for scheduled tests (thanks to Bill Day for pointing that out) 194 | - Fixed some GUI glitches, cleaned up the GUI code 195 | - Corrected a naming Typo (6.01 didn't exist, it was 6.0-1 only for windows installer) 196 | 197 | [v6.0-4] 198 | 199 | - Fixed a problem with overwrite confirmation of smartd.conf.example of a previous installation in silent mode 200 | - Fixed a minor issue in the start menu smartd.conf link (thanks to Willem Pauw for pointing that out) 201 | - Have a longer and nicer test message that won't be caught by standard antispam (hopefully... it worked on mine) 202 | - Cosmetic fixes: truncated messages depending on language 203 | 204 | [v6.0-3] 205 | 206 | - Initial public release 207 | - Updated upstream source 208 | - Temporary removed WTSSendMessage tools, using integrated support from smart deamon 209 | 210 | [v5.43-x] 211 | 212 | - Private beta testing 213 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /PYTHON-BUILD-TOOLS.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deajan/smartmontools-win/852b1bd877e6d167a405e8877cb6f60885779ca4/PYTHON-BUILD-TOOLS.txt -------------------------------------------------------------------------------- /README-DE.TXT: -------------------------------------------------------------------------------- 1 | Smartmontools for Windows Package 2 | (C) 2012-2020 Orsiris de Jong - http://www.netpower.fr 3 | 4 | Smartmontools for Windows ist ein alternatives Package für "Smartmontools" von Bruce Allen und Christian Franke. 5 | Er wurde programmiert, um smartmontools als Dienst zu installieren, Warnungen per email versenden zu können oder Lokal anzeigen, und um die S.M.A.R.T-Überwachung zu konfigurieren. 6 | Das Installationsprogramm kann skriptbasiert per Kommandozeile oder graphisch für eine normale Einzelplatzinstallation benutzt werden. 7 | 8 | Die Konfigurationsdateien werden automatisch geschrieben (können aber trozdem per Hand geändert werden). 9 | 10 | Ein Dienst "SmartD" wird installiert und für automatischen Start konfiguriert. 11 | Dieser Dienst sucht nach allen Laufwerken, die smartmontools überwachen kann und schickt eine email, wenn ein Fehler auftritt. 12 | Eine Logdatei "smart.log" wird angelegt mit allen Laufwerksinformationen, die auch per email geschickt werden. Eine Logdatei "erroraction.log" wird ebenfalls angelegt und enthält alle email Sendedaten und lokale Fehlermeldungen. 13 | 14 | Diese Software und die Software, die installiert wird, wird unter der GPL-Lizenz verteilt. 15 | Es wird keine Haftung für eventuelle Probleme oder Störungen übernommen, die durch den Einsatz dieser Software verursacht werden. 16 | 17 | Dennoch können sie gerne eine email an ozy [at] netpower.fr schreiben für eingeschränkte Unterstüzung in meiner Freizeit. 18 | 19 | Upgrade 20 | ------- 21 | 22 | Die Konfigurationsdateien von älteren Installationen werden behalten. 23 | Die Kommandozeilenparameter von den Installer haben sich viel geändert. Sie müssen ihre installer Scripts aktualisieren für die neuen Kommandozeilenparameter. 24 | 25 | Copyright 26 | --------- 27 | 28 | Der Installer, die Python Benützeroberfläche und der source sind unter GPLv2 lizenziert. 29 | Die folgende Software wird von diesen Program benutzt: 30 | 31 | - smartmontools by Bruce Allen & Christian Franke, http://smartmontools.sourceforge.net 32 | - sendemail by Brandon Zehm, http://caspian.dotconf.net 33 | - Mailsend by Muhammad Muquit, http://www.muquit.com 34 | - Inno Setup by Jordan Russel, http://www.jrsoftware.org 35 | - Gzip by Free Software Foundation, Inc. Copyright (C) 1992, 1993 Jean-loup Gailly, http://gnuwin32.sourceforge.net/ 36 | - Base64 by Matthias Gärtner, http://www.rtner.de/software/base64.htm 37 | - dd by Chrysocome and John Newbigin, http://www.chrysocome.net/dd 38 | 39 | Binärdatein 40 | ----------- 41 | 42 | Sie können die letzten Binärdatein runterladen bei http://www.netpower.fr/smartmontools-win 43 | 44 | Kompilieren 45 | ----------- 46 | 47 | Der Installer kann mit Inno Setup 5.5+ kompiliert werden. 48 | Alle vorstehenden tools mussen geladen werden und die Datein die von iis file angegeben werden kopiert werden. 49 | Python programme sind mit py2exe kompiliert. Nach kompilation müssen die dist datein kopiert werden zu der datei die von iss Datei angegeben wurde. 50 | 51 | 52 | Kommandozeilenparameter 53 | ----------------------- 54 | 55 | smartmontools-win-6.5-x.exe [OPTIONEN] 56 | 57 | [OPTIONEN] 58 | 59 | /COMPONENTS="Komma separate Liste der komponenten" 60 | 61 | Diese Option ubergehen die Defaultoptionen. 62 | 63 | Acceptierbare komponentent sind 64 | core Basic Installation 65 | core\service smartd Dienst installieren 66 | core\service\gui Benützeroberfläche installieren 67 | core\service\mailalert Auf Fehler E-mail senden 68 | core\service\localalert Auf Fehler Error bericht anzeigen 69 | core\scheduledtestalerts Jeden monat ein test Fehler auslösen 70 | fixbadsecttools Defektsektor Reparaturscript installieren 71 | regext Recht-klick SMART Optionen für Festplatten einstellen 72 | updatedb Nach installation smart Festplattendatabase updaten 73 | authorlinks Link zur Internetseite einstellen 74 | statistics Anonyme Installationstatistik senden 75 | 76 | /SILENT Keine Meldungen zur Installation ausgeben 77 | 78 | /SUPPRESSMSGBOXES Konfigurationsdateien überschreiben ohne anfrage 79 | 80 | /HELP Alle Komandozeilenparameter anzeigen 81 | 82 | Beispiele 83 | --------- 84 | 85 | Sie können eine forfertige Konfigurationsdatei zur Installation hunzufügen. 86 | Eine forfertige smartd.conf Datei kann mit den Installationsprogramm automatisch geladen werden. 87 | Eine forfertige erroraction_config.cmd Datei kann mit den Installationsprogram automatisch geladen werden. 88 | Beispieldatein können an folgender Adresse geladen werden: https://github.com/deajan/smartmontools-win/tree/master/unattended 89 | 90 | Die Konfigurationsdateien müssen in der gleichen Datei als das Installationsprogram sein: 91 | - smartmontools-win-6.5-x.exe 92 | - smartd.conf 93 | - erroraction_config.cmd 94 | 95 | Laden mit: 96 | smartmontools-win-6.5-1.exe /COMPONENTS="core\service,core\service\gui,core\service\mailsupport,updatedb,regext,authorlinks,statistics" /SUPPRESSMSGBOXES /SILENT -------------------------------------------------------------------------------- /README-FR.TXT: -------------------------------------------------------------------------------- 1 | Smartmontools for Windows Package 2 | (C) 2012-2020 Orsiris de Jong - http://www.netpower.fr 3 | 4 | 5 | Smartmontools for Windows est un package alternatif pour smartmontools de Bruce Allen et Christian Franke et a été crée afin de pouvoir installer rapidement smartmontools en tant que service, utiliser le support d'alertes mail et locales et préconfigurer les options de monitoring S.M.A.R.T. 6 | L'installation peut se faire en ligne de commandes pour un déploiement massif ou en graphique pour un utilisateur classique. 7 | 8 | Les fichiers de configuration sont générés automatiqueement pour plus de facilité (cela étant, vous pouvez toujours les éditer à la main au besoin). 9 | 10 | Un service nommé "SmartD" est crée et lancé aux démarrage du système. Celui-ci énumére les disques que smartmontools peut surveiller et envoi un email ou affiche un message en cas d'erreur. 11 | Un fichier nommé smart.log est alors crée incluant toutes les informations des disques, et envoyé par mail. Un log des actions d'erreurs est crée en tant que erroraction.log. 12 | 13 | Ce logiciel et les logiciels qu'il installe sont sous licence GPL. Aucune responsabilité ne pourra être engagée cas de problèmes ou dysfonctionnements dus à l'usage de ce logiciel. 14 | 15 | Neanmoins, vous pouvez écrire un email à ozy [at] netpower.fr pour un obtenir un support limité durant mon temps libre. 16 | 17 | Mise à jour 18 | ----------- 19 | 20 | Les fichiers de configuration des versions précédentes sont conservés (à mooins qu'un fichier smartd.conf et/ou erroraction_config.cmd sont fournis avec l'installeur). 21 | Les options en ligne de commande de l'installeur ont énormément changés. Pensez à adapter vos éventuels scripts d'installation à la nouvelle syntaxre (voir ci-dessous). 22 | 23 | Copyrights 24 | ---------- 25 | 26 | Les sources du package d'installation, les interfaces python sont distribués sous la licence GPLv2. 27 | Cet installeur utilise les logiciels suivants: 28 | 29 | - smartmontools by Bruce Allen, http://smartmontools.sourceforge.net 30 | - sendemail by Brandon Zehm, http://caspian.dotconf.net 31 | - Mailsend by Muhammad Muquit, http://www.muquit.com 32 | - Inno Setup by Jordan Russel, http://www.jrsoftware.org 33 | - Gzip by Free Software Foundation, Inc. Copyright (C) 1992, 1993 Jean-loup Gailly, http://gnuwin32.sourceforge.net/ 34 | - Base64 by Matthias Gärtner, http://www.rtner.de/software/base64.html 35 | - dd by Chrysocome and John Newbigin, http://www.chrysocome.net/dd 36 | 37 | Binaires 38 | -------- 39 | 40 | Vous trouverez les derniers binaires sur la page http://www.netpower.fr/smartmontools-win 41 | 42 | Compilation 43 | ----------- 44 | 45 | La compilation fonctionne avec Inno Setup & Innot Preprocessor 5.5+. 46 | Vous aurez besoin de télécharger les logiciels ci-dessus et les extraire aux endroits décrits par le fichier iis. 47 | Les exécutables Python sont crées avec py2exe. Il suffit de renommer le dossier dist crée par les scripts de création d'exécutables. 48 | 49 | Utilisation sous forme de script 50 | -------------------------------- 51 | 52 | smartmontools-win-6.5-x.exe [OPTIONS] 53 | 54 | [OPTIONS] 55 | 56 | /COMPONENTS="liste des composants séparés par une virgule" 57 | 58 | La liste des composants valide est: 59 | core Base de l'installation, ne peut être déselectionnée 60 | core\service Installer le service smartd 61 | core\service\gui Interface graphique pour configurer le service smartd et les alertes 62 | core\service\mailalert Envoyer un email en cas d'alerte 63 | core\service\localalert Afficher un message en cas d'alerte 64 | core\scheduledtestalerts Créer une alerte de test tous les mois 65 | fixbadsecttools Script de réparation de secteurs défectueux 66 | reegext Ajouter des options SMART au menu contextuel des disques durs 67 | updatedb Mettre à jour la base de données des disques après installation 68 | authorlinks Ajouter les liens vers le site de l'auteur 69 | statistics envoyer des statistiques anonymes sur l'installation 70 | 71 | /SILENT Installer smartmontools-win sans afficher l'interface graphique 72 | 73 | /SUPPRESSMSGBOXES Supprime la demande de confirmation d'écrasement de fichiers de configuration existants (à moins que des fichiers de configuration sont fournis avec l'installeur) 74 | 75 | /HELP Affiche l'ensemble des options de l'installeur 76 | 77 | Voir les examples ci-dessous 78 | 79 | Exemples d'utilisation 80 | ---------------------- 81 | 82 | Vous pouvez préconfigurer les options de smartd ainsi que les options d'alertes afin de créer une installation automatique. 83 | Ajouter un fichier préconfiguré smartd.conf dans le dossier de l'installeur suffit à l'utiliser. 84 | Ajouter un fichier préconfiguré erroraction_config.cmd dans le dossier de l'installeur suffit à l'utiliser. 85 | Ces fichiers peuvent être trouvés à l'adressse https://github.com/deajan/smartmontools-win/tree/master/unattended 86 | 87 | Il suffira alors de créer un dossier contenant les fichiers suivants 88 | - smartmontools-win-6.5-x.exe 89 | - smartd.conf 90 | - erroraction_config.cmd 91 | 92 | Pour exécuter l'installation en mode autonome: 93 | smartmontools-win-6.5.x.exe /COMPONENTS="core\service,core\service\gui,core\service\mailsupport,updatedb,regext,authorlinks,statistics" /SUPPRESSMSGBOXES /SILENT -------------------------------------------------------------------------------- /README-RU.TXT: -------------------------------------------------------------------------------- 1 | Smartmontools для Windows Package 2 | (C) 2012-2020 Orsiris de Jong - http://www.netpower.fr 3 | Перевод на русский Кислейко Илья, osterik@gmail.com. Пожалуйста, напишите мне, если заметите ошибку в переводе. 4 | --------------------------------------------------------- 5 | 6 | [EDIT] Newer translation needed here, this document is out of date. 7 | 8 | Параметры командной строки см. ниже 9 | 10 | Smartmontools для Windows это альтернативная сборка пакета smartmontools (созданного Bruce Allen и Christian Franke), которая была сделана, чтоб иметь возможность быстрой и удобной установки smartmontools как сервиса, с поддержкой уведомлений на электронную почту и всплывающими окнами, с заранее настроенными политиками наблюдения за параметрами S.M.A.R.T. 11 | Установщик может быть запущен в "тихом" режиме, используя параметры командной строки, что удобно для массового распространения, или в обычном графическом режиме для рядовых пользователей. 12 | 13 | Во время установки генерируются файлы конфигурации (которые, конечно же, доступны для ручного редактирования). 14 | Также создается служба "SmartD", которая автоматически стартует при запуске системы. Эта служба обнаруживает жесткие диски, за которыми может наблюдать smartmontools, и, в случае выявления ошибок, отправляет сообщение на почту и\или отображает уведомление на компьютере. 15 | При этом в файл "smart.log" записывается вся доступная информация о параметрах SMART, и он прикрепляется к письму. Отчёт о выполненных действиях записывается в файл "erroraction.log" 16 | 17 | Дополнительно, файл "smart.log" остаётся на диске и содержит все накопленные данные о параметрах SMART, на случай обращения по гарантии. 18 | 19 | Данное программное обеспечение(ПО) и установщик распространяются под GPL лицензией. Автор не несет какую-либо ответственность за проблемы или ущерб, которые могут возникнуть при использовании данного ПО. 20 | 21 | Тем не менее - не стесняйтесь писать на электронную почту ozy [at] netpower.fr, я могу чем-нибудь помочь в моё свободное время. 22 | Также, если вам понравился проделанный мною труд или вы используете ПО у себя на работе, не стесняйтесь поддержать мою работу на сайте. 99% поступлений, вероятней всего, пойдёт кофе-машине :) 23 | 24 | Установщик использует следующее программное обеспечение: 25 | 26 | - smartmontools by Bruce Allen & Christian Franke, http://smartmontools.sourceforge.net 27 | - sendEmail by Brandon Zehm, http://caspian.dotconf.net 28 | - Inno Setup by Jordan Russel, http://www.jrsoftware.org 29 | - Gzip by Free Software Foundation, Inc. Copyright (C) 1992, 1993 Jean-loup Gailly, http://gnuwin32.sourceforge.net/ 30 | - Base64 by Matthias Gдrtner, http://www.rtner.de/software/base64.htm 31 | - dd by Chrysocome and John Newbigin, http://www.chrysocome.net/dd 32 | 33 | Binaries 34 | -------- 35 | 36 | You'll find the latest binaries at http://www.netpower.fr/smartmontools-win 37 | You may also compile your own by downloading Inno Setup and the tools listed above. 38 | 39 | Параметры командной строки 40 | ----------------------- 41 | 42 | smartmontools-win-6.4-4.exe [--short=S/../.././08] [--long=L/../../5/12] [--hddlist="/dev/pd0;/dev/csmi0,1"] [--checkhealth=(yes|no)] [--checkataerrors=(yes|no)] [--checkfailureusae=(yes|no)] [--reportselftesterrors=(yes|no] [--reportcurrentpendingsect=(yes|no)] [--reportofflinependingsect=(yes|no)] [--trackchangeusageprefail=(yes|no)] [--ignoretemperature=(yes|no)] [--powermode=(never|sleep|standby|idle)] [--maxskips=7] [-f source@mail.tld -t destination@mail.tld -s smtp.server.tld [-u smtpuser] [-p smtppassword] [--tls=no]] [--localmessages=(yes|no)] [--warningmessage="Your custom alert message"] [--compresslogs=(yes|no)] [--keepfirstlog=(yes|no)] [--sendtestmessage=(yes|no)] [/silent] 43 | 44 | --short=S/../.././13 Регулярное выражение, определяющее расписание запуска краткого(базового) теста самопроверки диска, по умолчанию - каждый день в 8:00 (подробнее см. ниже или руководство по smartd.conf) 45 | You may also set this parameter to no if you don't want to run short selftests 46 | --long=L/../../5/12 Регулярное выражение, определяющее расписание запуска полного(расширенного) теста самопроверки диска, по умолчанию - в пятницу в 8:00 (подробнее см. ниже или руководство по smartd.conf) 47 | You may also set this parameter to no if you don't want to run long selftests 48 | --hddlist="/dev/pd0;/dev/pd1;/dev/sdc" Список дисков, разделённый двоеточиями. Если не указан - диски будут определены автоматически. 49 | Пример: --hddlist="/dev/csmi0,0;/dev/csmi0,1" для Intel RAID из двух дисков (Т.к. автоматическое определение не всегда срабатывает с Intel RAID) 50 | --checkhealth=(yes|no) Наблюдать за статусом SMART, сообщать о возникших проблемах, по умолчанию включено 51 | --checkataerrors=(yes|no) Сообщать о росте количества ошибок в журнале SMART «ошибки», по умолчанию включено 52 | --checkfailureusage=(yes|no) Наблюдение за отказами в любых значениях "Usage" атрибутов. Это не-критичные атрибуты (температура, число запусков и т.п.) изменение которых не свидетельствует о скором отказе диска, но говорит о не оптимальном режиме работы диска, что может вызвать сокращение его срока службы. По умолчанию включено 53 | --reportselftesterrors=(yes|no) Сообщать о росте количества ошибок в журнале SMART «самопроверка», по умолчанию включено 54 | --reportcurrentpendingsect=(yes|no) по умолчанию включено 55 | --reportofflinependingsect=(yes|no) по умолчанию включено 56 | --trackchangeusageprefail=(yes|no) Сообщать если значения атрибутов групп "Prefailure" (критичных) или "Usage"(использования) изменились со времени прошлой проверки, по умолчанию включено 57 | --ignoretemperature=(yes|no) Не отслеживать изменения температуры, по умолчанию включено 58 | --powermode=(never|sleep|standby|idle) = В каком состоянии энергосбережения должен находиться диск для запуска тестов. По умолчанию диск проверяется, если он не в спящем режиме. 59 | --maxskips=N Максимальное количество тестов, пропущенных из-за несоответствия режимов энергосбережения, после которых тест будет запущен принудительно. По умолчанию =7 60 | 61 | -f Адрес e-mail отправителя, с которого будут отправляться отчёты 62 | -t Адрес e-mail получателя сообщений 63 | -s SMTP-сервер 64 | -u логин входа на SMTP-сервер (не обязательно) 65 | -p пароль входа на SMTP-сервер(не обязательно) 66 | --tls=(no|auto|yes) Использовать TLS для доступа на почтовый сервер, по умолчанию no 67 | --localmessages=(no|yes) Показывать предупреждения и сообщения об ошибках на компьютере, где установлена программа, по умолчанию no 68 | --warningmessage="Пользовательское сообщение об ошибке", если не установлено, то будет использоваться сообщение по умолчанию 69 | --compresslogs=(no|yes) Архивировать журналы при отправке, по умолчанию yes 70 | --keepfirstlog=(no|yes) Создать файл smart.(version).log, содержащий всю доступную информацию о всех дисках, по умолчанию yes 71 | --sendtestmessage=(no|yes), Отправить тестовое сообщение, по умолчанию yes 72 | /silent или /verysilent Параметры запуска установки в "тихом" режиме. Обратите внимание - эти параметры записываются через слэш "/", т.к. это переключатели внутренней логики установщика Inno Setup 73 | 74 | См. примеры ниже 75 | 76 | Регулярные выражения, определяющее расписание запуска теста самопроверки диска 77 | ---------------------------- 78 | 79 | Регулярные выражения должны выглядеть следующим образом: T/MM/DD/d/HH, где: 80 | T = Тип теста (S=краткий(short), L=полный(long)) 81 | MM = Месяц (январь = 01, декабрь = 12) 82 | DD = Число месяца (01...31) 83 | d = День недели (понедельник = 1, воскресенье = 7) 84 | HH = Час в 24-х часовом формате 85 | 86 | Параметры даты\времени можно заменить на точки, которые рассматриваются как шаблоны. Следующее регулярное выражение запланирует проведение полного теста каждые вторник и пятницу в 2 часа ночи: 87 | 88 | L/../../[2,5]/02 89 | 90 | Примеры 91 | -------- 92 | 93 | Простейший сценарий установки: 94 | 95 | smartmontools-win-6.4-4.exe -f sourcemail@example.tld -t destination@example.tld -s smtp.of.your.isp.com /silent 96 | 97 | Эта команда установит smartmontools в "тихом" режиме, настроит оповещения по почте, авто-определение дисков, используя все средства мониторинга, запланирует проведение краткого теста каждый день в 8 утра и полного теста в пятницу в 12 часов. 98 | 99 | Другой пример использует почтовый сервер вашего провайдера (с авторизацией и TLS-шифрованием), не игнорирует колебания температуры диска, отображает предупреждающие сообщения на компьютере и будет производить краткий тест каждый день в 9 утра и полный тест во вторник и воскресенье в 2 часа ночи для дисков /dev/pd0 и /dev/csmi0,1: 100 | 101 | smartmontools-win-6.4-4.exe -f sourcemail@example.tld -t destination@example.tld -s smtp.of.your.isp.com -u username@smtp.server.tld -p pA55W0RD --tls=yes --ignoretemperature=no --hddlist=/dev/pd0;/dev/csmi0,1 --short=S/../.././09 --long=L/../../[2,7]/02 --localmessages=yes /silent 102 | 103 | 104 | -------------------------------------------------------------- 105 | 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Smartmontools for Windows Package 2 | (C) 2012-2020 Orsiris de Jong - http://www.netpower.fr 3 | 4 | Smartmontools For Windows is an alternate package for smartmontools by Bruce Allen and Christian Franke, that has been created to smoothly install smartmontools as service, 5 | support out of the box mail or local alerts, and configure smart daemon options with a graphical user interface. 6 | Installation can be run silently with command line parameters for massive deployments, or with a graphical user interface. 7 | 8 | Configuration files are automatically generated (but you can still enjoy manual editing of course). 9 | A service called "smartd" is created and launched at system startups. This service will enumerate hard disks smartmontools can monitor and send an email and/or show a local message in case of errors. 10 | Everytime smartd detects an issue, the current states of the drives are written to smart.log and an alert is triggered. 11 | When mail / local alerts are triggered, all actions regarding alerts are logged to erroraction.log. 12 | 13 | On install, the current states of all drives smartd can detect are written to smartmontools-install-(version).log for warranty issues. 14 | 15 | The software has been tested on multiple platforms, nevertheless no responsibility will be taken for any problems or malfunctions that may occur while using this software. 16 | Anyway, feel free to send a mail to ozy [at] netpower.fr for support on my free time. 17 | 18 | ## Upgrade path 19 | 20 | The configuration from previous installations is now kept (unless a smartd.conf and/or and erroraction_config.cmd file is provided along with the installer script). 21 | The commandline options of the installer have heavily changed. Be sure to update your mass installer scripts according to new commandline syntax (see below). 22 | 23 | ## Copyrights 24 | 25 | The package itself, the python interfaces and it's source code is licensed under GPLv2. 26 | Additionnaly, it uses the following free software: 27 | 28 | - smartmontools by Bruce Allen & Christian Franke, http://smartmontools.sourceforge.net 29 | - smartd-pyngui by Orsiris de Jong, http://github.com/deajan/smartd-pyngui 30 | - Mailsend by Muhammad Muquit, http://www.muquit.com 31 | - Inno Setup by Jordan Russel, http://www.jrsoftware.org 32 | - Gzip by Free Software Foundation, Inc. Copyright (C) 1992, 1993 Jean-loup Gailly, http://gnuwin32.sourceforge.net/ 33 | - Base64 by Matthias Gärtner, http://www.rtner.de/software/base64.htm 34 | - dd by Chrysocome and John Newbigin, http://www.chrysocome.net/dd 35 | 36 | ## Binaries 37 | 38 | You'll find the latest binaries at http://www.netpower.fr/smartmontools-win 39 | 40 | ## Useful command line parameters 41 | 42 | smartmontools-win-6.6-x.exe [OPTIONS] 43 | 44 | [OPTIONS] 45 | 46 | /COMPONENTS="comma separated list of component names" 47 | 48 | This setting overrides the default selection. 49 | 50 | Valid components are: 51 | core Basic install, cannot be unselected 52 | core\service Install smartd service 53 | core\service\gui Graphical user interface for smartd and alerts 54 | core\service\mailalert On alerts send an email 55 | core\service\localalert On alerts show messages on screen 56 | core\scheduledtestalerts Trigger a test alert every month 57 | fixbadsecttools Fix bad sector script 58 | regext Register SMART right click actions on drives 59 | updatedb Update drive database right after installation 60 | authorlinks Include links to the authors websites 61 | statistics Send anonymous install statistics 62 | 63 | /SILENT Installs smartmontools-win silently, without showing the configuration GUI. 64 | 65 | /SUPPRESSMSGBOXES Removes the configuration files overwrite confirmation and keep the original configuration (unless new config files are supplied along with the installer). 66 | 67 | /HELP Shows all possible commandline switches 68 | 69 | See examples below 70 | 71 | ## Unattended examples 72 | 73 | You may want to preconfigure smartd settings or alert setting when making an unattended installation. 74 | In that case you can install the package on a test computer, use the GUI to configure the service and alerts, and use the generated configuration files for a mass installation. 75 | Putting a preconfigured smartd.conf file along with the setup exe will load it automatically. 76 | Putting a preconfigured erroraction_config.cmd file along with the setup exe will automatically configure alert options. 77 | Example files can be found at https://github.com/deajan/smartmontools-win/tree/master/unattended 78 | 79 | Put the following files in the same directory 80 | - smartmontools-win-7.1-1.exe 81 | - smartd.conf 82 | - erroraction_config.cmd 83 | 84 | Then run: 85 | smartmontools-win-7.1-1.exe /COMPONENTS="core\service,core\service\gui,core\service\mailsupport,updatedb,regext,authorlinks,statistics" /SUPPRESSMSGBOXES /SILENT 86 | 87 | ## Compilation 88 | 89 | Compilation works with Inno Setup & Inno Preprocessor 5.5+. 90 | You'll need to download all the software mentionned above and extract them to the corresponding directories listed in main iss file. 91 | 92 | ## Build python executables 93 | 94 | In order to build python executables from source, you'll need: 95 | 96 | pip install pygubu pywin32 cx_freeze 97 | 98 | You may then run cxsetup.py in order to create executable versions of smartd-pyngui and erroraction_config 99 | -------------------------------------------------------------------------------- /ScheduledTask.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2015-06-22T13:48:23 5 | odejong 6 | 7 | 8 | 9 | 2015-06-22T12:00:00 10 | true 11 | 12 | 13 | 1 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | LeastPrivilege 35 | S-1-5-18 36 | 37 | 38 | 39 | IgnoreNew 40 | true 41 | true 42 | true 43 | true 44 | false 45 | 46 | true 47 | false 48 | 49 | true 50 | true 51 | false 52 | false 53 | false 54 | P3D 55 | 7 56 | 57 | 58 | 59 | "[PATH]\erroraction.cmd" 60 | --test 61 | [PATH] 62 | 63 | 64 | -------------------------------------------------------------------------------- /erroraction.cmd: -------------------------------------------------------------------------------- 1 | :: Smartmontools for Windows package v6.5 erroraction.cmd 2017042401 2 | :: http://www.netpower.fr 3 | :: (L) 2012-2017 by Orsiris de Jong 4 | 5 | :: Config can be changed in erroraction_config.cmd 6 | 7 | :: CHANGELOG: 8 | :: 24 Avr 2017: 9 | :: - smart.log now also includes the original error message from smartd service 10 | :: 17 Avr 2017: 11 | :: - Fixed bogus preflight function end 12 | :: 13 Avr 2017: 13 | :: - Fixed preflight checks because of ambiguous batch syntax 14 | :: 12 Avr 2017: 15 | :: - Added more preflight checks 16 | :: - Fixed syntax in smartctl device erxpansion 17 | :: - Added exit code 18 | :: 12 Nov 2016: 19 | :: - Fixed password cannot contain '!' character 20 | :: - Added -M environment variables from smartd 21 | :: - Added date in logs 22 | :: 10 Nov 2016: 23 | :: - Added default mailer 24 | :: - Added admin privileges check 25 | :: - CreateSmartOutput now uses drive definitions found in smartd.conf in order to get drive status 26 | :: - Added GetEnvironment function to check for executables before launching 27 | :: - Better test message 28 | 29 | @echo off 30 | :: Needed in order to let password end with '!' character 31 | setlocal disabledelayedexpansion 32 | 33 | :: Get currentdir 34 | :: Get Script working dir if erroraction.cmd is launched as scheduled task 35 | set curdir=%~dp0 36 | set curdir=%curdir:~0,-1% 37 | 38 | :: Load autgenerated configuration 39 | call "%curdir%\erroraction_config.cmd" 40 | 41 | set DEBUG=yes 42 | set SCRIPT_ERROR=0 43 | 44 | set ERROR_LOG_FILE=%curdir%\erroraction.log 45 | set SMART_LOG_FILE=%curdir%\smart.log 46 | 47 | :: Add SMARTD environment variables to WARNING_MESSAGE 48 | set SMARTD_WARNING_MESSAGE=SMARTD DETAILS: %SMARTD_TFIRST% %SMARTD_FULLMESSAGE% %SMARTD_DEVICE% %SMARTD_DEVICETYPE% %SMARTD_DEVICESTRING% %SMARTD_FAILTYPE% 49 | set WARNING_MESSAGE=%WARNING_MESSAGE% - %SMARTD_WARNING_MESSAGE% 50 | 51 | IF "%1"=="--dryrun" ( set DRY=1 ) ELSE ( set DRY=0 ) 52 | IF "%1"=="--test" ( call:Tests ) ELSE ( set TEST=0 ) 53 | 54 | :: GetEnvironment is the only function that triggers premature end of the script as other failures might not interrupt processing 55 | call:GetEnvironment 56 | IF "!SCRIPT_ERROR!"=="1" GOTO END 57 | call:GetComputerName 58 | call:CreateSmartOutput 59 | call:Mailer 60 | call:LocalMessage 61 | GOTO END 62 | 63 | 64 | :Log 65 | echo %DATE:~0,2%-%DATE:~3,2%-%DATE:~6,4% %TIME:~0,2%H%TIME:~3,2%m%TIME:~6,2%s - %~1 >> "%ERROR_LOG_FILE%" 66 | echo %~1 67 | GOTO:EOF 68 | 69 | :Tests 70 | set TEST=1 71 | SC QUERY smartd | FINDSTR "RUNNING" > nul 2> nul 72 | IF "%ERRORLEVEL%"=="0" ( 73 | set SERVICE_RUNS=1 74 | set WARNING_MESSAGE=Smartmontools for Windows test: Service smartd is runinng 75 | ) ELSE ( 76 | set SERVICE_RUNS=0 77 | set WARNING_MESSAGE=Alert: Smartmontools for Windows test: Service smartd is not running 78 | ) 79 | GOTO:EOF 80 | 81 | :GetEnvironment 82 | 83 | :: Check for PC privileges :) 84 | net session >nul 2>&1 85 | IF NOT %ERRORLEVEL%==0 ( 86 | call:Log "PC checked for insufficient privileges" 87 | SET SCRIPT_ERROR=1 88 | ) 89 | dir "%curdir%\smartd.conf" > nul 2> nul 90 | IF NOT %ERRORLEVEL%==0 ( 91 | call:Log "Missing smartd.conf file" 92 | SET SCRIPT_ERROR=1 93 | ) 94 | dir "%curdir%\smartctl.exe" > nul 2> nul 95 | IF NOT %ERRORLEVEL%==0 ( 96 | call:Log "Missing smartctl.exe file" 97 | SET SCRIPT_ERROR=1 98 | ) 99 | 100 | :: Incoherent %ERRORLEVEL% and !ERRORLEVEL!... Get your shit toghether cmd 101 | dir "%curdir%\wtssendmsg.exe" > nul 2> nul 102 | IF NOT %ERRORLEVEL%==0 ( 103 | IF "%LOCAL_ALERT%"=="yes" call:Log "Missing wtssendmsg.exe file. Did you install without local alert support ?" && SET SCRIPT_ERROR=1 104 | ) 105 | 106 | dir "%curdir%\mailsend.exe" > nul 2> nul 107 | IF NOT %ERRORLEVEL%==0 ( 108 | IF "%MAIL_ALERT%"=="yes" call:Log "Missing mailsend.exe file. Did you install without mail alert support ?" && SET SCRIPT_ERROR=1 109 | ) 110 | 111 | dir "%curdir%\base64.exe" > nul 2> nul 112 | IF NOT %ERRORLEVEL%==0 ( 113 | IF "%MAIL_ALERT%"=="yes" call:Log "Missing base64.exe file. Did you install without mail alert support ?" && SET SCRIPT_ERROR=1 114 | ) 115 | 116 | dir "%curdir%\gzip.exe" > nul 2> nul 117 | IF NOT %ERRORLEVEL%==0 ( 118 | IF "%MAIL_ALERT%"=="yes" call:Log "Missing gzip.exe file. Did you install without mail alert support ?" && SET SCRIPT_ERROR=1 119 | ) 120 | GOTO:EOF 121 | 122 | :CheckMailValues 123 | echo "%SOURCE_MAIL%" | findstr /I "@" > nul 124 | IF %ERRORLEVEL%==1 ( 125 | call:Log "Source mail not set" 126 | GOTO END 127 | ) 128 | echo "%DESTINATION_MAIL%" | findstr /I "@" > nul 129 | IF %ERRORLEVEL%==1 ( 130 | call:Log "Destination Mail not Set" 131 | GOTO END 132 | ) 133 | IF "%SUBJECT%"=="" ( 134 | call:Log "Mail subject not set" 135 | GOTO END 136 | ) 137 | echo "%SMTP_SERVER%" | findstr /I "." > nul 138 | IF %ERRORLEVEL%==1 ( 139 | call:Log "Smtp sever not set" 140 | GOTO END 141 | ) 142 | call:Log "Configuration file check success." 143 | GOTO:EOF 144 | 145 | :CreateSmartOutput 146 | echo ------------------------------------------------------------------------------------------------- >> "%SMART_LOG_FILE%" 147 | echo %DATE:~0,2%-%DATE:~3,2%-%DATE:~6,4% %TIME:~0,2%H%TIME:~3,2%m%TIME:~6,2%s >> "%SMART_LOG_FILE%" 148 | echo %SMARTD_WARNING_MESSAGE% >> "%SMART_LOG_FILE%" 149 | echo ------------------------------------------------------------------------------------------------- >> "%SMART_LOG_FILE%" 150 | for /F %%d in ('type "%curdir%\smartd.conf" ^| findstr /R /C:"^/"') do "%curdir%\smartctl.exe" -a %%d >> "%SMART_LOG_FILE%" 151 | for /F %%d in ('type "%curdir%\smartd.conf" ^| findstr /R /C:"^DEVICESCAN"') do SET DEVICESCAN=yes 152 | IF "%DEVICESCAN%"=="yes" FOR /F "delims= " %%i in ('"%curdir%\smartctl.exe" --scan') do "%curdir%\smartctl.exe" -a %%i >> "%SMART_LOG_FILE%" 153 | IF %ERRORLEVEL%==1 call:Log "Cannot extract some or all smartctl data." 154 | GOTO:EOF 155 | 156 | :GetComputerName 157 | set COMPUTER_FQDN=%COMPUTERNAME% 158 | IF NOT "%USERDOMAIN%"=="" set COMPUTER_FQDN=%COMPUTERNAME%.%USERDOMAIN% 159 | IF NOT "%USERDNSDOMAIN%"=="" set COMPUTER_FQDN=%COMPUTERNAME%.%USERDNSDOMAIN% 160 | GOTO:EOF 161 | 162 | :GetPwd 163 | :: Disable delayed expansion as there is no way the password can end with an exclamation mark if set 164 | :: Dear people who invented batch, delayed expansion and those superb %dp~n variable namings, there's a special place in hell (or whatever afwul thing you believe in) for you ! 165 | FOR /F "delims=" %%p IN ('"echo %SMTP_PASSWORD% | "%curdir%\base64.exe" -d"') DO SET SMTP_PASSWORD=%%p 166 | GOTO:EOF 167 | 168 | :Mailer 169 | IF NOT "%MAIL_ALERT%"=="yes" GOTO:EOF 170 | IF "!TEST!"=="1" ( 171 | set SUBJECT=Smart test on %COMPUTER_FQDN% 172 | ) ELSE ( 173 | set SUBJECT=Smart Error on %COMPUTER_FQDN% 174 | ) 175 | set MAIL_CONTENT=%DATE% - %WARNING_MESSAGE% 176 | 177 | call:CheckMailValues 178 | call:GetPwd 179 | IF "%MAILER%"=="blat" call:MailerBlat 180 | IF "%MAILER%"=="sendemail" call:MailerSendEmail 181 | IF "%MAILER%"=="mailsend" call:MailerMailSend 182 | IF "%MAILER%"=="" call:MailerMailSend 183 | GOTO:EOF 184 | 185 | :MailerMailSend 186 | set attachment= 187 | IF "%COMPRESS_LOGS%"=="yes" ( 188 | "%curdir%\gzip" -c "%SMART_LOG_FILE%" > "%SMART_LOG_FILE%.gz" 189 | set attachment=-attach "%SMART_LOG_FILE%.gz,application/gzip,a" 190 | ) ELSE ( 191 | set attachment=-attach "%SMART_LOG_FILE%" 192 | ) 193 | 194 | IF "%SECURITY%"=="tls" set encryption=-starttls 195 | IF "%SECURITY%"=="ssl" set encryption=-ssl 196 | 197 | IF NOT "%SMTP_USER%"=="" set smtpuser=-auth -user "%SMTP_USER%" 198 | IF NOT "%SMTP_PASSWORD%"=="" set smtppassword=-pass "%SMTP_PASSWORD%" 199 | IF %DRY%==1 ( 200 | echo "%curdir%\mailsend.exe" -f "%SOURCE_MAIL%" -t "%DESTINATION_MAIL%" -sub "%SUBJECT%" -M "%MAIL_CONTENT%" %attachment% -smtp "%SMTP_SERVER%" -port %SMTP_PORT% %smtpuser% %smtppassword% %encryption% 201 | ) ELSE ( 202 | "%curdir%\mailsend.exe" -f "%SOURCE_MAIL%" -t "%DESTINATION_MAIL%" -sub "%SUBJECT%" -M "%MAIL_CONTENT%" %attachment% -smtp "%SMTP_SERVER%" -port %SMTP_PORT% %smtpuser% %smtppassword% %encryption% 203 | ) 204 | IF NOT %ERRORLEVEL%==0 ( 205 | set SCRIPT_ERROR=1 206 | Call:Log "Sending mail using mailsend failed." 207 | ) 208 | GOTO:EOF 209 | 210 | :: SendEmail from Brandon Zehm mailer (http://caspian.dotconf.net), kept for compatibility 211 | :MailerSendEmail 212 | set attachment= 213 | IF "%COMPRESS_LOGS%"=="yes" ( 214 | "%curdir%\gzip" -c "%SMART_LOG_FILE%" > "%SMART_LOG_FILE%.gz" 215 | set attachment=-a "%SMART_LOG_FILE%.gz" 216 | ) ELSE ( 217 | set attachment=-a "%SMART_LOG_FILE%" 218 | ) 219 | 220 | IF "%SECURITY%"=="tls" set encryption=-o tls=yes 221 | IF "%SECURITY%"=="ssl" set encryption=-o tls=auto 222 | 223 | IF NOT "%SMTP_USER%"=="" set smtpuser=-xu "%SMTP_USER%" 224 | IF NOT "%SMTP_PASSWORD%"=="" set smtppassword=-xp "%SMTP_PASSWORD%" 225 | IF %DRY%==1 ( 226 | echo "%curdir%\sendemail.exe" -f "%SOURCE_MAIL%" -t "%DESTINATION_MAIL%" -u "%SUBJECT%" -m "%MAIL_CONTENT%" %attachment% -s %SMTP_SERVER%:%SMTP_PORT% %encryption% %smtpuser% %smtppassword% 227 | ) ELSE ( 228 | "%curdir%\sendemail.exe" -f "%SOURCE_MAIL%" -t "%DESTINATION_MAIL%" -u "%SUBJECT%" -m "%MAIL_CONTENT%" %attachment% -s %SMTP_SERVER%:%SMTP_PORT% %encryption% %smtpuser% %smtppassword% 229 | ) 230 | IF NOT %ERRORLEVEL%==0 ( 231 | set SCRIPT_ERROR=1 232 | Call:Log "Sending mail using sendemail failed." 233 | ) 234 | GOTO:EOF 235 | 236 | :: Blat support needs blat mail parameters already in registry 237 | :MailerBlat 238 | IF %DRY%==1 ( 239 | echo blat - -q -subject "%SUBJECT%" -to "%DESTINATION_MAIL%" < "%MAIL_CONTENT%" 240 | ) ELSE ( 241 | blat - -q -subject "%SUBJECT%" -to "%DESTINATION_MAIL%" < "%MAIL_CONTENT%" 242 | ) 243 | 244 | IF NOT %ERRORLEVEL%==0 ( 245 | set SCRIPT_ERROR=1 246 | Call:Log "Sending mail using blat failed". 247 | ) 248 | :LocalMessage 249 | IF NOT "%LOCAL_ALERT%"=="yes" GOTO:EOF 250 | set local_alert_type_switch= 251 | IF "%LOCAL_ALERT_TYPE%"=="active" set local_alert_type_switch=-a 252 | IF "%LOCAL_ALERT_TYPE%"=="console" set local_alert_type_switch=-c 253 | IF "%LOCAL_ALERT_TYPE%"=="connected" set local_alert_type_switch=-s 254 | IF %DRY%==1 ( 255 | echo "%curdir%\wtssendmsg.exe" %local_alert_type_switch% "%WARNING_MESSAGE% [%COMPUTER_FQDN%]" 256 | ) ELSE ( 257 | "%curdir%\wtssendmsg.exe" %local_alert_type_switch% "%WARNING_MESSAGE% [%COMPUTER_FQDN%]" 258 | ) 259 | IF NOT %ERRORLEVEL%==0 ( 260 | set SCRIPT_ERROR=1 261 | Call:Log "Sending local message using wtssendmsg failed." 262 | ) 263 | GOTO:EOF 264 | 265 | :END 266 | :: Keeping the ping part in order to let commandline window open for some seconds after execution 267 | IF NOT %SCRIPT_ERROR%==0 echo Something bad happened while executing this script. Please check log file. You can also check what happens with parameter --dryrun && ping 127.0.0.1 > nul && exit /b 1 268 | exit /b 0 269 | -------------------------------------------------------------------------------- /erroraction_config.cmd: -------------------------------------------------------------------------------- 1 | :: erroraction_config.cmd file for smartmontools for Windows v6.5+ 2 | 3 | :: Valid values are: yes, no 4 | set MAIL_ALERT=no 5 | 6 | 7 | set SOURCE_MAIL= 8 | set DESTINATION_MAIL= 9 | set SMTP_SERVER= 10 | set SMTP_PORT=25 11 | set SMTP_USER= 12 | 13 | :: SMTP Password must be encoded in base64 (example via https://www.base64encode.org) 14 | set SMTP_PASSWORD= 15 | 16 | :: Security may be: none, ssl or tls 17 | set SECURITY=none 18 | 19 | :: Valid values are: yes, no 20 | set LOCAL_ALERT=no 21 | 22 | :: You may change this to a customized warning message or leave it to the default 23 | set WARNING_MESSAGE=[WARNING_MESSAGE] 24 | 25 | :: Valid values are: yes, no 26 | set COMPRESS_LOGS=yes 27 | 28 | -------------------------------------------------------------------------------- /erroraction_config/command_runner/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This file is part of command_runner module 5 | 6 | """ 7 | command_runner is a quick tool to launch commands from Python, get exit code 8 | and output, and handle most errors that may happen 9 | 10 | Versionning semantics: 11 | Major version: backward compatibility breaking changes 12 | Minor version: New functionnality 13 | Patch version: Backwards compatible bug fixes 14 | 15 | """ 16 | 17 | __intname__ = 'command_runner' 18 | __author__ = 'Orsiris de Jong' 19 | __copyright__ = 'Copyright (C) 2015-2020 Orsiris de Jong' 20 | __licence__ = 'BSD 3 Clause' 21 | __version__ = '0.5.0-dev' 22 | __build__ = '2020111101' 23 | 24 | 25 | import os 26 | import sys 27 | from logging import getLogger 28 | from typing import Union, Optional, List, Tuple, NoReturn 29 | import subprocess 30 | from datetime import datetime 31 | from time import sleep 32 | 33 | 34 | logger = getLogger() 35 | 36 | 37 | def live_command_runner(command: str, valid_exit_codes: Optional[List[int]] = None, timeout: int = 1800, 38 | shell: bool = False, encoding: str = 'utf-8', 39 | windows_no_window: bool = False, 40 | stdout: Union[int, str] = subprocess.PIPE, stderr: Union[int, str] = subprocess.STDOUT, 41 | **kwargs) -> Tuple[Optional[int], str]: 42 | """ 43 | Just the same as command_runner, but allows to show stdout / stderr output on the fly 44 | Needs python >= 3.7 45 | 46 | """ 47 | # Set default values for kwargs 48 | errors = kwargs.pop('errors', 'backslashreplace') # Don't let encoding issues make you mad 49 | universal_newlines = kwargs.pop('universal_newlines', False) 50 | creationflags = kwargs.pop('creationflags', 0) 51 | if windows_no_window: 52 | # Disable the following pylint error since the code also runs on nt platform, but 53 | # triggers and error on Unix 54 | # pylint: disable=E1101 55 | creationflags = creationflags | subprocess.CREATE_NO_WINDOW 56 | 57 | # If stdout is a file, let's create it 58 | if isinstance(stdout, str): 59 | stdout = open(stdout, 'w') 60 | stdout_to_file = True 61 | else: 62 | stdout_to_file = False 63 | if isinstance(stderr, str): 64 | stderr = open(stderr, 'w') 65 | 66 | output = '' 67 | 68 | try: 69 | begin_time = datetime.now() 70 | process = subprocess.Popen(command, shell=shell, 71 | universal_newlines=universal_newlines, encoding=encoding, 72 | errors=errors, creationflags=creationflags, 73 | stdout=stdout, stderr=stderr, **kwargs) 74 | 75 | while process.poll() is None: 76 | if not stdout_to_file: 77 | current_output = process.stdout.readline() 78 | sys.stdout.write(current_output) 79 | output += str(current_output) 80 | 81 | if (datetime.now() - begin_time).total_seconds() > timeout: 82 | # Try to terminate nicely before killing the process 83 | process.terminate() 84 | # Let the process terminate itself before trying to kill it not nicely 85 | # Under windows, terminate() and kill() are equivalent 86 | sleep(.5) 87 | if process.poll() is None: 88 | process.kill() 89 | logger.error('Timeout [{} seconds] expired for command [{}] execution.'.format(timeout, command)) 90 | return None, 'Timeout of {} seconds expired.'.format(timeout) 91 | 92 | # Get remaining output from process after a grace period 93 | sleep(.5) 94 | try: 95 | current_output = process.stdout.read() 96 | sys.stdout.write(current_output) 97 | output += str(current_output) 98 | except AttributeError: 99 | # process.stdout.read() might not exist anymore 100 | pass 101 | exit_code = process.poll() 102 | if isinstance(output, str): 103 | logger.debug(output) 104 | return exit_code, output 105 | # OSError if not a valid executable 106 | except FileNotFoundError as exc: 107 | logger.error('Command [{}] failed, file not found: {}'.format(command, exc)) 108 | return None, exc.__str__() 109 | except (OSError, IOError) as exc: 110 | logger.error('Command [{}] failed because of OS: {}.'.format(command, exc)) 111 | return None, exc.__str__() 112 | except Exception as exc: 113 | logger.error('Command [{}] failed for unknown reasons: {}.'.format(command, exc)) 114 | logger.debug('Error:', exc_info=True) 115 | return None, exc.__str__() 116 | 117 | 118 | def command_runner(command: str, valid_exit_codes: Optional[List[int]] = None, timeout: int = 1800, shell: bool = False, 119 | encoding: str = 'utf-8', 120 | windows_no_window: bool = False, **kwargs) -> Tuple[Optional[int], str]: 121 | """ 122 | Unix & Windows compatible subprocess wrapper that handles encoding, timeout, and 123 | various exit codes. 124 | Accepts subprocess.check_output and subprocess.popen arguments 125 | Whenever we can, we need to avoid shell=True in order to preseve better security 126 | Runs system command, returns exit code and stdout/stderr output, and logs output on error 127 | valid_exit_codes is a list of codes that don't trigger an error 128 | """ 129 | 130 | # Set default values for kwargs 131 | errors = kwargs.pop('errors', 'backslashreplace') # Don't let encoding issues make you mad 132 | universal_newlines = kwargs.pop('universal_newlines', False) 133 | creationflags = kwargs.pop('creationflags', 0) 134 | if windows_no_window: 135 | # Disable the following pylint error since the code also runs on nt platform, but 136 | # triggers an error on Unix 137 | # pylint: disable=E1101 138 | creationflags = creationflags | subprocess.CREATE_NO_WINDOW 139 | 140 | try: 141 | # universal_newlines=True makes netstat command fail under windows 142 | # timeout does not work under Python 2.7 with subprocess32 < 3.5 143 | # decoder may be cp437 or unicode_escape for dos commands or utf-8 for powershell 144 | # Disabling pylint error for the same reason as above 145 | # pylint: disable=E1123 146 | output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell, 147 | timeout=timeout, universal_newlines=universal_newlines, encoding=encoding, 148 | errors=errors, creationflags=creationflags, **kwargs) 149 | 150 | except subprocess.CalledProcessError as exc: 151 | exit_code = exc.returncode 152 | try: 153 | output = exc.output 154 | except Exception: 155 | output = "command_runner: Could not obtain output from command." 156 | if exit_code in valid_exit_codes if valid_exit_codes is not None else [0]: 157 | logger.debug('Command [%s] returned with exit code [%s]. Command output was:' % (command, exit_code)) 158 | if isinstance(output, str): 159 | logger.debug(output) 160 | return exc.returncode, output 161 | else: 162 | logger.error('Command [%s] failed with exit code [%s]. Command output was:' % 163 | (command, exc.returncode)) 164 | logger.error(output) 165 | return exc.returncode, output 166 | # OSError if not a valid executable 167 | except (OSError, IOError) as exc: 168 | logger.error('Command [%s] failed because of OS [%s].' % (command, exc)) 169 | return None, exc.__str__() 170 | except subprocess.TimeoutExpired: 171 | logger.error('Timeout [%s seconds] expired for command [%s] execution.' % (timeout, command)) 172 | return None, 'Timeout of %s seconds expired.' % timeout 173 | except Exception as exc: 174 | logger.error('Command [%s] failed for unknown reasons [%s].' % (command, exc)) 175 | logger.debug('Error:', exc_info=True) 176 | return None, exc.__str__() 177 | else: 178 | logger.debug('Command [%s] returned with exit code [0]. Command output was:' % command) 179 | if output: 180 | logger.debug(output) 181 | return 0, output 182 | 183 | 184 | def deferred_command(command: str, defer_time: Optional[int] = None) -> NoReturn: 185 | """ 186 | This is basically an ugly hack to launch commands in windows which are detached from parent process 187 | Especially useful to auto update/delete a running executable 188 | 189 | #TODO: Implement delete on reboot 190 | 191 | """ 192 | if not isinstance(defer_time, int): 193 | raise ValueError('defer_time needs to be in seconds.') 194 | 195 | if os.name == 'nt': 196 | deferrer = 'ping 127.0.0.1 -n %s > NUL & ' % defer_time 197 | else: 198 | deferrer = 'ping 127.0.0.1 -c %s > /dev/null && ' % defer_time 199 | 200 | subprocess.Popen(deferrer + command, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) 201 | 202 | 203 | def _selftest(): 204 | 205 | print('Example code for %s, %s, %s' % (__intname__, __version__, __build__)) 206 | """ 207 | exit_code, output = command_runner('ping 127.0.0.1') 208 | assert exit_code == 0, 'Exit code should be 0 for ping command' 209 | 210 | exit_code, output = command_runner('ping 127.0.0.1', timeout=1) 211 | assert exit_code == None, 'Exit code should be none on timeout' 212 | assert 'Timeout' in output, 'Output should have timeout' 213 | """ 214 | exit_code, output = live_command_runner('ping 127.0.0.1', encoding='cp437') 215 | assert exit_code == 0, 'Exit code should be 0 for ping command' 216 | 217 | exit_code, output = live_command_runner('ierhiohehierog2342') 218 | assert exit_code != 0, 'Unknown command should trigger an error' 219 | 220 | exit_code, output = live_command_runner('ping 127.0.0.1', timeout=1) 221 | assert exit_code == None, 'Exit code should be none in timeout' 222 | assert 'Timeout' in output, 'Output should have timeout' 223 | 224 | #exit_code = live_command_runner('ping 127.0.0.1', stdout=r'C:\GIT\test.log', stderr='/var/log/stderr.log') 225 | 226 | 227 | if __name__ == '__main__': 228 | _selftest() 229 | -------------------------------------------------------------------------------- /erroraction_config/command_runner/elevate.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2017-2020 Orsiris de Jong 5 | # This file is part of command_runner module 6 | 7 | """ 8 | elevate is a Windows/ unix compatible function elevator for Python 3+ 9 | 10 | usage: 11 | import sys 12 | from elevate import elevate 13 | 14 | def main(argv): 15 | print('Hello world, with arguments %s' % argv) 16 | 17 | # Hey, check my exit code ;) 18 | sys.exit(123) 19 | 20 | if __name__ == '__main__': 21 | elevate(main, sys.argv) 22 | 23 | Versionning semantics: 24 | Major version: backward compatibility breaking changes 25 | Minor version: New functionnality 26 | Patch version: Backwards compatible bug fixes 27 | 28 | """ 29 | 30 | __intname__ = 'command_runner.elevate' 31 | __author__ = 'Orsiris de Jong' 32 | __copyright__ = 'Copyright (C) 2020 Orsiris de Jong' 33 | __licence__ = 'BSD 3 Clause' 34 | __version__ = '0.2.0' 35 | __build__ = '2020040201' 36 | 37 | from logging import getLogger 38 | import os 39 | import sys 40 | from command_runner import command_runner 41 | 42 | if os.name == 'nt': 43 | try: 44 | import win32event # monitor process 45 | import win32process # monitor process 46 | from win32com.shell.shell import ShellExecuteEx 47 | from win32com.shell.shell import IsUserAnAdmin 48 | from win32com.shell import shellcon 49 | except ImportError: 50 | raise ImportError('Cannot import ctypes for checking admin privileges on Windows platform.') 51 | 52 | logger = getLogger() 53 | 54 | 55 | def is_admin(): 56 | """ 57 | Checks whether current program has administrative privileges in OS 58 | Works with Windows XP SP2+ and most Unixes 59 | 60 | :return: Boolean, True if admin privileges present 61 | """ 62 | current_os_name = os.name 63 | 64 | # Works with XP SP2 + 65 | if current_os_name == 'nt': 66 | try: 67 | return IsUserAnAdmin() 68 | except Exception: 69 | raise EnvironmentError('Cannot check admin privileges') 70 | elif current_os_name == 'posix': 71 | # Check for root on Posix 72 | # os.getuid only exists on postix OSes 73 | return os.getuid() == 0 74 | else: 75 | raise EnvironmentError('OS does not seem to be supported for admin check. OS: %s' % current_os_name) 76 | 77 | 78 | def elevate(fn, *args, **kwargs): 79 | if is_admin(): 80 | fn(*args, **kwargs) 81 | else: 82 | # UAC elevation / sudo code working for CPython, Nuitka >= 0.6.2, PyInstaller, PyExe, CxFreeze 83 | 84 | # Regardless of the runner (CPython, Nuitka or frozen CPython), sys.argv[0] is the relative path to script, 85 | # sys.argv[1] are the arguments 86 | # The only exception being CPython on Windows where sys.argv[0] contains absolute path to script 87 | # Regarless of OS, sys.executable will contain full path to python binary for CPython and Nuitka, 88 | # and full path to frozen executable on frozen CPython 89 | 90 | # Recapitulative table create with 91 | # (CentOS 7x64 / Python 3.4 / Nuitka 0.6.1 / PyInstaller 3.4) and 92 | # (Windows 10 x64 / Python 3.7x32 / Nuitka 0.6.2.10 / PyInstaller 3.4) 93 | # -------------------------------------------------------------------------------------------------------------- 94 | # | OS | Variable | CPython | Nuitka | PyInstaller | 95 | # |------------------------------------------------------------------------------------------------------------| 96 | # | Lin | argv | ['./script.py', '-h'] | ['./test', '-h'] | ['./test.py', -h'] | 97 | # | Lin | sys.executable | /usr/bin/python3.4 | /usr/bin/python3.4 | /absolute/path/to/test | 98 | # | Win | argv | ['C:\\Python\\test.py', '-h'] | ['test', '-h'] | ['test', '-h'] | 99 | # | Win | sys.executable | C:\Python\python.exe | C:\Python\Python.exe | C:\absolute\path\to\test.exe | 100 | # -------------------------------------------------------------------------------------------------------------- 101 | 102 | # Nuitka 0.6.2 and newer define builtin __nuitka_binary_dir 103 | # Nuitka does not set the frozen attribute on sys 104 | # Nuitka < 0.6.2 can be detected in sloppy ways, ie if not sys.argv[0].endswith('.py') or len(sys.path) < 3 105 | # Let's assume this will only be compiled with newer nuitka, and remove sloppy detections 106 | try: 107 | # Actual if statement not needed, but keeps code inspectors more happy 108 | if __nuitka_binary_dir or '__compiled__' in globals() is not None: 109 | is_nuitka_compiled = True 110 | except NameError: 111 | is_nuitka_compiled = False 112 | 113 | if is_nuitka_compiled: 114 | # On nuitka, sys.executable is the python binary, even if it does not exist in standalone, 115 | # so we need to fill runner with sys.argv[0] absolute path 116 | runner = os.path.abspath(sys.argv[0]) 117 | arguments = sys.argv[1:] 118 | # current_dir = os.path.dirname(runner) 119 | 120 | logger.debug('Running elevator as Nuitka with runner [%s]' % runner) 121 | logger.debug('Arguments are %s' % arguments) 122 | 123 | # If a freezer is used (PyInstaller, cx_freeze, py2exe) 124 | elif getattr(sys, "frozen", False): 125 | runner = os.path.abspath(sys.executable) 126 | arguments = sys.argv[1:] 127 | # current_dir = os.path.dirname(runner) 128 | 129 | logger.debug('Running elevator as Frozen with runner [%s]' % runner) 130 | logger.debug('Arguments are %s' % arguments) 131 | 132 | # If standard interpreter CPython is used 133 | else: 134 | runner = os.path.abspath(sys.executable) 135 | arguments = [os.path.abspath(sys.argv[0])] + sys.argv[1:] 136 | # current_dir = os.path.abspath(sys.argv[0]) 137 | 138 | logger.debug('Running elevator as CPython with runner [%s]' % runner) 139 | logger.debug('Arguments are %s' % arguments) 140 | 141 | if os.name == 'nt': 142 | # Re-run the function with admin rights 143 | # Join arguments and double quote each argument in order to prevent space separation 144 | arguments = ' '.join('"' + arg + '"' for arg in arguments) 145 | try: 146 | # Old method using ctypes which does not wait for executable to exit nor deos get exit code 147 | # See https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecutew 148 | # int 0 means SH_HIDE window, 1 is SW_SHOWNORMAL 149 | # needs the following imports 150 | # import ctypes 151 | 152 | # ctypes.windll.shell32.ShellExecuteW(None, 'runas', runner, arguments, None, 0) 153 | 154 | # Method with exit code that waits for executable to exit, needs the following imports 155 | # import win32event # monitor process 156 | # import win32process # monitor process 157 | # from win32com.shell.shell import ShellExecuteEx 158 | # from win32com.shell import shellcon 159 | childProcess = ShellExecuteEx(nShow=0, fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, 160 | lpVerb='runas', lpFile=runner, lpParameters=arguments) 161 | 162 | procHandle = childProcess['hProcess'] 163 | win32event.WaitForSingleObject(procHandle, win32event.INFINITE) 164 | exit_code = win32process.GetExitCodeProcess(procHandle) 165 | logger.debug('Child exited with code: %s' % exit_code) 166 | sys.exit(exit_code) 167 | 168 | except Exception as e: 169 | logger.info(e) 170 | logger.debug('Trace:', exc_info=True) 171 | sys.exit(255) 172 | # Linux runner and hopefully Unixes 173 | else: 174 | # Search for sudo executable in order to avoid using shell=True with subprocess 175 | sudo_path = None 176 | for path in os.environ.get('PATH', ''): 177 | if os.path.isfile(os.path.join(path, 'sudo')): 178 | sudo_path = os.path.join(path, 'sudo') 179 | if sudo_path is None: 180 | logger.error('Cannot find sudo executable. Cannot elevate privileges. Trying to run wihtout.') 181 | fn(*args, **kwargs) 182 | else: 183 | command = 'sudo "%s"%s%s' % ( 184 | runner, 185 | (' ' if len(arguments) > 0 else ''), 186 | ' '.join('"%s"' % argument for argument in arguments) 187 | ) 188 | exit_code, output = command_runner(command, shell=False, 189 | timeout=None) 190 | 191 | logger.info('Child output: %s' % output) 192 | sys.exit(exit_code) 193 | -------------------------------------------------------------------------------- /erroraction_config/cxsetup.py: -------------------------------------------------------------------------------- 1 | from cx_Freeze import setup, Executable 2 | 3 | 4 | import os.path 5 | PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__)) 6 | 7 | os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6') 8 | os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6') 9 | 10 | options = { 11 | 'build_exe': { 12 | 'include_files':[ 13 | os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'), 14 | os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'), 15 | 'erroraction_config.ui', 16 | 'smartd_pyngui.ui', 17 | ], 18 | #'includes':["pygubu.builder"], 19 | #'excludes':["PyQt4.QtSql", "sqlite3", 20 | # "scipy.lib.lapack.flapack", 21 | # "PyQt4.QtNetwork", 22 | # "PyQt4.QtScript", 23 | # "numpy.core._dotblas", 24 | # "PyQt5", "email", "http", "pyodoc_data", "unittest", "xml", "urllib"], 25 | "optimize": 2, 26 | }, 27 | } 28 | 29 | 30 | # On appelle la fonction setup 31 | setup( 32 | options = options, 33 | name = "smartd_pyngui", 34 | version = "0.3.0.2", 35 | description = "Smartmontools-win GUI", 36 | executables = [Executable("erroraction_config.py", icon= 'erroraction_config.ico', base = None), Executable("smartd_pyngui.py", icon= 'smartd_pyngui.ico', base = None)] 37 | ) 38 | -------------------------------------------------------------------------------- /erroraction_config/erroraction_config.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deajan/smartmontools-win/852b1bd877e6d167a405e8877cb6f60885779ca4/erroraction_config/erroraction_config.ico -------------------------------------------------------------------------------- /erroraction_config/erroraction_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | #### BASIC FUNCTIONS & DEFINITIONS ######################################################################### 5 | 6 | class Constants: 7 | """Simple class to use constants 8 | usage 9 | _CONST = Constants 10 | print(_CONST.NAME) 11 | """ 12 | APP_NAME="erroraction_config" 13 | APP_VERSION="0.3a" 14 | APP_BUILD="2020111701" 15 | APP_DESCRIPTION="smartmontools for Windows mail config" 16 | CONTACT="ozy@netpower.fr - http://www.netpower.fr" 17 | AUTHOR="Orsiris de Jong" 18 | 19 | ERRORACTION_CMD_FILENAME="erroraction.cmd" 20 | ERRORACTION_CONFIG_FILENAME="erroraction_config.cmd" 21 | MAILSEND_BINARY="mailsend.exe" 22 | 23 | IS_STABLE=True 24 | 25 | LOG_FILE=APP_NAME + ".log" 26 | 27 | def __setattr__(self, *_): 28 | pass 29 | 30 | _CONSTANT = Constants 31 | 32 | #### LOGGING & DEBUG CODE #################################################################################### 33 | 34 | import os 35 | from command_runner.elevate import elevate 36 | 37 | try: 38 | os.environ["_DEBUG"] 39 | _DEBUG = True 40 | except: 41 | _DEBUG = False 42 | 43 | import tempfile 44 | import logging 45 | from logging.handlers import RotatingFileHandler 46 | 47 | logger = logging.getLogger() 48 | 49 | # Set file log (try temp log file if not allowed to write to current dir) 50 | try: 51 | logFileHandler = RotatingFileHandler(_CONSTANT.LOG_FILE, mode='a', encoding='utf-8', maxBytes=1000000, backupCount=1) 52 | except: 53 | logFileHandler = RotatingFileHandler(tempfile.gettempdir() + os.sep + _CONSTANT.LOG_FILE, mode='a', encoding='utf-8', maxBytes=1000000, backupCount=1) 54 | 55 | logFileHandler.setLevel(logging.DEBUG) 56 | logFileHandler.setFormatter(logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')) 57 | logger.addHandler(logFileHandler) 58 | 59 | # Set stdout log 60 | logStdoutHandler = logging.StreamHandler() 61 | if _DEBUG == True: 62 | logStdoutHandler.setLevel(logging.DEBUG) 63 | else: 64 | logStdoutHandler.setLevel(logging.ERROR) 65 | logger.addHandler(logStdoutHandler) 66 | 67 | #### IMPORTS ################################################################################################ 68 | 69 | import sys 70 | import getopt 71 | import platform # Detect OS 72 | import re # Regex handling 73 | import time # sleep command 74 | import codecs # unicode encoding 75 | from subprocess import Popen, PIPE # call to external binaries 76 | import base64 # Support base64 mail passwords 77 | 78 | from datetime import datetime 79 | 80 | # GUI 81 | try: 82 | import tkinter as tk # Python 3 83 | from tkinter import messagebox 84 | except: 85 | import Tkinter as tk # Python 2 86 | import tkMessageBox as messagebox 87 | 88 | try: 89 | import pygubu # GUI builder 90 | except: 91 | logger.critical("Cannot find pygubu module. Try installing it with python -m pip install pygubu") 92 | sys.exit(1) 93 | 94 | # Manually resolve dependancies from pygubu with nuitka / other freezers like cx_freeze (Thanks to pygubu author Alejandro https://github.com/alejandroautalan) 95 | # As a side effect, show various messages in console on startup 96 | import nuitkahelper 97 | 98 | if platform.system() == "Windows": 99 | import ctypes # In order to perform UAC call 100 | 101 | logger.info("Running on python " + platform.python_version() + " / " + str(platform.uname())) 102 | 103 | #### ACTUAL APPLICATION ###################################################################################### 104 | 105 | CONFIG = "" # Contains full config as Configuration class 106 | 107 | class Configuration: 108 | errorActionCmdPath = "" 109 | 110 | def __init__(self, filePath= ''): 111 | """Determine smartd configuration file path""" 112 | 113 | # __file__ variable doesn't exist in frozen py2exe mode, get appRoot 114 | try: 115 | self.appRoot = os.path.dirname(os.path.abspath(__file__)) 116 | except: 117 | self.appRoot = os.path.dirname(os.path.abspath(sys.argv[0])) 118 | 119 | try: 120 | #TODO: undo double checked, here and in readconf 121 | if not os.path.isfile(filePath): 122 | raise TypeError 123 | else: 124 | self.errorActionCmdPath = filePath 125 | except: 126 | #rootWindow.widthdraw() 127 | msg="Wrong configuration file path provided." 128 | logger.critical(msg) 129 | messagebox.showinfo("Error", msg) 130 | sys.exit(1) 131 | 132 | class Application: 133 | """pygubu tkinter GUI class""" 134 | 135 | configValues = ['MAIL_ALERT', 'SOURCE_MAIL', 'DESTINATION_MAIL', 'SMTP_SERVER', 'SMTP_PORT', 136 | 'LOCAL_ALERT', 'WARNING_MESSAGE', 'COMPRESS_LOGS', 'DEVICE_LIST', 'SMART_LOG_FILE', 'ERROR_LOG_FILE', 'PROGRAM_PATH'] 137 | 138 | authValues = ['SMTP_USER', 'SMTP_PASSWORD', 'SECURITY'] 139 | 140 | def __init__(self, master, configDict): 141 | self.master = master 142 | self.configDict = configDict 143 | self.builder = builder = pygubu.Builder() 144 | 145 | # Load GUI xml description file 146 | filePath = os.path.join(CONFIG.appRoot, _CONSTANT.APP_NAME + ".ui") 147 | try: 148 | self.builder.add_from_file(filePath) 149 | except Exception as e: 150 | logger.critical("Cannot find ui file [" + filePath + "].") 151 | logger.debug(e) 152 | sys.exit(1) 153 | 154 | self.mainwindow = builder.get_object('MainFrame', master) 155 | 156 | # Bind GUI actions to functions 157 | self.builder.connect_callbacks(self) 158 | callbacks = { 159 | 'onUseAuthentication': self.onUseAuthentication, 160 | 'onTriggerAlert': self.onTriggerAlert, 161 | 'onSaveAndExit': self.onSaveAndExit, 162 | } 163 | self.builder.connect_callbacks(callbacks) 164 | 165 | # Read config values but prefer passed arguments over read ones 166 | tempDict = self.configDict 167 | self.configDict = readErrorConfigFile(CONFIG.errorActionCmdPath) 168 | self.configDict.update(tempDict) 169 | 170 | # Populate values in GUI 171 | for key, value in self.configDict.items(): 172 | try: 173 | try: 174 | self.builder.get_object(key, master).delete("1.0", "end") 175 | except: 176 | self.builder.get_object(key, master).delete("0", "end") 177 | 178 | self.builder.get_object(key, master).insert("end", value) 179 | self.builder.get_variable(key).set(value) 180 | except: 181 | if value == "yes": 182 | try: 183 | self.builder.get_object(key, master).select() 184 | except: 185 | pass 186 | elif value == "no": 187 | try: 188 | self.builder.get_object(key, master).deselect() 189 | except: 190 | pass 191 | 192 | if "SMTP_USER" in self.configDict: 193 | self.builder.get_object('UseAuthentication', master).select() 194 | self.onUseAuthentication() 195 | 196 | def prepareConfigDict(self): 197 | self.conficDict = {} 198 | values = self.configValues 199 | if self.builder.get_variable('useAuthentication').get() == True: 200 | values.extend(self.authValues) 201 | 202 | for key in values: 203 | try: 204 | self.configDict[key] = self.builder.get_object(key, self.master).get() 205 | except: 206 | pass 207 | try: 208 | self.configDict[key] = self.builder.get_object(key, self.master).get("1.0", "end") 209 | except: 210 | pass 211 | try: 212 | self.configDict[key] = self.builder.get_variable(key).get() 213 | except: 214 | pass 215 | 216 | def onUseAuthentication(self): 217 | if self.builder.get_variable('useAuthentication').get() == True: 218 | background = "#aaffaa" 219 | else: 220 | background = "#aaaaaa" 221 | 222 | for key in self.authValues: 223 | self.builder.get_object(key)['background']=background 224 | 225 | def onTriggerAlert(self): 226 | self.prepareConfigDict() 227 | writeErrorConfigFile(CONFIG.errorActionCmdPath, self.configDict) 228 | TriggerAlert(self.configDict) 229 | 230 | def onSaveAndExit(self): 231 | try: 232 | self.prepareConfigDict() 233 | writeErrorConfigFile(CONFIG.errorActionCmdPath, self.configDict) 234 | messagebox.showinfo('Information', 'Configuration saved') 235 | except: 236 | messagebox.showinfo('Error', 'Guru meditation failure !') 237 | return False 238 | 239 | sys.exit(0) 240 | 241 | def stringToBase64(s): 242 | return base64.b64encode(s.encode('utf-8')) 243 | 244 | def base64ToString(b): 245 | return base64.b64decode(b).decode('utf-8') 246 | 247 | def readErrorConfigFile(fileName): 248 | if not os.path.isfile(fileName): 249 | logger.info("No suitable [" + _CONSTANT.ERRORACTION_CONFIG_FILENAME + "] file found, creating new file [" + CONFIG.errorActionCmdPath + "].") 250 | 251 | return False 252 | 253 | try: 254 | fileHandle = open(fileName, 'r') 255 | except Exception as e: 256 | msg="Cannot open config file [ " + fileName + "]." 257 | logger.error(msg) 258 | logger.debug(e) 259 | messagebox.showinfo("Error", msg) 260 | return False 261 | 262 | try: 263 | configDict = {} 264 | for line in fileHandle.readlines(): 265 | if not line[0] == "#" and not line[0] == " " and not line[0] == "\n" and not line[0] == "\r": 266 | conf = line.split('=', 1) 267 | key = conf[0].replace('SET ', '', 1).replace('set ', '', 1) 268 | if len(conf) > 1: 269 | value = conf[1].strip() 270 | if key == "SMTP_PASSWORD": 271 | value = base64ToString(value) 272 | configDict[key] = value 273 | 274 | logger.debug("Read: " + str(configDict)) 275 | except Exception as e: 276 | msg="Cannot read in config file [" + fileName + "]." 277 | logger.error(msg) 278 | logger.debug(e) 279 | messagebox.showinfo("Error", msg) 280 | return False 281 | 282 | try: 283 | fileHandle.close() 284 | return configDict 285 | except Exception as e: 286 | logger.error("Cannot close file [" + fileName + "].") 287 | logger.debug(e) 288 | 289 | def writeErrorConfigFile(fileName, configDict): 290 | logger.debug("Writing " + str(configDict)) 291 | configLines = "" 292 | for key, value in configDict.items(): 293 | if key == "SMTP_PASSWORD": 294 | try: 295 | configLines += "SET " + key + "=" + stringToBase64(value).decode('utf-8') + "\n" 296 | except Exception as e: 297 | logger.critical("Cannot encode " + key) 298 | sys.exit(1) 299 | else: 300 | configLines += "SET " + key + "=" + value + "\n" 301 | 302 | try: 303 | fileHandle = open(fileName, 'w') 304 | except Exception as e: 305 | msg="Cannot open config file [ " + fileName + "]." 306 | logger.error(msg) 307 | logger.debug(e) 308 | messagebox.showinfo("Error", msg) 309 | return False 310 | 311 | try: 312 | fileHandle.write(":: This file was generated on " + str(datetime.now()) + " by " + _CONSTANT.APP_NAME + " " + _CONSTANT.APP_VERSION + "\n:: http://www.netpower.fr\n") 313 | fileHandle.write(configLines) 314 | except Exception as e: 315 | msg="Cannot write config file [ " + fileName + "]." 316 | logger.error(msg) 317 | logger.debug(e) 318 | messagebox.showinfo("Error", msg) 319 | return False 320 | try: 321 | fileHandle.close() 322 | except Exception as e: 323 | logger.error("Cannot close file [" + fileName + "].") 324 | logger.debug(e) 325 | 326 | def TriggerAlert(configDict): 327 | erroraction_cmd = CONFIG.appRoot + os.sep + ".." + os.sep + _CONSTANT.ERRORACTION_CMD_FILENAME 328 | 329 | if not os.path.isfile(erroraction_cmd): 330 | erroraction_cmd = CONFIG.appRoot + os.sep + _CONSTANT.ERRORACTION_CMD_FILENAME 331 | if not os.path.isfile(erroraction_cmd): 332 | msg="Cannot find [ " + erroraction_cmd + "]." 333 | logger.error(msg) 334 | messagebox.showinfo("Error", msg) 335 | return False 336 | 337 | command=[erroraction_cmd, '--test'] 338 | 339 | pHandle = Popen(command, stdout=PIPE, stderr=PIPE) 340 | output, err = pHandle.communicate() 341 | if not pHandle.returncode == 0: 342 | msg="Cannot execute test action:\r\n" + output.decode('iso-8859-1') + "\r\n" + err.decode('iso-8859-1') 343 | logger.error(msg) 344 | messagebox.showinfo('Error', msg) 345 | return False 346 | 347 | messagebox.showinfo('Information', 'Finished testing alert action.') 348 | 349 | def usage(): 350 | print(_CONSTANT.APP_NAME + " v" + _CONSTANT.APP_VERSION + " " + _CONSTANT.APP_BUILD) 351 | print(_CONSTANT.AUTHOR) 352 | print(_CONSTANT.CONTACT) 353 | print("") 354 | print("Works on Windows only") 355 | print("Usage:\n") 356 | print(_CONSTANT.APP_NAME + " -c [c:\\path\\to\\" + _CONSTANT.ERRORACTION_CONFIG_FILENAME + "] [OPTIONS]") 357 | print("") 358 | print("[OPTIONS]") 359 | print("-f [..] Specify a source email for alerts") 360 | print("-t [..] Destination email for alerts") 361 | print("-s [..] SMTP server address") 362 | print("-P [..] SMTP server port") 363 | print("-u [..] SMTP server username") 364 | print("-p [..] SMTP server password") 365 | print("--security=[..] SMTP server security. Valid values are: none, ssl, tls") 366 | print("-z Compress log files before sending") 367 | print("-m Enable mail warnings (automatically enabled if destination mail provided)") 368 | print("-l Enable smart warnings on screen") 369 | print("--warning=\"[..]\" Specify a warning message that will be used for alerts") 370 | print("--help, -h, -? Will show this message") 371 | print("") 372 | print("Example:") 373 | print(_CONSTANT.APP_NAME + " -c \"C:\Program Files\smartmontools for windows\bin\erroraction_config.cmd\" -f infra@example.tld -t monitoring@example.tld -s my.smtp.server.tld -P 587 -u infra@example.tld -p MyPassword -z") 374 | sys.exit(1) 375 | 376 | def main(argv): 377 | global CONFIG 378 | 379 | if _CONSTANT.IS_STABLE == False: 380 | logger.warn("Warning: This is an unstable developpment version.") 381 | 382 | configDict={} 383 | 384 | try: 385 | opts, args = getopt.getopt(argv[1:], "hmlz?c:?f:?t:?s:u:?p:?P:?", [ 'security=', 'warning=' ]) 386 | except getopt.GetoptError: 387 | usage() 388 | sys.exit() 389 | 390 | confFile = None 391 | for opt, arg in opts: 392 | if opt == '-h' or opt == "--help" or opt == "-?": 393 | usage() 394 | elif opt == '-c': 395 | confFile = arg 396 | elif opt == '-m': 397 | configDict['MAIL_ALERT'] = "yes" 398 | elif opt == '-f': 399 | configDict['SOURCE_MAIL'] = arg 400 | elif opt == '-t': 401 | configDict['DESTINATION_MAIL'] = arg 402 | configDict['MAIL_ALERT'] = "yes" 403 | elif opt == '-s': 404 | configDict['SMTP_SERVER'] = arg 405 | elif opt == '-P': 406 | configDict['SMTP_PORT'] = arg 407 | elif opt == '-u': 408 | configDict['SMTP_USER'] = arg 409 | elif opt == '-p': 410 | configDict['SMTP_PASSWORD'] = arg 411 | elif opt == '--security' and (arg == "none" or arg == "tls" or arg == "ssl"): 412 | configDict['SECURITY'] = arg 413 | elif opt == '-l': 414 | configDict['LOCAL_ALERT'] = "yes" 415 | elif opt == '--warning': 416 | configDict['WARNING_MESSAGE'] = arg 417 | elif opt == '-z': 418 | configDict['COMPRESS_LOGS'] = "yes" 419 | 420 | # Mailer variable for compat 421 | configDict['MAILER'] = 'mailsend' 422 | 423 | 424 | if confFile: 425 | CONFIG = Configuration(confFile) 426 | else: 427 | CONFIG = Configuration('') 428 | 429 | try: 430 | root = tk.Tk() 431 | root.title(_CONSTANT.APP_NAME) 432 | app = Application(root, configDict) 433 | root.mainloop() 434 | 435 | except Exception as e: 436 | logger.critical("Cannot instanciate main tk app.") 437 | logger.debug(e) 438 | sys.exit(1) 439 | 440 | 441 | if __name__ == '__main__': 442 | elevate(main, sys.argv) 443 | 444 | -------------------------------------------------------------------------------- /erroraction_config/erroraction_config.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 10 6 | 10 7 | 200 8 | 9 | 0 10 | True 11 | 0 12 | 13 | 14 | 15 | smartmontools for Windows erroraction.cmd configurator 16 | 17 | 0 18 | 2 19 | True 20 | 0 21 | 22 | 23 | 24 | 25 | 26 | 200 27 | 10 28 | 10 29 | Alert message 30 | 200 31 | 32 | 0 33 | 2 34 | True 35 | 1 36 | 37 | 38 | 39 | 6 40 | WARNING: smartmontools error message that is the thing of the past 41 | 42 42 | 43 | 0 44 | True 45 | 0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 200 54 | Email alert settings 55 | 200 56 | 57 | 0 58 | 2 59 | True 60 | 2 61 | nsew 62 | 63 | 64 | 65 | Source email address 66 | 67 | 0 68 | True 69 | 1 70 | w 71 | 72 | 73 | 74 | 75 | 76 | 77 | 1 78 | True 79 | 1 80 | e 81 | 82 | 83 | 84 | 85 | 86 | Destination email address 87 | 88 | 0 89 | True 90 | 2 91 | w 92 | 93 | 94 | 95 | 96 | 97 | 98 | 1 99 | True 100 | 2 101 | e 102 | 103 | 104 | 105 | 106 | 107 | SMTP server 108 | 109 | 0 110 | True 111 | 3 112 | w 113 | 114 | 115 | 116 | 117 | 118 | 119 | 1 120 | True 121 | 3 122 | e 123 | 124 | 125 | 126 | 127 | 128 | SMTP Port 129 | 130 | 0 131 | True 132 | 4 133 | w 134 | 135 | 136 | 137 | 138 | 139 | 25 140 | 141 | 1 142 | True 143 | 4 144 | e 145 | 146 | 147 | 148 | 149 | 150 | SMTP Username 151 | 152 | 0 153 | True 154 | 6 155 | w 156 | 157 | 158 | 159 | 160 | 161 | 162 | 1 163 | True 164 | 6 165 | e 166 | 167 | 168 | 169 | 170 | 171 | SMTP Password 172 | 173 | 0 174 | True 175 | 7 176 | w 177 | 178 | 179 | 180 | 181 | 182 | 183 | 1 184 | True 185 | 7 186 | e 187 | 188 | 189 | 190 | 191 | 192 | Security 193 | 194 | 0 195 | True 196 | 8 197 | w 198 | 199 | 200 | 201 | 202 | 203 | none ssl tls 204 | 17 205 | 206 | 1 207 | True 208 | 8 209 | e 210 | 211 | 212 | 213 | 214 | 215 | onUseAuthentication 216 | False 217 | True 218 | Use authentication 219 | boolean:useAuthentication 220 | 221 | 0 222 | True 223 | 5 224 | w 225 | 226 | 227 | 228 | 229 | 230 | no 231 | yes 232 | Compress logs before sending 233 | string:COMPRESS_LOGS 234 | 235 | 0 236 | True 237 | 9 238 | w 239 | 240 | 241 | 242 | 243 | 244 | no 245 | yes 246 | Send email alerts 247 | string:MAIL_ALERT 248 | 249 | 0 250 | True 251 | 0 252 | w 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 200 261 | Local alert settings 262 | 200 263 | 264 | 0 265 | 2 266 | True 267 | 3 268 | nsew 269 | 270 | 271 | 272 | no 273 | yes 274 | Send local alerts on screen 275 | string:LOCAL_ALERT 276 | 277 | 0 278 | True 279 | 0 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | onTriggerAlert 288 | Save & Trigger test alert 289 | 290 | 0 291 | True 292 | 4 293 | w 294 | 295 | 296 | 297 | 298 | 299 | onSaveAndExit 300 | Save & Exit 301 | 302 | 1 303 | True 304 | 4 305 | e 306 | 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /erroraction_config/nuitkahelper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | #file: nuitkahelper 4 | 5 | #Help nuitka compiler to include specific modules 6 | #import pygubu.builder.tkstdwidgets 7 | #import pygubu.builder.ttkstdwidgets 8 | import pygubu.builder.widgets.dialog 9 | import pygubu.builder.widgets.editabletreeview 10 | import pygubu.builder.widgets.scrollbarhelper 11 | import pygubu.builder.widgets.scrolledframe 12 | import pygubu.builder.widgets.tkscrollbarhelper 13 | import pygubu.builder.widgets.tkscrolledframe 14 | import pygubu.builder.widgets.pathchooserinput 15 | -------------------------------------------------------------------------------- /erroraction_config/setup_erroraction_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # setup.py 4 | import sys 5 | try: 6 | from distutils.core import setup 7 | except: 8 | print("Missing distutils.core module") 9 | sys.exit(1) 10 | 11 | try: 12 | import py2exe 13 | except: 14 | print("Missing py2exe module") 15 | sys.exit(1) 16 | 17 | sys.argv.append("py2exe") 18 | 19 | APP_NAME='erroraction_config' 20 | 21 | setup( 22 | name=APP_NAME, 23 | version='0.2', 24 | description='smartmontools-win alert GUI', 25 | author='Orsiris de Jong', 26 | #windows = [{'script': APP_NAME + ".py", 27 | # 'icon_resources': [(1, APP_NAME + ".ico")], 28 | # 'uac_info': "requireAdministrator", 29 | # }], 30 | console=[APP_NAME + ".py"], 31 | 32 | zipfile = "shared.lib", 33 | data_files=[("", [APP_NAME + ".ui"])], 34 | options= { 35 | "py2exe": { 36 | "includes" : ["sys", 37 | "pygubu.builder.tkstdwidgets", 38 | "pygubu.builder.ttkstdwidgets", 39 | "pygubu.builder.widgets.dialog", 40 | "pygubu.builder.widgets.editabletreeview", 41 | "pygubu.builder.widgets.scrollbarhelper", 42 | "pygubu.builder.widgets.scrolledframe", 43 | "pygubu.builder.widgets.tkscrollbarhelper", 44 | "pygubu.builder.widgets.tkscrolledframe", 45 | "pygubu.builder.widgets.pathchooserinput",], 46 | "excludes" : ["_ssl", 47 | "pyreadline", 48 | "difflib", 49 | "doctest", 50 | "locale", 51 | "optparse", 52 | "calendar", 53 | "doctest", 54 | "pdb", 55 | "unittest", 56 | "difflib", 57 | "inspect", 58 | ], 59 | "compressed" : True, 60 | "optimize": 2, 61 | 62 | }}, 63 | ) 64 | 65 | #TODO: remove tcl\tcl8.5\{encoding,demos,tzdata} 66 | -------------------------------------------------------------------------------- /fix_badsectors.cmd: -------------------------------------------------------------------------------- 1 | :: Reallocate bad sector script v1.0 2 | :: http://www.netpower.fr 3 | :: (CopyLeft) 2013 by Orsiris "Ozy" de Jong 4 | 5 | @echo off 6 | setlocal 7 | echo Experimental script to reallocate bad sectors 8 | echo You can get last bad sector address by performing a smartmontools 9 | echo long test and check results. 10 | echo. 11 | echo This script reads and writes 8 x 512 bytes of data to the LBA 12 | echo address of a bad sector forcing drive's firmware to reallocate the bad sector. 13 | echo Use at your own risk. 14 | echo. 15 | echo Please run this script in the directory where your dd executable is located 16 | echo. 17 | set /p none=Press any key to get a list of drives 18 | 19 | :SETDRV 20 | dd --list 21 | echo Enter the drive name where the bad sector is located (or enter q to quit) 22 | echo. 23 | echo First drive could be \\?\Device\Harddisk0\DR0 24 | echo Second drive could be \\?\Device\Harddisk1\DR0 25 | echo. 26 | set /p drive=Drive ? 27 | 28 | IF "%drive%"=="q" GOTO END 29 | IF "%drive%"=="Q" GOTO END 30 | IF "%drive%"=="" GOTO BADDRV 31 | 32 | :SETADDR 33 | set /p address=Enter LBA address of bad sector: 34 | IF "%address%"=="" GOTO BADADDR 35 | 36 | :FIX 37 | set /a faddress=%address%/8 38 | dd bs=4096c count=1c if=%drive% of=%temp%\%address%.lba skip=%faddress% 39 | dd bs=4096c count=1c if=/dev/zero of=%drive% skip=%faddress% 40 | dd bs=4096c count=1c if=%temp%\%address%.lba of=%drive% skip=%faddress% 41 | IF NOT "%ERRORLEVEL%"=="0" GOTO FALSE 42 | 43 | echo Run complete, pleadse run a smartmontools test (smartctl -t long drive) to check. 44 | GOTO END 45 | 46 | :FALSE 47 | echo It seems that the fix did not succedd. You might try smartmontools long test (smartctl -t long drive) to check. 48 | GOTO END 49 | 50 | :BADDRV 51 | echo Please enter a valid drive name 52 | GOTO SETDRV 53 | 54 | :BADADDR 55 | echo Please enter a valid LBA address 56 | GOTO SETADDR 57 | :END 58 | -------------------------------------------------------------------------------- /smartd.conf: -------------------------------------------------------------------------------- 1 | # Standard smartd.conf file for smartmontools for Windows - http://www.netpower.fr 2 | # The following line lets smartd autodetect drives, usually works for SATA / IDE drives 3 | 4 | # Please leave [PATH] which will be replaced by the install path of smartmontools-win 5 | 6 | DEVICESCAN -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 7 | 8 | # If using drives that can't be autodetected, you may specify them directly (don't forget to uncomment) 9 | 10 | #/dev/sda -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 11 | #/dev/csmi0,0 -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 12 | 13 | -------------------------------------------------------------------------------- /smartmontools for Windows includes.iss: -------------------------------------------------------------------------------- 1 | //// General purpose functions (2020111701) 2 | 3 | [code] 4 | //// Returns true if IsWin64 is false 5 | function IsWin32(): Boolean; 6 | begin 7 | result := not IsWin64; 8 | end; 9 | 10 | //// Returns last char of a string 11 | function LastChar(str: String): String; 12 | begin 13 | result := copy(str, Length(str), 1); 14 | end; 15 | 16 | //// Checks if given service exists 17 | function ServiceExists(srv: String): Boolean; 18 | var resultcode: Integer; 19 | 20 | begin 21 | ShellExec('', ExpandConstant('{sys}\sc.exe'), 'query ' + srv, '', SW_HIDE, ewWaitUntilTerminated, resultcode); 22 | if resultcode = 0 then 23 | Result := true 24 | else 25 | Result := false 26 | end; 27 | 28 | //// Checks if given service runs 29 | function ServiceIsRunning(srv: String): Boolean; 30 | var resultcode: Integer; 31 | 32 | begin 33 | ShellExec('', ExpandConstant('{cmd}'), ExpandConstant(' /C {sys}\sc.exe query ' + srv + ' | findstr "RUNNING"'), '', SW_HIDE, ewWaitUntilTerminated, resultcode); 34 | if resultcode = 0 then 35 | Result := true 36 | else 37 | Result := false 38 | end; 39 | 40 | //// Starts service after installation 41 | function LoadService(srv: String): Integer; 42 | var resultcode: Integer; 43 | 44 | begin 45 | if (ServiceExists(srv)) then 46 | begin 47 | if (ServiceIsRunning(srv) = false) then 48 | begin 49 | ShellExec('', ExpandConstant('{sys}\sc.exe'), 'start '+ srv, '', SW_HIDE, ewWaitUntilTerminated, resultcode); 50 | if resultcode <> 0 then 51 | MsgBox('Cannot load service [' + srv + '], exit code = ' + IntToStr(resultcode), mbError, MB_OK); 52 | result := resultcode; 53 | end 54 | end 55 | else 56 | MsgBox('Service [' + srv + '] cannot be loaded because it does not exist.', mbError, MB_OK); 57 | end; 58 | 59 | //// Stops service and wait 2000ms before removing file to be sure it's not in use anymore 60 | function UnloadService(srv: String): Integer; 61 | var resultcode: Integer; 62 | 63 | begin 64 | if (ServiceIsRunning(srv) = true) then 65 | begin 66 | ShellExec('', ExpandConstant('{sys}\sc.exe'), 'stop ' + srv, '', SW_HIDE, ewWaitUntilTerminated, resultcode); 67 | sleep(2000); 68 | if resultcode <> 0 then 69 | MsgBox('Cannot unload service [' + srv + '], exit code = ' + IntToStr(resultcode), mbError, MB_OK); 70 | result := resultcode; 71 | end 72 | else 73 | result := 0; 74 | 75 | end; 76 | 77 | //// Checks if binary path of service belongs to smartmontools-win 78 | function IsSmartWinService(srv: String): Boolean; 79 | var resultcode: Integer; 80 | 81 | begin 82 | ShellExec('', ExpandConstant('{cmd}'), ExpandConstant('/C {sys}\sc.exe qc ' + srv + ' | findstr /C:"\\smartmontools for Windows\\bin\\smartd.exe"'), '', SW_HIDE, ewWaitUntilTerminated, resultcode); 83 | if resultcode = 0 then 84 | result := true 85 | else 86 | result := false 87 | end; 88 | 89 | //// Installs smartd service 90 | procedure InstallService(); 91 | var resultCode: Integer; 92 | 93 | begin 94 | Exec(ExpandConstant('{app}\bin\smartd.exe'), ExpandConstant('install -c "{app}\bin\smartd.conf"'), '', SW_HIDE, ewWaitUntilTerminated, resultcode); 95 | if resultcode <> 0 then 96 | MsgBox('Cannot install service via [' + ExpandConstant('{app}\bin\smartd.exe') + ' ' + ExpandConstant('install -c "{app}\bin\smartd.conf"') + '], exit code = ' + IntToStr(resultcode), mbError, MB_OK); 97 | end; 98 | 99 | 100 | //// Uninstalls given service 101 | procedure UninstallService(srv: String); 102 | var resultcode: Integer; 103 | 104 | begin 105 | UnloadService(srv); 106 | ShellExec('', ExpandConstant('{sys}\sc.exe'), 'delete ' + srv, '', SW_HIDE, ewWaitUntilTerminated, resultcode); 107 | if resultcode <> 0 then 108 | MsgBox('Cannot uninstall service [' + srv + '], exit code = ' + IntToStr(resultcode), mbError, MB_OK); 109 | end; 110 | 111 | //// Explode a string into an array using passed delimeter 112 | function Explode(Text: String; Separator: String): TArrayOfString; 113 | var 114 | i: integer; 115 | res: TArrayOfString; 116 | 117 | begin 118 | i := 0; 119 | repeat 120 | SetArrayLength(res, i+1); 121 | if Pos(Separator,Text) > 0 then begin 122 | res[i] := Copy(Text, 1, Pos(Separator, Text)-1); 123 | Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text)); 124 | i := i + 1; 125 | end else 126 | begin 127 | res[i] := Text; 128 | Text := ''; 129 | end; 130 | until Length(Text)=0; 131 | result := res; 132 | end; 133 | 134 | //// Implode an array into a string using a passed delimiter 135 | function Implode(Arr: TArrayOfString; Separator: String): String; 136 | var 137 | i: integer; 138 | res: String; 139 | begin 140 | i := 0; 141 | res := ''; 142 | repeat 143 | res := res + Arr[i] + Separator; 144 | i := i + 1; 145 | until (i >= GetArrayLength(Arr)); 146 | result := res; 147 | end; 148 | 149 | //// Returns commmand line arguments, usage: GetCommandLineParam('--test') 150 | ////("--test=value" will return "value", "-t value" will return "value", "-t" will return "yes" 151 | function GetCommandLineParam(Param: string): String; 152 | var 153 | CmdlineParamCount: Integer; 154 | 155 | begin 156 | CmdlineParamCount := 0; 157 | 158 | while (CmdlineParamCount <= ParamCount) do 159 | begin 160 | if ((Param = Copy(ParamStr(CmdlineParamCount), 0, (Pos('=', ParamStr(CmdlineParamCount))) - 1)) or (Param = ParamStr(CmdlineParamCount))) then 161 | begin 162 | if (Pos('=',ParamStr(CmdlineParamCount)) > 0) then 163 | begin 164 | result := Copy(ParamStr(CmdlineParamCount), (Pos('=', ParamStr(CmdlineParamCount)) + 1), Length(ParamStr(CmdlineParamCount))); 165 | end 166 | else if ((Copy(ParamStr(CmdlineParamCount + 1), 0, 1) <> '-') and (Copy(ParamStr(CmdlineParamCount + 1), 0, 1) <> '/') and (Length(ParamStr(CmdlineParamCount + 1)) > 0)) then 167 | //end else if ((Pos('-', ParamStr(CmdlineParamCount + 1)) <> 0) and (Length(ParamStr(CmdlineParamCount + 1)) > 0) and (Pos('/', ParamStr(CmdlineParamCount + 1)) <> 0)) then 168 | begin 169 | result := ParamStr(CmdlineParamCount + 1); 170 | end else 171 | begin 172 | result := 'yes'; 173 | end; 174 | end; 175 | // and 176 | //MsgBox(ParamStr(CmdlineParamCount), MbInformation, MB_OK); 177 | CmdlineParamCount := CmdlineParamCount + 1; 178 | end; 179 | end; 180 | 181 | // Determine if an earlier version of this program is already installed 182 | function IsUpdateInstall(): Boolean; 183 | begin 184 | Result := RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#AppGUID}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{#AppGUID}_is1'); 185 | end; 186 | 187 | // Base64 encode and decode functions found at http://www.vincenzo.net/isxkb/index.php?title=Encode/Decode_Base64 188 | const Codes64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 189 | 190 | function Encode64(S: AnsiString): AnsiString; 191 | var 192 | i: Integer; 193 | a: Integer; 194 | x: Integer; 195 | b: Integer; 196 | begin 197 | Result := ''; 198 | a := 0; 199 | b := 0; 200 | for i := 1 to Length(s) do 201 | begin 202 | x := Ord(s[i]); 203 | b := b * 256 + x; 204 | a := a + 8; 205 | while (a >= 6) do 206 | begin 207 | a := a - 6; 208 | x := b div (1 shl a); 209 | b := b mod (1 shl a); 210 | Result := Result + copy(Codes64,x + 1,1); 211 | end; 212 | end; 213 | if a > 0 then 214 | begin 215 | x := b shl (6 - a); 216 | Result := Result + copy(Codes64,x + 1,1); 217 | end; 218 | a := Length(Result) mod 4; 219 | if a = 2 then 220 | Result := Result + '==' 221 | else if a = 3 then 222 | Result := Result + '='; 223 | 224 | end; 225 | 226 | function Decode64(S: AnsiString): AnsiString; 227 | var 228 | i: Integer; 229 | a: Integer; 230 | x: Integer; 231 | b: Integer; 232 | begin 233 | Result := ''; 234 | a := 0; 235 | b := 0; 236 | for i := 1 to Length(s) do 237 | begin 238 | x := Pos(s[i], codes64) - 1; 239 | if x >= 0 then 240 | begin 241 | b := b * 64 + x; 242 | a := a + 6; 243 | if a >= 8 then 244 | begin 245 | a := a - 8; 246 | x := b shr a; 247 | b := b mod (1 shl a); 248 | x := x mod 256; 249 | Result := Result + chr(x); 250 | end; 251 | end 252 | else 253 | Exit; // finish at unknown 254 | end; 255 | end; 256 | 257 | function FileReplaceString(const FileName, SearchString, ReplaceString: string):boolean; 258 | var 259 | MyFile : TStrings; 260 | MyText : string; 261 | begin 262 | MyFile := TStringList.Create; 263 | 264 | try 265 | result := true; 266 | 267 | try 268 | MyFile.LoadFromFile(FileName); 269 | MyText := MyFile.Text; 270 | 271 | if StringChangeEx(MyText, SearchString, ReplaceString, True) > 0 then //Only save if text has been changed. 272 | begin; 273 | MyFile.Text := MyText; 274 | MyFile.SaveToFile(FileName); 275 | end; 276 | except 277 | result := false; 278 | end; 279 | finally 280 | MyFile.Free; 281 | end; 282 | end; -------------------------------------------------------------------------------- /smartmontools for Windows main.iss: -------------------------------------------------------------------------------- 1 | ; smartmontools for Windows package 2 | 3 | #define BuildNumber "2020111701" 4 | #define AppName "smartmontools for Windows" 5 | #define AppShortName "smartmontools-win" 6 | #define MajorVersion "7.1" 7 | #define MinorVersion "1" 8 | #define SubBuild "3" 9 | ; Define build type -dev -beta -rc for WIP, leave empty for RTM 10 | #define BuildType "" 11 | #define AppPublisher "Orsiris de Jong" 12 | #define AppURL "http://www.netpower.fr" 13 | #define CopyrightYears="2012-2020" 14 | 15 | #define BaseDir "C:\GIT\smartmontools-win" 16 | #define SmartmonToolsDir "smartmontools-7.1-1.win32-setup" 17 | #define smartdPynguiDir "smartd-pyngui" 18 | ;#define erroractionGuiDir "erroraction-gui" 19 | #define SendEmailDir "sendEmail-v156" 20 | #define MailsendDir "mailsend1.19" 21 | #define GzipDir "gzip-1.3.12-1-bin" 22 | #define ddDir "dd-0.6beta3" 23 | #define vcRedistDir "VCREDIST" 24 | #define wgetDir "wget" 25 | #define SmartServiceName "smartd" 26 | #define AppGUID "{487E2D86-AB76-467B-8EC0-0AF89EC38F5C}" 27 | 28 | [Setup] 29 | ; Aribtrary chosen GUID 30 | AppId={{#AppGUID} 31 | AppName={#AppName} 32 | AppVersion={#MajorVersion}-{#MinorVersion} 33 | AppPublisher={#AppPublisher} 34 | AppPublisherURL={#AppURL} 35 | AppSupportURL={#AppURL} 36 | AppUpdatesURL={#AppURL} 37 | DefaultDirName={commonpf}\{#AppName} 38 | DefaultGroupName=smartmontools for Windows 39 | LicenseFile={#BaseDir}\LICENSE.TXT 40 | OutputDir={#BaseDir}\Build 41 | OutputBaseFilename={#AppShortName}-{#MajorVersion}-{#MinorVersion}{#BuildType} 42 | Compression=lzma2/max 43 | SolidCompression=yes 44 | VersionInfoCopyright=Written in {#CopyrightYears} by {#AppPublisher} {#AppURL} 45 | VersionInfoVersion="{#MajorVersion}.{#MinorVersion}.{#SubBuild}" 46 | MinVersion=0,6.1sp1 47 | CloseApplications=no 48 | ArchitecturesInstallIn64BitMode=x64 49 | 50 | [Languages] 51 | Name: en; MessagesFile: "compiler:Default.isl"; InfoBeforeFile: "{#BaseDir}\README.md"; 52 | Name: fr; MessagesFile: "compiler:Languages\French.isl"; InfoBeforeFile: "{#BaseDir}\README-FR.TXT"; 53 | Name: de; MessagesFile: "compiler:Languages\German.isl"; InfoBeforeFile: "{#BaseDir}\README-DE.TXT"; 54 | ;Name: ru; MessagesFile: "compiler:Languages\Russian.isl"; InfoBeforeFile: "{#BaseDir}\README-RU.TXT"; 55 | 56 | [CustomMessages] 57 | #include "smartmontools for windows strings.iss" 58 | 59 | [Types] 60 | Name: full; Description: "{cm:FullInstall}"; 61 | Name: custom; Description: "{cm:CustomInstall}"; Flags: iscustom; 62 | Name: smartd-pyngui; Description: "{cm:SmartdPynguiInstall}"; 63 | 64 | [Components] 65 | Name: core; Description: "{cm:coredescription}"; Types: full; Flags: exclusive 66 | Name: core\service; Description: "{cm:coreservice}"; Types: full; 67 | Name: core\service\gui; Description: "{cm:servicegui}"; Types: full; 68 | Name: core\service\mailalert; Description: "{cm:mailsupport}"; Types: full; 69 | Name: core\service\localalert; Description: "{cm:localsupport}"; Types: full; 70 | Name: core\scheduledtestalerts; Description: "{cm:scheduledtestalerts}"; Types: custom; 71 | Name: core\regext; Description: "{cm:regext}"; Types: full; 72 | Name: core\regext\info; Description: "{cm:smartinfo}"; Types: Full; 73 | Name: core\regext\tests; Description: "{cm:smarttests}"; Types: Full; 74 | Name: core\updatedb; Description: "{cm:updatedb}"; Types: Full; 75 | Name: smartdpyngui; Description: "{cm:smartdpyngui}"; Types: smartd-pyngui; Flags: exclusive 76 | Name: fixbadsecttools; Description: "{cm:fixbadsecttools}"; Types: custom; 77 | Name: authorlinks; Description: "{cm:authorlinks}"; Types: full; 78 | Name: statistics; Description: "{cm:statistics}"; Types: full smartd-pyngui; 79 | 80 | [Files] 81 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\drivedb.h"; DestDir: "{app}\bin"; Components: core; 82 | ;Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\runcmda.exe.manifest"; DestDir: "{app}\bin"; Components: core; 83 | ;Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\runcmdu.exe.manifest"; DestDir: "{app}\bin"; Components: core; 84 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\update-smart-drivedb.exe"; DestDir: "{app}\bin"; Components: core; 85 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\smartd_warning.cmd"; DestDir: "{app}\bin"; Components: core\service; 86 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\smartd.conf"; DestDir: "{app}\bin"; DestName: smartd.conf.example; Components: core; Flags: ignoreversion 87 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\runcmda.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32() 88 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\runcmdu.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32() 89 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\smartctl.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32() 90 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\smartctl-nc.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32() 91 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\smartd.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32(); AfterInstall: TestForExistingSmartdUpstream(); 92 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin\wtssendmsg.exe"; DestDir: "{app}\bin"; Components: core; Check: IsWin32() 93 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\runcmda.exe"; DestDir: "{app}\bin"; Components: core; Flags: 64bit; Check: IsWin64 94 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\runcmdu.exe"; DestDir: "{app}\bin"; Components: core; Flags: 64bit; Check: IsWin64 95 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\smartctl.exe"; DestDir: "{app}\bin"; Components: core; Flags: 64bit; Check: IsWin64 96 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\smartctl-nc.exe"; DestDir: "{app}\bin"; Components: core; Flags: 64bit; Check: IsWin64 97 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\smartd.exe"; DestDir: "{app}\bin"; Components: core; Flags: 64bit; Check: IsWin64; AfterInstall: TestForExistingSmartdUpstream(); 98 | Source: "{#BaseDir}\{#SmartmontoolsDir}\bin64\wtssendmsg.exe"; DestDir: "{app}\bin"; Components: core\service\localalert; Flags: 64bit; Check: IsWin64 99 | Source: "{#BaseDir}\{#SmartmontoolsDir}\doc\*"; DestDir: "{app}\doc\smartmontools"; Components: core; Flags: ignoreversion recursesubdirs createallsubdirs 100 | Source: "{#BaseDir}\{#smartdPynguiDir}\*"; Excludes: "tzdata,demos,msgs,images"; DestDir: "{app}\bin\{#smartdPynguiDir}"; Components: core\service\gui; Flags: recursesubdirs createallsubdirs 101 | ;Source: "{#BaseDir}\{#erroractionGuiDir}\*"; DestDir: "{app}\bin\{#smartdPynguiDir}"; Components: core\service\gui; Flags: recursesubdirs createallsubdirs 102 | Source: "{#BaseDir}\{#vcRedistDir}\msvcr100.dll"; DestDir: "{app}\bin\{#smartdPynguiDir}"; Components: core\service\gui; 103 | Source: "{#BaseDir}\{#MailSendDir}\mailsend.exe"; DestDir: "{app}\bin"; Components: core\service\mailalert; 104 | Source: "{#BaseDir}\{#MailSendDir}\COPYRIGHT.TXT"; DestDir: "{app}\doc\mailsend"; Components: core\service\mailalert; 105 | Source: "{#BaseDir}\{#GzipDir}\bin\gzip.exe"; DestDir: "{app}\bin"; Components: core\service\mailalert; 106 | Source: "{#BaseDir}\{#GzipDir}\man\cat1\gzip.1.txt"; DestDir: "{app}\doc\gzip"; Components: core\service\mailalert; 107 | Source: "{#BaseDir}\base64.exe"; DestDir: "{app}\bin"; Components: core\service\mailalert; 108 | Source: "{#BaseDir}\{#ddDir}\dd.exe"; DestDir: "{app}\bin"; Components: fixbadsecttools; 109 | Source: "{#BaseDir}\{#ddDir}\Copying.txt"; DestDir: "{app}\doc\dd"; Components: fixbadsecttools; 110 | Source: "{#BaseDir}\{#ddDir}\ddchanges.txt"; DestDir: "{app}\doc\dd"; Components: fixbadsecttools; 111 | Source: "{#BaseDir}\{#wgetDir}\wget-1.14.exe"; DestDir: "{tmp}"; Components: statistics; AfterInstall: SendInstallerStats(); 112 | Source: "{#BaseDir}\fix_badsectors.cmd"; DestDir: "{app}\bin"; Components: fixbadsecttools; 113 | Source: "{#BaseDir}\README.md"; DestDir: "{app}\doc\Smartmontools for Windows package"; Components: core; 114 | ;Source: "{#BaseDir}\README-RU.TXT"; DestDir: "{app}\doc\Smartmontools for Windows package"; Components: core; 115 | Source: "{#BaseDir}\README-FR.TXT"; DestDir: "{app}\doc\Smartmontools for Windows package"; Components: core; 116 | Source: "{#BaseDir}\README-DE.TXT"; DestDir: "{app}\doc\Smartmontools for Windows package"; Components: core; 117 | Source: "{#BaseDir}\LICENSE.TXT"; DestDir: "{app}\doc\Smartmontools for Windows package"; Components: core; 118 | Source: "{#BaseDir}\erroraction.cmd"; DestDir: "{app}\bin"; Components: core\service; 119 | Source: "{#BaseDir}\erroraction_config.cmd"; DestDir: "{app}\bin"; Components: core\service; Flags: confirmoverwrite; Check: NoExternalErroractionFile(); AfterInstall: UpdateErroractionConfFile(); 120 | Source: "{#BaseDir}\ScheduledTask.xml"; DestDir: "{app}\bin"; Components: core\scheduledtestalerts; AfterInstall: WriteScheduledTest(); 121 | Source: "{#BaseDir}\smartd.conf"; DestDir: "{app}\bin"; Components: core\service; Flags: confirmoverwrite; Check: NoExternalSmartdFile(); AfterInstall: UpdateSmartdConfFile(); 122 | Source: "{#BaseDir}\{#smartdPynguiDir}\*"; Excludes: "tzdata,demos,msgs,images"; DestDir: "{app}\bin\{#smartdPynguiDir}"; Components: smartdpyngui; Flags: recursesubdirs createallsubdirs 123 | 124 | [Run] 125 | Filename: {app}\bin\update-smart-drivedb.exe; Parameters: "/S"; Components: core\updatedb; StatusMSG: "Updating drive database."; Flags: waituntilterminated 126 | Filename: {app}\bin\{#smartdPynguiDir}\smartd_pyngui.exe; Parameters: "-c ""{app}\bin\smartd.conf"""; Components: core\service\gui; StatusMSG: "Setup Smartd service"; Flags: waituntilterminated skipifsilent 127 | Filename: {app}\bin\{#smartdPynguiDir}\smartd_pyngui.exe; Components: smartdpyngui; StatusMSG: "Setup Smartd service"; Flags: waituntilterminated skipifsilent 128 | Filename: {app}\bin\{#smartdPynguiDir}\erroraction_config.exe; Parameters: "-c ""{app}\bin\erroraction_config.cmd"""; Components: core\service\gui; StatusMSG: "Setup alert settings"; Flags: waituntilterminated skipifsilent 129 | Filename: {app}\bin\scheduled_send.cmd; Components: core\scheduledtestalerts; StatusMsg: "Setting up scheduled test send"; Flags: runhidden 130 | 131 | [Icons] 132 | Name: {group}\Reconfigure SMART service; Filename: "{app}\bin\{#smartdPynguiDir}\smartd_pyngui.exe"; Parameters: "-c ""{app}\bin\smartd.conf"""; Components: core\service\gui; 133 | Name: {group}\Reconfigure SMART service; Filename: "{app}\bin\{#smartdPynguiDir}\smartd_pyngui.exe"; Components: smartdpyngui; 134 | Name: {group}\Reconfigure SMART Alert settings; Filename: "{app}\bin\{#smartdPynguiDir}\erroraction_config.exe"; Parameters: "-c ""{app}\bin\erroraction_config.cmd"""; Components: core\service\gui; 135 | Name: {group}\Visit NetPower.fr; Filename: http://www.netpower.fr; Components: authorlinks; 136 | Name: {group}\Visit smartmontools Site; Filename: http://smartmontools.sourceforge.net; Components: authorlinks; 137 | ;Name: {group}\Fix Bad sectors (use at own risk!); Filename: "{app}\bin\fix_badsectors.cmd"; Components: fixbadsecttools 138 | Name: "{group}\{cm:UninstallProgram, {#=AppName}}"; Filename: {uninstallexe}; 139 | 140 | [Registry] 141 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctlinfo\; ValueType: String; ValueData: {cm:smartinfo}; Components: core\regext\info; Flags: uninsdeletekey 142 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctlinfo\command; ValueType: String; ValueData: """{app}\bin\runcmda.exe"" ""{app}\bin\smartctl.exe"" -d auto -a %L"; Components: core\regext\info; Flags: uninsdeletevalue 143 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctlshorttest\; ValueType: String; ValueData: {cm:smarttestshort}; Components: core\regext\tests; Flags: uninsdeletekey 144 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctlshorttest\command; ValueType: String; ValueData: """{app}\bin\runcmda.exe"" ""{app}\bin\smartctl.exe"" -d auto -t short %L"; Components: core\regext\tests; Flags: uninsdeletevalue 145 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctllongtest\; ValueType: String; ValueData: {cm:smarttestlong}; Components: core\regext\tests; Flags: uninsdeletekey 146 | Root: HKLM; Subkey: SOFTWARE\Classes\Drive\shell\smartctllongtest\command; ValueType: String; ValueData: """{app}\bin\runcmda.exe"" ""{app}\bin\smartctl.exe"" -d auto -t long %L"; Components: core\regext\tests; Flags: uninsdeletevalue 147 | 148 | [UninstallRun] 149 | ; TODO: check if smartd should remain because of upstream package 150 | ;Filename: {sys}\sc.exe; Parameters: "delete ""{#SmartServiceName}"""; Components: core\service; Flags: runhidden 151 | 152 | ; Remove earlier versions of smartd-pyngui in order to avoid python conflicts 153 | [InstallDelete] 154 | Type: filesandordirs; Name: "{app}\bin\{#smartdPynguiDir}"; 155 | 156 | [UninstallDelete] 157 | Type: Files; Name: "{app}\bin\erroraction.cmd"; 158 | Type: Files; Name: "{app}\bin\erroraction_config.cmd"; 159 | Type: Files; Name: "{app}\bin\smartd.conf"; 160 | Type: Files; Name: "{app}\bin\drivedb.h.old"; 161 | Type: Files; Name: "{app}\bin\scheduled_send.cmd"; 162 | Type: Files; Name: "{app}\bin\{#smartdPynguiDir}\*.log"; 163 | Type: dirifempty; Name: "{app}\bin"; 164 | Type: dirifempty; Name: "{app}"; 165 | 166 | [Code] 167 | var 168 | InitialLogFile: String; 169 | //pageid: integer; 170 | 171 | #include "smartmontools for Windows includes.iss" 172 | 173 | procedure UpdateSmartdConfFile(); 174 | begin 175 | /// Modifiy app path for smartd.conf 176 | FileReplaceString(ExpandConstant('{app}\bin\smartd.conf'), '[PATH]', ExpandConstant('{app}\bin')); 177 | end; 178 | 179 | function NoExternalSmartdFile(): Boolean; 180 | begin 181 | if (FileExists(Expandconstant('{src}\smartd.conf'))) then 182 | begin 183 | FileCopy(ExpandConstant('{src}\smartd.conf'), ExpandConstant('{app}\bin\smartd.conf'), False); 184 | UpdateSmartdConfFile(); 185 | result := false; 186 | end else 187 | result := true; 188 | end; 189 | 190 | procedure UpdateErroractionConfFile(); 191 | begin 192 | //// Modify erroraction_config.cmd with app path and warning message 193 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), '[PATH]', ExpandConstant('{app}\bin')); 194 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), '[WARNING_MESSAGE]', ExpandConstant('{cm:warningmessage}')); 195 | 196 | //// Depending on options selected, set MAIL_ALERT=yes/no and LOCAL_ALERT=yes/no in erroraction_config.cmd 197 | //// To lazy to find out how to use wildcards with FileReplaceString --> old disgusting way 198 | if (WizardIsComponentSelected('core\service\mailalert')) then 199 | begin 200 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'MAIL_ALERT=no', 'MAIL_ALERT=yes'); 201 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'MAIL_ALERT=' + #13#10, 'MAIL_ALERT=yes'); 202 | end else 203 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'MAIL_ALERT=yes', 'MAIL_ALERT=no'); 204 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'MAIL_ALERT=' + #13#10, 'MAIL_ALERT=no'); 205 | 206 | if (WizardIsComponentSelected('core\service\localalert')) then 207 | begin 208 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'LOCAL_ALERT=no', 'LOCAL_ALERT=yes'); 209 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'LOCAL_ALERT=' + #13#10, 'LOCAL_ALERT=yes'); 210 | end else 211 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'LOCAL_ALERT=yes', 'LOCAL_ALERT=no'); 212 | FileReplaceString(ExpandConstant('{app}\bin\erroraction_config.cmd'), 'LOCAL_ALERT=' + #13#10, 'LOCAL_ALERT=no'); 213 | end; 214 | 215 | function NoExternalErroractionFile(): Boolean; 216 | begin 217 | if (FileExists(Expandconstant('{src}\erroraction_config.cmd'))) then 218 | begin 219 | FileCopy(ExpandConstant('{src}\erroraction_config.cmd'), ExpandConstant('{app}\bin\erroraction_config.cmd'), False); 220 | UpdateErroractionConfFile(); 221 | Result := false; 222 | end 223 | else 224 | Result := true; 225 | end; 226 | 227 | //// Create a file called smart.(version).log including info about all disks 228 | function CreateInitialLog(): Boolean; 229 | var 230 | resultcode: Integer; 231 | 232 | begin 233 | ////TODO: detect smartd.conf drives 234 | InitialLogFile := ExpandConstant('{app}\smartmontools-install-{#MajorVersion}-{#MinorVersion}.log'); 235 | SaveStringToFile(InitialLogFile, '# Smartmontools for Windows installed on ' + GetDateTimeString('dd mmm yyyy hh:nn:ss', #0, #0) + #13#10 + #13#10, True); 236 | ShellExec('', ExpandConstant('{cmd}') ,ExpandConstant('/c for /f "delims= " %i in (' + #39 + '"{app}\bin\smartctl" --scan' + #39 +') do "{app}\bin\smartctl.exe" -a %i >> "' + InitialLogFile + '"'), '', SW_HIDE, ewWaitUntilTerminated, resultcode) 237 | if resultcode = 0 then 238 | Result := true 239 | else 240 | Result := false 241 | end; 242 | 243 | //// ScheduledTask command file 244 | procedure WriteScheduledTest(); 245 | begin 246 | //// Create scheduled tasks configuration file 247 | SaveStringToFile(ExpandConstant('{app}\bin\scheduled_send.cmd'), ':: This file was generated on ' + GetDateTimeString('dd mmm yyyy', #0, #0) + ' by smartmontools for Windows package' + #13#10, False); 248 | SaveStringToFile(ExpandConstant('{app}\bin\scheduled_send.cmd'), ':: http://www.netpower.fr' + #13#10#13#10, True); 249 | SaveStringToFile(ExpandConstant('{app}\bin\scheduled_send.cmd'), '@echo off' + #13#10, True); 250 | SaveStringToFile(ExpandConstant('{app}\bin\scheduled_send.cmd'), ':: Attention: schtasks cannot set Run if missed' + #13#10, True); 251 | SaveStringToFile(ExpandConstant('{app}\bin\scheduled_send.cmd'), ExpandConstant('schtasks /CREATE /TN "Smartmontools for Windows Test" /XML "{app}\bin\ScheduledTask.xml" /RU System /F') + #13#10, True); 252 | 253 | //// Modify Scheduled task file with app path 254 | FileReplaceString(ExpandConstant('{app}\bin\ScheduledTask.xml'), '[PATH]', ExpandConstant('{app}\bin')); 255 | end; 256 | 257 | // TODO 258 | procedure TestForExistingSmartdUpstream(); 259 | begin 260 | if ((FileExists(ExpandConstant('{pf32}\smartmontools\bin\smartd.exe'))) or (FileExists(ExpandConstant('{pf}\smartmontools\bin\smartd.exe')))) then 261 | begin 262 | if (ServiceExists('{#SmartServiceName}') = true) then 263 | begin 264 | if (MsgBox('Upstream smartd service is installed. Do you want to replace the upstream service ?', mbConfirmation, MB_YESNO) = IDYES) then 265 | begin 266 | UninstallService('{#SmartServiceName}'); 267 | InstallService; 268 | end 269 | end 270 | else 271 | InstallService; 272 | end 273 | else 274 | if (ServiceExists('{#SmartServiceName}') = true) then 275 | UninstallService('{#SmartServiceName}'); 276 | InstallService; 277 | end; 278 | 279 | procedure SendInstallerStats(); 280 | var 281 | Version: TWindowsVersion; 282 | WindowsString: String; 283 | Parameters: String; 284 | ResultCode: Integer; 285 | 286 | begin 287 | GetWindowsVersionEx(Version); 288 | WindowsString := IntToStr(Version.Major) + '.' + IntToStr(Version.Minor) + ' build ' + IntToStr(Version.Build) + ' SP ' + IntToStr(Version.ServicePackMajor) + '.' + IntToStr(Version.ServicePackMinor) 289 | 290 | if (Version.NTPlatform = true) then 291 | WindowsString := WindowsString + ' NT'; 292 | 293 | if (Version.ProductType = VER_NT_WORKSTATION) then 294 | WindowsString := WindowsString + ' NT_WORKSTATION' 295 | else if (Version.ProductType = VER_NT_DOMAIN_CONTROLLER) then 296 | WindowsString := WindowsString + ' NT_DOMAIN_CONTROLLER' 297 | else if (Version.ProductType = VER_NT_SERVER) then 298 | WindowsString := WindowsString + ' NT_SERVER'; 299 | 300 | if (Version.SuiteMask = VER_SUITE_BACKOFFICE) then 301 | WindowsString := WindowsString + ' SUITE_BACKOFFICE' 302 | else if (Version.SuiteMask = VER_SUITE_BLADE) then 303 | WindowsString := WindowsString + ' SUITE_BLADE' 304 | else if (Version.SuiteMask = VER_SUITE_DATACENTER) then 305 | WindowsString := WindowsString + ' SUITE_DATACENTER' 306 | else if (Version.SuiteMask = VER_SUITE_ENTERPRISE) then 307 | WindowsString := WindowsString + ' SUITE_ENTERPRISE' 308 | else if (Version.SuiteMask = VER_SUITE_EMBEDDEDNT) then 309 | WindowsString := WindowsString + ' SUITE_EMBEDDEDNT' 310 | else if (Version.SuiteMask = VER_SUITE_PERSONAL) then 311 | WindowsString := WindowsString + ' SUITE_PERSONAL' 312 | else if (Version.SuiteMask = VER_SUITE_SINGLEUSERTS) then 313 | WindowsString := WindowsString + ' SUITE_SINGLEUSERTS' 314 | else if (Version.SuiteMask = VER_SUITE_SMALLBUSINESS) then 315 | WindowsString := WindowsString + ' SUITE_SMALLBUSINESS' 316 | else if (Version.SuiteMask = VER_SUITE_SMALLBUSINESS_RESTRICTED) then 317 | WindowsString := WindowsString + ' SUITE_SMALLBUSINESS_RESTRICTED' 318 | else if (Version.SuiteMask = VER_SUITE_TERMINAL) then 319 | WindowsString := WindowsString + ' SUITE_TERMINAL'; 320 | if (IsWin32) then 321 | WindowsString := WindowsString + ' Win32' 322 | else 323 | WindowsString := WindowsString + ' Win64'; 324 | 325 | Parameters := ExpandConstant(' -qO- "' + 'http://instcount.netpower.fr?program={#AppShortName}&version={#MajorVersion}-{#MinorVersion}.{#SubBuild}{#BuildType}&action=install&os=' + WindowsString + '"') 326 | //MsgBox("Statistics parameters: " + Parameters, mbInformation, MB_OK); 327 | Exec(ExpandConstant('{tmp}\wget-1.14.exe'), parameters, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) 328 | end; 329 | 330 | function InitializeSetup(): Boolean; 331 | begin 332 | 333 | // Stop the smartd service before upgrading 334 | if (IsUpdateInstall() = true) then 335 | UnloadService('{#SmartServiceName}'); 336 | result := True; 337 | end; 338 | 339 | //// After installation execution hook 340 | procedure CurStepChanged(CurStep: TSetupStep); 341 | //var Sender: TObject; 342 | begin 343 | if CurStep = ssDone then 344 | begin 345 | CreateInitialLog(); 346 | LoadService('{#SmartServiceName}'); 347 | end; 348 | end; 349 | 350 | //// Before uninstallation execution hook 351 | procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); 352 | begin 353 | if CurUninstallStep = usUninstall then 354 | if (IsSmartWinService('{#SmartServiceName}') = true) then 355 | begin 356 | UninstallService('{#SmartServiceName}'); 357 | end 358 | else 359 | begin 360 | if (MsgBox('There is a smartd service is installed which does not seem to belong to smartmontools-win. Do you want to uninstall it ?', mbConfirmation, MB_YESNO) = IDYES) then 361 | UninstallService('{#SmartServiceName}'); 362 | end 363 | end; 364 | -------------------------------------------------------------------------------- /smartmontools for Windows strings.iss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deajan/smartmontools-win/852b1bd877e6d167a405e8877cb6f60885779ca4/smartmontools for Windows strings.iss -------------------------------------------------------------------------------- /unattended/erroraction_config.cmd: -------------------------------------------------------------------------------- 1 | :: erroraction_config.cmd file for smartmontools for Windows v6.5+ 2 | 3 | :: Valid values are: yes, no 4 | set MAIL_ALERT=yes 5 | 6 | 7 | set SOURCE_MAIL= 8 | set DESTINATION_MAIL= 9 | set SMTP_SERVER= 10 | set SMTP_PORT=25 11 | set SMTP_USER= 12 | 13 | :: SMTP Password must be encoded in base64 (example via https://www.base64encode.org) 14 | set SMTP_PASSWORD= 15 | 16 | :: Security may be: none, ssl or tls 17 | set SECURITY=none 18 | 19 | :: Valid values are: yes, no 20 | set LOCAL_ALERT=no 21 | 22 | :: You may change this to a customized warning message or leave it to the default 23 | set WARNING_MESSAGE=[WARNING_MESSAGE] 24 | 25 | :: Valid values are: yes, no 26 | set COMPRESS_LOGS=yes 27 | 28 | -------------------------------------------------------------------------------- /unattended/smartd.conf: -------------------------------------------------------------------------------- 1 | # Standard smartd.conf file for smartmontools for Windows - http://www.netpower.fr 2 | # The following line lets smartd autodetect drives, usually works for SATA / IDE drives 3 | 4 | # Please leave [PATH] which will be replaced by the install path of smartmontools-win 5 | 6 | DEVICESCAN -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 7 | 8 | # If using drives that can't be autodetected, you may specify them directly (don't forget to uncomment) 9 | 10 | #/dev/sda -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 11 | #/dev/csmi0,0 -H -l error -f -C 197+ -U 198+ -t -l selftest -I 194 -m -M exec "[PATH]\erroraction.cmd" -n sleep,7,q -s (S/../.././10|L/../../[5]/13) 12 | 13 | --------------------------------------------------------------------------------