mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 14:25:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecee0047df | ||
|
|
c954101bd9 | ||
|
|
d20aeb4121 | ||
|
|
9440de5ca9 | ||
|
|
c2955b508c | ||
|
|
fbf70814f0 | ||
|
|
a823790926 | ||
|
|
14838b82ae | ||
|
|
e11347c005 | ||
|
|
98842f238e | ||
|
|
5ffc87ad9b | ||
|
|
fb5d139443 | ||
|
|
9d6ee05660 | ||
|
|
1ee97606aa | ||
|
|
b6f721c167 | ||
|
|
ede4933819 | ||
|
|
70ce4a6d06 | ||
|
|
213c26db3f | ||
|
|
8ae3c42100 | ||
|
|
ff466a1d2d | ||
|
|
5e46ed7cb6 | ||
|
|
c197ba76fa | ||
|
|
fa2b10f3ce | ||
|
|
7b523aa075 | ||
|
|
0ca9971460 | ||
|
|
b3f23abec0 | ||
|
|
a2d735fee5 | ||
|
|
fb801d8ebb | ||
|
|
9a92bfec45 | ||
|
|
6d50abb3cf | ||
|
|
778872363a | ||
|
|
6c404d57c9 | ||
|
|
449b645278 | ||
|
|
02428a26c0 | ||
|
|
90bbc19923 | ||
|
|
4f5690c89b | ||
|
|
4000fa1a2e | ||
|
|
ba7ffafa7f | ||
|
|
33b59d5723 | ||
|
|
28551a9666 | ||
|
|
c5478d6a0e | ||
|
|
2ca8174054 | ||
|
|
10e4496bb7 | ||
|
|
880d876ccf | ||
|
|
2ffec89ed8 | ||
|
|
5c257ffdc4 | ||
|
|
dc6297b0c9 |
+1
-1
@@ -13,4 +13,4 @@ install-sh
|
||||
*.glade.cpp
|
||||
*.ui.cpp
|
||||
*.txt.cpp
|
||||
gsmartcontrol.spec
|
||||
.kdev4
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2006-2008 Alexander Chemeris
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -18,8 +18,9 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
|
||||
|
||||
|
||||
All files which don't have any copyright notices, tests and examples are
|
||||
covered under the Whatever License. See LICENSE_whatever.txt for details.
|
||||
All files which don't have any copyright notices, as well as tests and
|
||||
examples are covered under the Unlicense. See LICENSE_unlicense.txt for
|
||||
details.
|
||||
|
||||
|
||||
Portions of this software are copyright Google Inc. See LICENSE_pcrecpp.txt
|
||||
|
||||
+6
-2
@@ -9,14 +9,18 @@ All original code (except for the tests) is licensed under the Zlib License.
|
||||
See LICENSE_zlib.txt for details.
|
||||
|
||||
|
||||
All tests and examples are covered under the Whatever License. See
|
||||
LICENSE_whatever.txt for details.
|
||||
All tests and examples are covered under the Unlicense. See
|
||||
LICENSE_unlicense.txt for details.
|
||||
|
||||
|
||||
Portions of this software are copyright Regents of the University of
|
||||
California, see LICENSE_bsd-ucb.txt for details.
|
||||
|
||||
|
||||
Portions of this software are copyright Alexander Chemeris, see
|
||||
LICENSE_bsd-ac.txt for details.
|
||||
|
||||
|
||||
Portions of this software are licensed under Boost Software License, see
|
||||
LICENSE_boost_1_0.txt and individual source files for copyright information.
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2005, Google Inc.
|
||||
Copyright (c) 2005 - 2010, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
@@ -1,12 +0,0 @@
|
||||
Whatever License
|
||||
|
||||
THIS SOFTWARE IS PROVIDED 'AS-IS', WITHOUT ANY EXPRESS OR IMPLIED
|
||||
WARRANTY. IN NO EVENT WILL THE AUTHORS BE HELD LIABLE FOR ANY DAMAGES
|
||||
ARISING FROM THE USE OF THIS SOFTWARE.
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely.
|
||||
+96
-6
@@ -2,7 +2,7 @@
|
||||
# Add autoconf.m4 directory to local macro search path
|
||||
ACLOCAL_AMFLAGS = -I autoconf.m4
|
||||
|
||||
SUBDIRS = src data
|
||||
SUBDIRS = data debian.dist src
|
||||
|
||||
|
||||
# These files are actually needed for compilation.
|
||||
@@ -16,21 +16,28 @@ noinst_DATA = AUTHORS.txt LICENSE_gsmartcontrol.txt README.txt
|
||||
# Some of these files are actually needed for compilation (see src/res/Makefile.am).
|
||||
dist_doc_DATA = AUTHORS.txt ChangeLog NEWS README.txt \
|
||||
LICENSE_boost_1_0.txt \
|
||||
LICENSE_bsd-ac.txt \
|
||||
LICENSE_bsd-ucb.txt \
|
||||
LICENSE_gpl2.txt \
|
||||
LICENSE_gpl3.txt \
|
||||
LICENSE_gsmartcontrol.txt \
|
||||
LICENSE_hz.txt \
|
||||
LICENSE_pcrecpp.txt \
|
||||
LICENSE_whatever.txt \
|
||||
LICENSE_unlicense.txt \
|
||||
LICENSE_zlib.txt
|
||||
|
||||
|
||||
# nobase_ preserves their directory names.
|
||||
nobase_dist_doc_DATA = contrib/cron-based_noadmin/README \
|
||||
contrib/cron-based_noadmin/cron_gather_smart.sh \
|
||||
contrib/cron-based_noadmin/crontab.example \
|
||||
contrib/cron-based_noadmin/smartctl_subst.sh
|
||||
|
||||
|
||||
# Extra files bundled with distribution.
|
||||
# file2csource.sh is needed for building but not installed.
|
||||
EXTRA_DIST = COPYING TODO INSTALL configure autogen.sh \
|
||||
baqup gsmartcontrol.kdevelop \
|
||||
templates \
|
||||
EXTRA_DIST = COPYING INSTALL configure autogen.sh \
|
||||
gsmartcontrol.kdev4 \
|
||||
file2csource.sh \
|
||||
gsmartcontrol.spec
|
||||
|
||||
@@ -46,7 +53,6 @@ gch: global_macros.h.gch
|
||||
gch-clean:
|
||||
rm -f global_macros.h.gch
|
||||
|
||||
distclean-local: gch-clean
|
||||
|
||||
|
||||
# rpm support
|
||||
@@ -60,3 +66,87 @@ src-rpm: dist
|
||||
# rpmbuild -ta $(distdir).tar.bz2
|
||||
|
||||
|
||||
|
||||
# NSIS installer support.
|
||||
# Requires wine, installed NSIS, smartctl-nc.exe, smartctl.exe.
|
||||
# Gtkmm dlls and pcre dlls are required if linking against them.
|
||||
# dos2unix on build machine.
|
||||
# Execute only with win32 build present.
|
||||
|
||||
WIN_ZIP_NAME = $(PACKAGE)-$(VERSION)-win32
|
||||
WIN_ZIP_NOGTK_NAME = $(PACKAGE)-$(VERSION)-win32-nogtk
|
||||
|
||||
|
||||
win-dist: win-dist-nocleanup win-dist-cleanup
|
||||
|
||||
win-dist-nocleanup: win-dist-prepare nsis-dist-nocleanup win-zip-dist-nocleanup
|
||||
|
||||
win-dist-cleanup: win-zip-dist-cleanup nsis-dist-cleanup
|
||||
rm -rf win-dist
|
||||
|
||||
win-dist-clean: win-dist-cleanup
|
||||
rm -f gsmartcontrol-*.exe gsmartcontrol-*.zip
|
||||
|
||||
|
||||
win-dist-prepare-all: nsis-dist-prepare win-zip-dist-prepare
|
||||
|
||||
|
||||
win-dist-prepare: all
|
||||
$(MKDIR_P) win-dist
|
||||
cp $(top_srcdir)/data/icon_*.png win-dist/
|
||||
|
||||
$(MKDIR_P) win-dist/doc
|
||||
cp data/nsis/distribution*.txt win-dist/doc/
|
||||
cp $(top_srcdir)/AUTHORS.txt $(top_srcdir)/LICENSE_* $(top_srcdir)/README.txt win-dist/doc/
|
||||
cp $(top_srcdir)/NEWS win-dist/doc/NEWS.txt
|
||||
|
||||
cp "@WINDOWS_BINDIR@"/smartctl-nc.exe win-dist/
|
||||
cp "@WINDOWS_BINDIR@"/smartctl.exe win-dist/
|
||||
|
||||
cp src/gsmartcontrol.exe src/gsmartcontrol.exe.manifest win-dist/
|
||||
|
||||
unix2dos win-dist/doc/*.txt
|
||||
$(STRIP) win-dist/*.exe
|
||||
|
||||
|
||||
nsis-dist-prepare: win-dist-prepare
|
||||
cp -a win-dist nsis-dist
|
||||
cp $(top_srcdir)/data/gsmartcontrol.ico nsis-dist/
|
||||
cp data/nsis/*.nsi $(top_srcdir)/data/nsis/nsi_* nsis-dist/
|
||||
unix2dos nsis-dist/*.nsi
|
||||
cp "@WINDOWS_BINDIR@"/"@GTK_INSTALLER_NAME@".exe nsis-dist/
|
||||
|
||||
nsis-dist-nocleanup: nsis-dist-prepare
|
||||
cd nsis-dist && @NSIS_EXEC@ gsmartcontrol.nsi
|
||||
mv nsis-dist/$(PACKAGE)-$(VERSION).exe .
|
||||
cd nsis-dist && @NSIS_EXEC@ /DNO_GTK gsmartcontrol.nsi
|
||||
mv nsis-dist/$(PACKAGE)-$(VERSION)-nogtk.exe .
|
||||
|
||||
nsis-dist-cleanup:
|
||||
rm -rf nsis-dist
|
||||
|
||||
nsis-dist: nsis-dist-nocleanup nsis-dist-cleanup
|
||||
|
||||
|
||||
win-zip-dist-prepare:
|
||||
cp -a win-dist $(WIN_ZIP_NAME)
|
||||
cp -a win-dist $(WIN_ZIP_NOGTK_NAME)
|
||||
cp -a "@WINDOWS_BINDIR@"/"@GTK_INSTALLER_NAME@"/* $(WIN_ZIP_NAME)/
|
||||
|
||||
win-zip-dist-nocleanup: win-zip-dist-prepare
|
||||
zip -K -9r $(WIN_ZIP_NAME).zip $(WIN_ZIP_NAME) -x $(WIN_ZIP_NAME)/doc/distribution-nogtk.txt
|
||||
zip -K -9r $(WIN_ZIP_NOGTK_NAME).zip $(WIN_ZIP_NOGTK_NAME) -x $(WIN_ZIP_NOGTK_NAME)/doc/distribution.txt
|
||||
|
||||
win-zip-dist-cleanup:
|
||||
rm -rf $(WIN_ZIP_NAME)
|
||||
rm -rf $(WIN_ZIP_NOGTK_NAME)
|
||||
|
||||
win-zip-dist: win-zip-dist-nocleanup win-zip-dist-cleanup
|
||||
|
||||
|
||||
|
||||
|
||||
distclean-local: gch-clean win-dist-clean
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,108 @@
|
||||
|
||||
Version 0.8.6, released on 2011-05-29
|
||||
Support detecting drives behind 3ware controllers (Linux, Windows),
|
||||
including tw_cli/cx/px mode in Windows. Having tw_cli is recommended
|
||||
but not required.
|
||||
Added support for specifying -d option and extra parameters via command
|
||||
line, "Add Device" and "Preferences" dialogs. This change effectively
|
||||
adds full support for multiple drives behind a single device name.
|
||||
Beesu and su-to-root are supported by gsmartcontrol-root script now.
|
||||
Completely revamped the attribute database and its handling, should be a
|
||||
lot more usable and forward-compatible now; SSD attributes are also
|
||||
included.
|
||||
In-program help has been expanded considerably.
|
||||
General improvements to user interface have been implemented (better GNOME
|
||||
HIG compliance, better tooltips, dialogs, etc...).
|
||||
Added ability to show smartctl output for devices whose info could not be
|
||||
parsed fully.
|
||||
Attributes in "brief" format are supported now.
|
||||
The parser has been updated to reflect the recent changes in smartctl.
|
||||
Quit and rescan operations are no longer denied without confirmation when
|
||||
tests are running.
|
||||
The Windows NSIS installer has been vastly improved.
|
||||
Better support for Windows Vista and 7.
|
||||
Changed copyright notices for files with Whatever License to use Unlicense.
|
||||
Added other minor features and fixed quite a few bugs.
|
||||
|
||||
Version 0.8.5, released on 2009-09-05
|
||||
GSmartControl now uses XDG config directory for per-user configuration on
|
||||
UNIX and CSIDL_PROFILE directory on Windows. Existing configuration is
|
||||
migrated automatically.
|
||||
The names are shown correctly for unsupported devices even with the latest
|
||||
smartctl snapshots now.
|
||||
Smartctl SVN revision is shown (if available).
|
||||
The progress bars update properly when parallel tests are run.
|
||||
Windows: GSmartControl should be able to operate on any valid filesystem
|
||||
path (not just locale-representable ones).
|
||||
Windows: GSmartControl is now officially compilable on x86_64 via mingw64.
|
||||
Fixed compilation under very old gtkmm/libglademm, and with gcc 4.4.
|
||||
Fixed parsing of multiple error types in SMART error log.
|
||||
Added minor features and fixed miscellaneous bugs.
|
||||
|
||||
Version 0.8.4, released on 2009-03-23
|
||||
Linux Software RAID devices are blacklisted now. (backported from Debian).
|
||||
Attributes tab is before the capabilities tab now.
|
||||
A man page has been generously contributed by Giuseppe Iuculano
|
||||
<giuseppe@iuculano.it>.
|
||||
Smartctl version now includes the CVS snapshot date (if available).
|
||||
Windows: Look for "smartctl-nc.exe" instead of "smartctl.exe" by default.
|
||||
Windows: Use smartmontools-supplied smartctl-nc.exe by default (if found).
|
||||
Other minor changes (mainly Debian backports).
|
||||
|
||||
Version 0.8.3, released on 2008-12-27
|
||||
A random "Smartctl returned an empty output" error on Windows was fixed.
|
||||
Thanks to Zurab Khetsuriani for testing.
|
||||
Fixed a parser issue which prevented running self-tests in Windows.
|
||||
The supplied icon (hopefully) shows correctly in Windows 2000 now.
|
||||
This release adds an official support for Windows 2000 SP4.
|
||||
Added scripts to allow GSmartControl to read smartctl data from
|
||||
cron-generated files. This allows users to read somewhat recent
|
||||
smartctl information without having to run GSmartControl as root.
|
||||
Generously contributed by Alex Butcher <alex dot butcher 'at'
|
||||
assursys.co.uk>.
|
||||
Configure script correctly aborts instead of printing a warning if gtkmm
|
||||
or libglademm (if needed) is not found.
|
||||
Configure script now accepts --enable-windows-console,
|
||||
--disable-abort-if-no-gtkmm, --disable-abort-if-no-glade-reader,
|
||||
as well as Windows-supporting "auto" for --enable-nsis-wine and
|
||||
--with-nsis.
|
||||
Configure's --with-win32-env has been renamed to --with-windows-dlls.
|
||||
The "About" dialog shows version information now.
|
||||
Minor bugs were fixed.
|
||||
|
||||
Version 0.8.2, released on 2008-12-10
|
||||
Fixed gsmartcontrol_root.sh script to support distributions with no
|
||||
/usr/sbin in their users' paths (thanks to Erwan Velu).
|
||||
Added desktop auto-detection to gsmartcontrol_root.sh script. This allows
|
||||
us to use only one desktop file (thanks to Erwan Velu).
|
||||
Added Debian package directory (named "debian.dist" for now to avoid
|
||||
control file conflicts with Build Service).
|
||||
Renamed gsmartcontrol_root.sh to gsmartcontrol-root, to make Debian happy.
|
||||
Added make targets for Windows packages (zip and NSIS).
|
||||
Fixed Windows-related issues (Vista is fully supported now).
|
||||
Fixed minor bugs:
|
||||
Smartctl parser is win32-locale-aware now.
|
||||
No more unnecessary parsing.
|
||||
No segfault on exit under Windows and Solaris.
|
||||
A friendlier message is displayed if smartctl was not found.
|
||||
No highlighted labels when switching tabs in Information window.
|
||||
|
||||
Version 0.8.1, released on 2008-11-11
|
||||
Disabled Linux "by-id" drive detection - it's unreliable on some broken
|
||||
systems.
|
||||
Added some more attribute descriptions.
|
||||
Our names for attributes override smartctls' now.
|
||||
Added a proper "Add Device" dialog for Windows.
|
||||
Added an icon and resource file for Windows.
|
||||
Fixed minor bugs.
|
||||
|
||||
Version 0.8.0rc4, released on 2008-10-20
|
||||
FreeBSD support (tested with DesktopBSD 1.6 (FreeBSD 6.3) / x86).
|
||||
NetBSD support (tested with NetBSD 4.0.1 / x86).
|
||||
OpenBSD support (tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5).
|
||||
Solaris/gcc support (tested with Solaris 10 / x86 / gcc-3.4.3 / blastwave).
|
||||
Solaris/sunstudio support (tested with Solaris 10 / x86 / sunstudio12 / sunfreeware).
|
||||
Solaris/sunstudio support (tested with Solaris 10 / x86 / sunstudio12 /
|
||||
sunfreeware).
|
||||
Code to support Windows, Mac OS X, QNX.
|
||||
Support of older pcre versions (at least 4.5, maybe older too).
|
||||
Added gsmartcontrol_root.sh script to easily run gsmartcontrol as root.
|
||||
|
||||
+121
-56
@@ -10,7 +10,8 @@ Technology) data on modern hard disk drives. It allows you to inspect the
|
||||
drive's SMART data to determine its health, as well as run various tests on
|
||||
it.
|
||||
|
||||
Note: Only ATA drives (both PATA and SATA) are supported for now.
|
||||
Note: GSmartControl supports ATA drives (both PATA and SATA), various USB to
|
||||
ATA bridges and drives behind 3ware RAID controllers.
|
||||
|
||||
http://gsmartcontrol.berlios.de
|
||||
|
||||
@@ -18,30 +19,31 @@ http://gsmartcontrol.berlios.de
|
||||
|
||||
Features
|
||||
|
||||
Automatically report and hilight any abnormal SMART information.
|
||||
* automatically reports and highlights any anomalies;
|
||||
|
||||
Ability to enable / disable SMART.
|
||||
* allows enabling/disabling SMART;
|
||||
|
||||
Ability to enable / disable Automatic Offline Data Collection - A short
|
||||
* allows enabling/disabling Automatic Offline Data Collection - a short
|
||||
self-check that the drive will perform automatically every four hours with no
|
||||
impact on performance.
|
||||
impact on performance;
|
||||
|
||||
Ability to set global and per-drive options for smartctl.
|
||||
* supports configuration of global and per-drive options for smartctl;
|
||||
|
||||
Display drive identity, capabilities, attributes, error and self-test logs.
|
||||
* performs SMART self-tests;
|
||||
|
||||
Perform SMART self-tests.
|
||||
* displays drive identity information, capabilities, attributes, and
|
||||
self-test/error logs;
|
||||
|
||||
Ability to load smartctl output as a "virtual" device, which acts just like a
|
||||
real (read-only) device.
|
||||
* can read in smartctl output from a saved file, interpreting it as a
|
||||
read-only virtual device;
|
||||
|
||||
Works on most smartctl-supported operating systems.
|
||||
* works on most smartctl-supported operating systems;
|
||||
|
||||
Extensive help information.
|
||||
* has extensive help information.
|
||||
|
||||
|
||||
|
||||
What is SMART?
|
||||
What Is SMART?
|
||||
|
||||
Short answer: SMART is a technology which provides hard disk drives with
|
||||
methods to predict certain kinds of failures with certain chance of success.
|
||||
@@ -60,7 +62,7 @@ the drive is idle, and repair the defects, reallocating the data to more safe
|
||||
areas.
|
||||
|
||||
While having SMART sounds really good, there are some nuances to consider. One
|
||||
of the commond pitfalls is that it may create a false sense of security. That
|
||||
of the common pitfalls is that it may create a false sense of security. That
|
||||
is, a perfectly good SMART data is NOT an indication that the drive won't fail
|
||||
the next minute. The reverse is also true - some drives may function perfectly
|
||||
even with not-so-good-looking SMART data. However, as studies indicate, given
|
||||
@@ -99,16 +101,36 @@ You need to have the following software installed:
|
||||
* Gtkmm, version 2.6 or higher - see http://www.gtkmm.org .
|
||||
|
||||
* libglademm, version 2.4 or higher - see http://www.gtkmm.org .
|
||||
libglademm is not needed when using GTK 2.12 and Gtkmm 2.12.
|
||||
Note: libglademm is not needed when using GTK / Gtkmm 2.12 or newer.
|
||||
|
||||
Note that having GTK+ 2.12 and Gtkmm 2.12 is HIGHLY recommended. While earlier
|
||||
versions may work, they may produce suboptimal results and buggy behavior.
|
||||
|
||||
Most of these packages are probably already provided by your distribution.
|
||||
Here are the packages you need to have to build GSmartControl on some Linux
|
||||
distributions:
|
||||
|
||||
openSUSE, SLES, SLED:
|
||||
gcc-c++, pcre-devel, gtkmm2-devel, (possibly) libglademm-devel.
|
||||
|
||||
Fedora, CentOS, RHEL:
|
||||
gcc-c++, pcre-devel, gtkmm24-devel, (possibly) libglademm24-devel.
|
||||
|
||||
Mandriva:
|
||||
gcc-c++, gcc-cpp, libpcre-devel, gtkmm2.4-devel, (possibly)
|
||||
libglademm2.4-devel.
|
||||
|
||||
Ubuntu, Debian GNU/Linux:
|
||||
g++, libpcre3-dev, libgtkmm-2.4-dev, (possibly) libglademm-2.4-dev.
|
||||
|
||||
Note that usually you need to specify only these packages - the rest is
|
||||
installed automatically by the package manager's dependency resolver. Keep in
|
||||
mind that you also need smartmontools to run the program.
|
||||
|
||||
Note: If using the official Windows package, the requirements are listed on
|
||||
GSmartControl's website.
|
||||
|
||||
Note that GTK+ 2.12 and Gtkmm 2.12 are HIGHLY recommended. While earlier
|
||||
versions may work, they may produce ugly results and buggy behaviour.
|
||||
Libglademm is not needed when using GTK / Gtkmm 2.12.
|
||||
|
||||
Most of these packages are probably already provided by your distribution. For
|
||||
example, to build this program on OpenSUSE, you just need to install
|
||||
smartmontools, gtkmm2-devel and pcre-devel - the rest is installed
|
||||
automatically by the package manager's dependency resolver.
|
||||
|
||||
The following operating systems are supported:
|
||||
|
||||
@@ -120,36 +142,40 @@ The following operating systems are supported:
|
||||
|
||||
* OpenBSD - Tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5.
|
||||
|
||||
* Windows (2000 SP4 or newer) - Tested with Windows 2000 SP4, Windows XP SP3,
|
||||
Windows Vista SP2 (32-bit and 64-bit), Windows 7 SP1 (32-bit and 64-bit). The
|
||||
Windows port uses pd0, pd1, etc... for physical drives 0, 1, etc... .
|
||||
|
||||
* Solaris - Tested with Solaris 10 / x86 / gcc-3.4.3 / blastwave,
|
||||
Solaris 10 / x86 / sunstudio12 / sunfreeware. OpenSolaris should work but has
|
||||
not been tested yet. Note that until either smartctl gets ATA support under
|
||||
Solaris or GSmartControl gets SCSI support, these configurations are
|
||||
essentially useless.
|
||||
not been tested yet. Note: smartctl doesn't seem to support ATA under Solaris,
|
||||
while GSmartControl doesn't support SCSI yet. This only leaves various USB to
|
||||
ATA bridges. See smartctl (5), -d option for details.
|
||||
|
||||
* Mac OS X - 3rd-party testing by Fink project.
|
||||
|
||||
* DragonFlyBSD - Code written but no testing has been performed yet. Expected
|
||||
to work without any issues.
|
||||
|
||||
* Windows (NT line only) - Only minimal testing has been performed. Expected
|
||||
to work. The Windows port uses /dev/pd0, /dev/pd1, etc... for physical drives
|
||||
0, 1, etc... .
|
||||
|
||||
* Mac OS X - Code written but no testing has been performed yet.
|
||||
|
||||
* QNX - Code written but no testing has been performed yet.
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
|
||||
Short answer: ./configure; make; make install
|
||||
Short answer: build and install via: ./configure; make; make install
|
||||
|
||||
Run gsmartcontrol-root to invoke gsmartcontrol with your desktop's su
|
||||
mechanism, or use the desktop menu entry.
|
||||
|
||||
|
||||
Long answer: read below.
|
||||
|
||||
First, check if you can find a pre-built package for your distribution or
|
||||
operating system - they usually provide the best integration and the easiest
|
||||
installation procedure. For Linux, one option is to try the OpenSUSE Build
|
||||
installation procedure. For Linux, one option is to try the openSUSE Build
|
||||
Service - it provides ready-to-install packages for various popular Linux
|
||||
distributions (OpenSUSE, Fedora, etc...). See
|
||||
distributions (openSUSE, Fedora, etc...). See
|
||||
http://download.opensuse.org/repositories/home:/alex_sh/ .
|
||||
|
||||
If you want to compile from source, check that you have all the required
|
||||
@@ -157,15 +183,53 @@ dependencies (see Software Requirements section). Then the usual
|
||||
|
||||
./configure; make; make install
|
||||
|
||||
will build and install it. Installation usually requires adminstrative
|
||||
will build and install it. Installation usually requires administrative
|
||||
privileges, but you don't need to install the program in order to run it
|
||||
directly from the compilation directory.
|
||||
directly from the build directory.
|
||||
|
||||
|
||||
|
||||
Command Line Options
|
||||
|
||||
GSmartControl inherits options from GTK+ and other libraries, so be sure to
|
||||
run it with --help option to get a full list of accepted parameters.
|
||||
Note: The Windows version may not have a text output at all, so --help and
|
||||
similar arguments won't have any effect. However, --verbose will still
|
||||
increase the verbosity of a log saved via "Options -> View Execution Log ->
|
||||
Save All".
|
||||
|
||||
The most important parameters are:
|
||||
|
||||
-?, --help - Show help options.
|
||||
|
||||
-V, --version - Display version information.
|
||||
|
||||
-l, --no-locale - Disable locale.
|
||||
|
||||
--no-scan - Don't scan devices on startup.
|
||||
|
||||
--no-hide-tabs - Don't hide non-identity tabs when SMART is disabled.
|
||||
|
||||
--add-virtual - Load smartctl data from file, creating a virtual drive.
|
||||
|
||||
--add-device - Add this device to device list. The format of the device is
|
||||
"<device>::<type>::<extra_args>", where type and extra_args are optional.
|
||||
This option is useful with --no-scan to list certain drives only. You can
|
||||
specify this option multiple times.
|
||||
Example: --add-device /dev/sda --add-device /dev/twa0::3ware,2
|
||||
--add-device '/dev/sdb::::-T permissive'
|
||||
|
||||
-v, --verbose - Enable verbose logging; same as --verbosity-level 5.
|
||||
|
||||
-q, --quiet - Disable logging; same as --verbosity-level 0.
|
||||
|
||||
-b, --verbosity-level - Set verbosity level [0-5].
|
||||
|
||||
|
||||
|
||||
Permission Problems
|
||||
|
||||
Short answer: you need to be root (Administrator in Windows).
|
||||
Short answer: you need to be root (that's Administrator in Windows).
|
||||
In X11, use kdesu, gnomesu, sux, xdg-su or similar.
|
||||
|
||||
Long answer: read below.
|
||||
@@ -179,8 +243,8 @@ password" dialog boxes, and, after correct information is entered, should run
|
||||
this program with root privileges. The dialogs should be available in most
|
||||
commonly used X11 desktop environments.
|
||||
|
||||
Another way is to use the included gsmartcontrol_root.sh script, which finds
|
||||
the available su program and runs gsmartcontrol with it.
|
||||
Another way is to use the included gsmartcontrol-root script, which finds the
|
||||
available su program and runs gsmartcontrol with it.
|
||||
|
||||
Yet another way is to manually invoke the program with kdesu, gnomesu, sux or
|
||||
similar programs. For example,
|
||||
@@ -210,9 +274,10 @@ previously, it will be re-enabled on reboot.
|
||||
The easiest way to work around this is to set the desired settings on system
|
||||
startup. You may use smartctl or smartd to do that. For example, to enable
|
||||
both SMART and Automatic Offline Data Collection on /dev/sda, one would write
|
||||
the following to his/her boot.local, rc.local or similar:
|
||||
the following to the system startup script (e.g. boot.local, rc.local or
|
||||
similar on Linux):
|
||||
|
||||
smartctl --smart=on --offlineauto=on /dev/sda
|
||||
smartctl -s on -o on /dev/sda
|
||||
|
||||
For more information, see smartctl and smartd documentation.
|
||||
|
||||
@@ -220,12 +285,12 @@ For more information, see smartctl and smartd documentation.
|
||||
|
||||
Known Issues
|
||||
|
||||
Only ATA (both PATA and SATA) disks are supported for now. The main reasons
|
||||
are:
|
||||
Only ATA drives (both PATA and SATA), various USB to ATA bridges and drives
|
||||
behind 3ware RAID controllers are supported for now. The main reasons are:
|
||||
|
||||
* We can't support drives which don't work with smartmontools. This affects
|
||||
drives which don't support SMART or don't export SMART data correctly (e.g.
|
||||
USB enclosures, RAIDs, etc...).
|
||||
some USB enclosures, RAIDs, etc...).
|
||||
|
||||
* Smartctl's output for SCSI drives is completely different compared to ATA.
|
||||
Also, SCSI drives are rarely found in desktop systems and the servers rarely
|
||||
@@ -234,19 +299,14 @@ have X11 / Gtkmm running, so this is a low priority task.
|
||||
* I only have ATA drives, so testing would be almost impossible.
|
||||
|
||||
Immediate Offline Tests are not supported. I haven't found a way to reliably
|
||||
monitor them yet.
|
||||
|
||||
You may run several tests on different drives in parallel, but you will only
|
||||
see the progress information of the last executing test. So, if you run tests
|
||||
on drives A, B and C (in that order), you won't be able to monitor the tests
|
||||
on A and B until C completes. And you won't be able to see any progress on A
|
||||
until both B and C complete their tests.
|
||||
monitor them yet. Besides, they run automatically anyway if Automatic Offline
|
||||
Data Collection is enabled.
|
||||
|
||||
Testing is only supported on drives which correctly report their progress
|
||||
information in capabilities.
|
||||
|
||||
Not all drives support disabling Automatic Offline Data Collection, even if
|
||||
they report otherwise.
|
||||
they report otherwise. Unfortunately, there's no way to detect such drives.
|
||||
|
||||
Running on GTK+ / Gtkmm versions earlier than 2.12 may cause visual artifacts,
|
||||
usability issues (especially with tooltips and icons), instability, etc...
|
||||
@@ -266,14 +326,17 @@ terminal emulator (e.g., xterm, konsole or gnome-terminal):
|
||||
|
||||
smartctl -a /dev/sda
|
||||
|
||||
Note: If using Windows, the device name should be /dev/pd1 for the second
|
||||
physical drive, etc... .
|
||||
|
||||
If you still think it's a GSmartControl issue, please collect the following
|
||||
information about your system. Without it, it may be very hard or impossible
|
||||
to fix the bug.
|
||||
|
||||
* Which operating system you use (for example, OpenSUSE Linux 11.0).
|
||||
* Which operating system you use (for example, openSUSE Linux 11.4).
|
||||
|
||||
* Which version of GTK and Gtkmm you have installed. Finding this out is very
|
||||
distribution-specific. For example, on OpenSUSE it would be
|
||||
distribution-specific. For example, on openSUSE it would be
|
||||
"rpm -q gtk2 gtkmm2". Some distributions have gtkmm24 instead. You may also
|
||||
search them in your distribution's graphical package manager, if there is one.
|
||||
|
||||
@@ -281,7 +344,9 @@ search them in your distribution's graphical package manager, if there is one.
|
||||
with -v option, e.g. (type the following in a terminal emulator or Run
|
||||
dialog):
|
||||
|
||||
gsmartcontrol_root.sh other -v
|
||||
gsmartcontrol-root auto -v
|
||||
|
||||
Note: On Windows, run gsmartcontrol.exe with "-v" switch as Administrator.
|
||||
|
||||
Perform the steps needed to reproduce the bug, then go to
|
||||
"Options -> View Execution Log", and click "Save All".
|
||||
@@ -305,7 +370,7 @@ For license information, see LICENSE_gsmartcontrol.txt file.
|
||||
|
||||
You may notice that GSmartControl is not licensed under "GNU GPL version X or
|
||||
later", but under "GNU GPL version X and Y". I firmly believe that it's unwise
|
||||
to license a piece of code under non-existant licenses, whatever anyone else
|
||||
to license a piece of code under non-existent licenses, whatever anyone else
|
||||
might say. The reason for this is that one simply CANNOT know that, say, in 20
|
||||
years FSF won't be bought by some corporation who will release GPL version Z
|
||||
which will completely reverse the reasons GPL was created for.
|
||||
|
||||
@@ -16,26 +16,19 @@ local scope destruction also works if using stack variables.
|
||||
|
||||
|
||||
A treeview (also iconview, combobox) from glade comes
|
||||
with existing model, which should be unset
|
||||
with existing model, which should be unset.
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
Bugs / patches:
|
||||
|
||||
portability:
|
||||
win32 32-bit: int: 4, long: 4, pointer: 4.
|
||||
win32 64-bit: int: 4, long: 8, pointer: 8.
|
||||
Patch pangomm for Pango::strip_markup().
|
||||
|
||||
sparc: same as win32 (what about OS?).
|
||||
+ gtkmm bug: No Gtk::AboutDialog::set_logo(NULL);
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
GTKMM problems:
|
||||
|
||||
|
||||
Lots of gtk_, GTK_, g_ in documentation.
|
||||
|
||||
|
||||
no ComboBox::unset_model() and IconView::unset_model().
|
||||
+ Gtk::Main m(argc, argv, false);
|
||||
If gtk_get_option_group() and g_option_context_parse() were used before,
|
||||
this generates a warning:
|
||||
(gsmartcontrol:28241): Gtk-WARNING **: gtk_disable_setlocale() must be called before gtk_init()
|
||||
|
||||
|
||||
|
||||
@@ -44,78 +37,183 @@ no ComboBox::unset_model() and IconView::unset_model().
|
||||
TODO:
|
||||
|
||||
|
||||
test, release RC version for testing.
|
||||
Update to drivedb.h from 5.41, include 5.41 into release.
|
||||
|
||||
|
||||
|
||||
Testing:
|
||||
If ETA time has elapsed, but it's still only at 10% completion,
|
||||
ETA 0 is displayed. Fix.
|
||||
If smartctl -t ... returns an error, testing=true should not be set.
|
||||
Can't reproduce it?
|
||||
Detect running tests on launch (maybe ask the user too? some tests
|
||||
may be stuck due to bad firmware, e.g. 3ware/windows).
|
||||
|
||||
|
||||
Add support for launching with consolehelper (from usermode package).
|
||||
Fedora uses this by default.
|
||||
Investigate Fedora selinux situation.
|
||||
usermode-gtk contains consolehelper-gtk, not sure about our package
|
||||
requirement. consolehelper-gtk is not supposed to be launched by user,
|
||||
but I think we can check it with "which".
|
||||
http://fedoranews.org/contributors/matt_hansen/nautilus/
|
||||
|
||||
|
||||
Rework drive properties UI:
|
||||
use 48-bit or not or auto.
|
||||
Enable/disable/dont_touch SMART on startup for this drive.
|
||||
Enable/disable/dont_touch AODC on startup for this drive.
|
||||
Add --init-smart-only option to only apply the SMART/AODC enabling status
|
||||
from the drive properties.
|
||||
Add also --no-init-smart to avoid doing that on GUI startup.
|
||||
|
||||
Notifications:
|
||||
Tied to (drive::subdrive, notif_key, exact_value(optional)).
|
||||
If exact_value isn't specified when ignoring, notify on every value change.
|
||||
Ignore options:
|
||||
Per-drive: Ignore all notifications for this key, ignore only this value.
|
||||
Don't generate multiple notifications for the same drive/key combo.
|
||||
Clearing in preferences: Clear all ignored, clear ignored for this drive, clear individual.
|
||||
Soft-warnings require "-a" by default, tricky for scsi (maybe try -a, then -i?).
|
||||
|
||||
Monitor:
|
||||
Needs root access, so not gonna happen until the dbus/udisks stuff
|
||||
is finalized.
|
||||
Same program, add --tray option to start in tray only.
|
||||
Option to enable the tray icon.
|
||||
Option to continue running in the tray on window close.
|
||||
Use freedesktop notifications when notifications are generated
|
||||
and we're running in tray only.
|
||||
Don't generate the same notification at a single run time if it was
|
||||
ignored (untouched) by the user; Change the tray icon and
|
||||
show them in the main window instead.
|
||||
Periodically re-run smartctl to refresh the notifications.
|
||||
Periodically see if drives were added / removed (possibly use OS callbacks
|
||||
instead of polling?)
|
||||
|
||||
If a drive is not recognized, suggest using -d (sat, sat,12, ...)
|
||||
Refer the user to
|
||||
http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_USB-Devices
|
||||
|
||||
|
||||
|
||||
RAID:
|
||||
http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_RAID-Controllers
|
||||
|
||||
Areca Linux:
|
||||
Call as: smartctl -i -d areca,[1-24] /dev/sg0
|
||||
Detection:
|
||||
Check if /proc/scsi/sg/device_strs contains "Areca RAID controller".
|
||||
If not, there's no Areca controller present.
|
||||
Check /proc/scsi/sg/devices, the line # with type 3 is the sg* number.
|
||||
The "host" field value is the N value in /sys, see below.
|
||||
Check /sys/bus/scsi/devices/hostN/scsi_host/hostN/host_fw_hd_channels, set
|
||||
its contents as the number of ports. If not present, use 24.
|
||||
Probe each port for a valid drive: If the output contains "Device Read Identity Failed",
|
||||
then there is no drive on that port (or Areca has an old firmware, nothing we can
|
||||
do there).
|
||||
Notification: If /sys/bus/scsi/devices/hostN/scsi_host/hostN/host_fw_version
|
||||
is older than "V1.46 2009-01-06", notify the user (maybe its better to grep
|
||||
the smartctl output for that on port 0?).
|
||||
|
||||
3ware FreeBSD:
|
||||
Call as: smartctl -i -d 3ware,[0-127] /dev/twa0 (or twe0)
|
||||
Detection: unknown.
|
||||
|
||||
LSI MegaRAID (SCSI/SAS), Linux:
|
||||
Call as: smartctl -i -d megaraid,[0-?] /dev/sda
|
||||
We should differentiate between ordinary sda and RAID one (not sure if sda is detected).
|
||||
Detection: unknown.
|
||||
|
||||
HighPoint RocketRAID ((S)ATA) Linux:
|
||||
Call as: smartctl -i -d hpt,[1-8]/[1-8] /dev/sda
|
||||
Call as: smartctl -i -d hpt,[1-8]/[1-8]/[1-15] /dev/sda
|
||||
Note: /dev/sda should be derived from this controller.
|
||||
We should differentiate between ordinary sda and RAID one (not sure if sda is detected).
|
||||
Smartctl docs specify smaller limits, but the code says these are the ones.
|
||||
Detection: unknown.
|
||||
|
||||
HighPoint RocketRAID ((S)ATA) FreeBSD:
|
||||
Call as: smartctl -i -d hpt,[1-8]/[1-8] /dev/hptrr
|
||||
Call as: smartctl -i -d hpt,[1-8]/[1-8]/[1-15] /dev/hptrr
|
||||
Note: /dev/hptrr should be derived from this controller.
|
||||
Smartctl docs specify smaller limits, but the code says these are the ones.
|
||||
Detection: unknown.
|
||||
TODO: Analyze sent info.
|
||||
|
||||
CCISS (HP (Compaq) Smart Array Controller) Linux:
|
||||
Call as: smartctl -a -d cciss,[0-127] /dev/cciss/c0d0
|
||||
c0d0 is the controller (d0 seems to be a logical drive, doesn't matter?).
|
||||
/dev/cciss/c0d0p1 is the first ordinary partition (used in mount, etc...).
|
||||
The port limit had a brief regression in 5.39.x (limited to 15).
|
||||
5.39 doesn't seem to work at all (prereleases work with P400 controller)?
|
||||
Possibly a 64-bit-only issue?
|
||||
To detect controller presence: cat /proc/devices, contains "cciss0"
|
||||
for controller 0.
|
||||
There is a cciss_vol_status utility but it doesn't report anything except "OK" status.
|
||||
It may not return the "SMART Health Status: OK" line in smartctl -i for some reason?
|
||||
(It returns it in -a though, and in some freebsd output I found).
|
||||
If no /dev/cciss exists, you may need to run "cd /dev; ./MAKEDEV cciss".
|
||||
Smartctl SVN has some /dev/sg* stuff, check it out.
|
||||
|
||||
CCISS (HP (Compaq) Smart Array Controller) FreeBSD:
|
||||
Seems to be the same as Linux (uses the same driver?).
|
||||
Detection: unknown.
|
||||
|
||||
|
||||
|
||||
|
||||
libdebug:
|
||||
per-channel disabling.
|
||||
per-channel formatting.
|
||||
all flags should be per-channel.
|
||||
bug: if -q is passed, Execution log doesn't contain libdebug log. (requires per-channel status control).
|
||||
use format_time() instead of ctime() and friends, with ISO formatting.
|
||||
|
||||
|
||||
48-bit ATA command support:
|
||||
'-l xerror' -> Extended Comprehensive Error log: An multi-sector and
|
||||
LBA48 capable version of '-l error'. Output is similar, except more
|
||||
entries can exists and the high bytes of the registers are also printed.
|
||||
Some newer drives (Samsung) only write to this log.
|
||||
|
||||
'-l xselftest' -> Extended Self Test Log: An multi-sector and LBA48
|
||||
capable version of '-l selftest'. Output will be similar, except more
|
||||
entries can exists and the LBA values can be somewhat longer.
|
||||
|
||||
"smartctl -l this_wont_exist" gives the list of supported logs - this
|
||||
is needed to detect xerror / xselftest support in smartctl.
|
||||
|
||||
|
||||
|
||||
'-l sataphy' -> SATA Phy event counters: Non-SMART feature, useful to detect SATA cabling problems.
|
||||
|
||||
|
||||
----------- Feature List ----------
|
||||
|
||||
+Autodetect available devices
|
||||
|
||||
+Select current device (from autodetected list; manually whitelist devices).
|
||||
|
||||
+Smartctl binary (text entries in Options - binary, default command line options).
|
||||
+ Global command-line options for smartctl.
|
||||
+ Command-line options per-device in settings (e.g. -d ata).
|
||||
+ Search smartctl binary on startup (try to execute it with --version). If it's not there, alert the user.
|
||||
|
||||
+Indicate which of the devices has SMART supported / enabled.
|
||||
+ Enable / disable smart on devices.
|
||||
+ Indicate that this is until shutdown (but may be preserved on reboot).
|
||||
+ Direct them to smartd / smartctl documentation for permanent enabling.
|
||||
+ NOTE: SMART is sometimes preserved across power cycles.
|
||||
|
||||
+Enable / disable Automatic Offline Data Collection for devices. (-o on)
|
||||
+ Show its status in the main window.
|
||||
|
||||
+Show identity information for device (aka short info), --info.
|
||||
|
||||
+Show all SMART information for device (--all), includes:
|
||||
+ * Short info (--info)
|
||||
+ * SMART DATA
|
||||
+ * overall-health (-H, --health) - may check this automatically as well.
|
||||
+ * General SMART Values, aka Capabilities (-c, --capabilities)
|
||||
+ * Attributes (-A, --attributes). These need decoding.
|
||||
+ * Error Log (-l error)
|
||||
+ * Self-test log (-l selftest)
|
||||
+ * Selective self-test log and settings
|
||||
* SCT status and other stuff
|
||||
Display temperature somewhere (use SCT or Attr 194 for this).
|
||||
Which one is updated more frequently, SCT or attr 194?
|
||||
+ * Ability to save this information to a file.
|
||||
+ * On info window show: Ask to turn SMART on if it's disabled
|
||||
|
||||
+Program error reporting:
|
||||
+ invalid smartmontools version.
|
||||
+ cannot parse output - show log.
|
||||
+ smartctl exited with error - look it up in error map.
|
||||
|
||||
|
||||
SCT Temperatures (do we use these?)
|
||||
SCT Temperatures
|
||||
-l scttemp prints temperature and history.
|
||||
-t scttempint,N[,p] (N - count, p - preserve across reset or not).
|
||||
This configures temperature logging interval (1 min by default) and clears the history.
|
||||
-l scterc[,...] to get/set the SCT Error Recovery Control time limit (5.40 and newer).
|
||||
|
||||
|
||||
+Tests:
|
||||
Ability to detect a testing drive on boot, show its info with testing tab.
|
||||
Add detection for Interix (i586-pc-interix3), maybe with debian?
|
||||
|
||||
Run one-time Immediate Offline test (-t offline).
|
||||
Offline tests only update Attributes, and if errors are found they will
|
||||
appear in SMART error log. Self-test logs are unaffected.
|
||||
Abort (-X). Abort works with Offline only if there's
|
||||
"Abort Offline collection upon new command" capability.
|
||||
If the drive has "Suspend Offline collection upon new command" capability,
|
||||
immediate offline test may be tracked through --capabilities (not on mine!).
|
||||
If it's "Abort Offline collection upon new command", then the test
|
||||
will abort on --capabilities or --abort.
|
||||
|
||||
|
||||
|
||||
----------- SMART stuff ----------
|
||||
|
||||
|
||||
Run one-time Immediate Offline test (-t offline).
|
||||
Offline tests only update Attributes, and if errors are found they will
|
||||
appear in SMART error log. Self-test logs are unaffected.
|
||||
Abort (-X). Abort works with Offline only if there's
|
||||
"Abort Offline collection upon new command" capability.
|
||||
If the drive has "Suspend Offline collection upon new command" capability,
|
||||
immediate offline test may be tracked through --capabilities (not on mine!).
|
||||
If it's "Abort Offline collection upon new command", then the test
|
||||
will abort on --capabilities or --abort.
|
||||
|
||||
|
||||
Polling time
|
||||
|
||||
@@ -26,12 +26,23 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_EXCEPTIONS],
|
||||
[AC_CACHE_CHECK(whether the compiler supports exceptions,
|
||||
ac_cv_cxx_exceptions,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[try { throw 1; } catch (int i) { return i; }]])],[ac_cv_cxx_exceptions=yes],[ac_cv_cxx_exceptions=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_exceptions" = yes; then
|
||||
AC_DEFINE(HAVE_EXCEPTIONS,,[define if the compiler supports exceptions])
|
||||
fi
|
||||
ac_cv_cxx_exceptions,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
[[try { throw 1; } catch (int i) { return i; }]])],
|
||||
[ac_cv_cxx_exceptions=yes], [ac_cv_cxx_exceptions=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
|
||||
if test "$ac_cv_cxx_exceptions" = yes; then
|
||||
AC_DEFINE(HAVE_EXCEPTIONS, 1,
|
||||
[defined to 1 if the compiler supports exceptions, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_EXCEPTIONS, 0,
|
||||
[defined to 1 if the compiler supports exceptions, 0 otherwise])
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,12 +26,22 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_NAMESPACES],
|
||||
[AC_CACHE_CHECK(whether the compiler implements namespaces,
|
||||
ac_cv_cxx_namespaces,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[namespace Outer { namespace Inner { int i = 0; }}]], [[using namespace Outer::Inner; return i;]])],[ac_cv_cxx_namespaces=yes],[ac_cv_cxx_namespaces=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_namespaces" = yes; then
|
||||
AC_DEFINE(HAVE_NAMESPACES,,[define if the compiler implements namespaces])
|
||||
fi
|
||||
ac_cv_cxx_namespaces,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[namespace Outer { namespace Inner { int i = 0; }}]],
|
||||
[[using namespace Outer::Inner; return i;]])],
|
||||
[ac_cv_cxx_namespaces=yes], [ac_cv_cxx_namespaces=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_namespaces" = yes; then
|
||||
AC_DEFINE(HAVE_NAMESPACES, 1,
|
||||
[defined to 1 if the compiler implements namespaces, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_NAMESPACES, 0,
|
||||
[defined to 1 if the compiler implements namespaces, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
+31
-21
@@ -26,25 +26,35 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_RTTI],
|
||||
[AC_CACHE_CHECK(whether the compiler supports Run-Time Type Identification,
|
||||
ac_cv_cxx_rtti,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
class Base { public :
|
||||
Base () {}
|
||||
virtual int f () { return 0; }
|
||||
};
|
||||
class Derived : public Base { public :
|
||||
Derived () {}
|
||||
virtual int f () { return 1; }
|
||||
};
|
||||
]], [[Derived d;
|
||||
Base *ptr = &d;
|
||||
return typeid (*ptr) == typeid (Derived);
|
||||
]])],[ac_cv_cxx_rtti=yes],[ac_cv_cxx_rtti=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_rtti" = yes; then
|
||||
AC_DEFINE(HAVE_RTTI,,
|
||||
[define if the compiler supports Run-Time Type Identification])
|
||||
fi
|
||||
ac_cv_cxx_rtti,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
class Base {
|
||||
public:
|
||||
Base () {}
|
||||
virtual int f () { return 0; }
|
||||
};
|
||||
class Derived : public Base {
|
||||
public :
|
||||
Derived () {}
|
||||
virtual int f () { return 1; }
|
||||
};
|
||||
]], [[
|
||||
Derived d;
|
||||
Base* ptr = &d;
|
||||
return typeid (*ptr) == typeid (Derived);
|
||||
]])],
|
||||
[ac_cv_cxx_rtti=yes], [ac_cv_cxx_rtti=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_rtti" = yes; then
|
||||
AC_DEFINE(HAVE_RTTI, 1,
|
||||
[defined to 1 if the compiler supports Run-Time Type Identification, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_RTTI, 0,
|
||||
[defined to 1 if the compiler supports Run-Time Type Identification, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,16 +25,25 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_VERBOSE_TERMINATE_HANDLER],
|
||||
[AC_CACHE_CHECK(whether the compiler has __gnu_cxx::__verbose_terminate_handler,
|
||||
ac_cv_verbose_terminate_handler,
|
||||
[
|
||||
AC_REQUIRE([AC_CXX_EXCEPTIONS])
|
||||
AC_REQUIRE([AC_CXX_NAMESPACES])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <exception>]], [[std::set_terminate(__gnu_cxx::__verbose_terminate_handler);]])],[ac_cv_verbose_terminate_handler=yes],[ac_cv_verbose_terminate_handler=no
|
||||
])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_verbose_terminate_handler" = yes; then
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, , [define if the compiler has __gnu_cxx::__verbose_terminate_handler])
|
||||
fi
|
||||
ac_cv_verbose_terminate_handler,
|
||||
[
|
||||
AC_REQUIRE([AC_CXX_EXCEPTIONS])
|
||||
AC_REQUIRE([AC_CXX_NAMESPACES])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#include <exception>]],
|
||||
[[std::set_terminate(__gnu_cxx::__verbose_terminate_handler);]])],
|
||||
[ac_cv_verbose_terminate_handler=yes], [ac_cv_verbose_terminate_handler=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_verbose_terminate_handler" = yes; then
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, 1,
|
||||
[defined to 1 if the compiler has __gnu_cxx::__verbose_terminate_handler, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, 0,
|
||||
[defined to 1 if the compiler has __gnu_cxx::__verbose_terminate_handler, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -22,6 +22,12 @@ AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
AC_ARG_ENABLE(abort-if-no-glade-reader, AS_HELP_STRING([--disable-abort-if-no-glade-reader],
|
||||
[disable abort if no glade file reader is found (default: configure aborts when glade file reader is not found)]),
|
||||
[app_cv_abort_if_no_glade_reader=${enableval}], [app_cv_abort_if_no_glade_reader=yes])
|
||||
|
||||
AC_MSG_NOTICE([Abort if no glade file reader is found: $app_cv_abort_if_no_glade_reader])
|
||||
|
||||
# This is just in case
|
||||
# PKG_PROG_PKG_CONFIG()
|
||||
|
||||
@@ -65,8 +71,24 @@ AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
# libglade specified, or auto and no gtkbuilder. gtkmm2.4-compatible libglademm is >= 2.4.0.
|
||||
# (not sure about libglade version).
|
||||
if test "x$app_cv_gld_reader" = "xnone"; then
|
||||
PKG_CHECK_MODULES([app_cv_gld_reader], [$app_cv_gld_reader_libglade_pkg_name >= 2.4.0],
|
||||
[app_cv_gld_reader="libglade"], [AC_MSG_WARN([$LIBGLADE_PKG_ERRORS])])
|
||||
if test "x$app_cv_gld_reader_libglade_name" = "xlibglade"; then
|
||||
# libglade
|
||||
PKG_CHECK_MODULES([LIBGLADE], [$app_cv_gld_reader_libglade_pkg_name >= 2.4.0],
|
||||
[app_cv_gld_reader="libglade"], [AC_MSG_WARN([$LIBGLADE_PKG_ERRORS])])
|
||||
app_cv_gld_reader_CFLAGS="$LIBGLADE_CFLAGS";
|
||||
app_cv_gld_reader_CXXFLAGS="$LIBGLADE_CFLAGS";
|
||||
app_cv_gld_reader_LIBS="$LIBGLADE_LIBS";
|
||||
else
|
||||
# libglademm
|
||||
PKG_CHECK_MODULES([LIBGLADEMM], [$app_cv_gld_reader_libglade_pkg_name >= 2.4.0],
|
||||
[app_cv_gld_reader="libglade"], [AC_MSG_WARN([$LIBGLADEMM_PKG_ERRORS])])
|
||||
app_cv_gld_reader_CFLAGS=""
|
||||
app_cv_gld_reader_CXXFLAGS="$LIBGLADEMM_CFLAGS";
|
||||
app_cv_gld_reader_LIBS="$LIBGLADEMM_LIBS";
|
||||
fi
|
||||
# reset them so they don't interfere later
|
||||
LIBGLADE_CFLAGS="";
|
||||
LIBGLADE_LIBS="";
|
||||
fi
|
||||
|
||||
if test "x$with_libglade" = "xyes" && test "x$app_cv_gld_reader" = "xnone"; then
|
||||
@@ -75,16 +97,13 @@ AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
|
||||
# still not found.
|
||||
if test "$app_cv_gld_reader" = "none"; then
|
||||
AC_MSG_WARN([Neither GtkBuilder nor $app_cv_gld_reader_libglade_name found. The program will be unable to compile fully.])
|
||||
fi
|
||||
|
||||
|
||||
# pkg-config doesn't do CXXFLAGS, so do it manually.
|
||||
app_cv_gld_reader_CXXFLAGS="$app_cv_gld_reader_CFLAGS";
|
||||
|
||||
# if using libglademm, it doesn't make any sense to leave the flags for C.
|
||||
if test "x$1" = "xC++"; then
|
||||
app_cv_gld_reader_CFLAGS="";
|
||||
if test "x$app_cv_abort_if_no_glade_reader" = "xno"; then
|
||||
AC_MSG_WARN([$LIBGLADE_PKG_ERRORS])
|
||||
AC_MSG_WARN([Neither GtkBuilder nor $app_cv_gld_reader_libglade_name found. The program will be unable to compile fully.])
|
||||
else
|
||||
AC_MSG_WARN([Neither GtkBuilder nor $app_cv_gld_reader_libglade_name found.])
|
||||
AC_MSG_ERROR([$LIBGLADE_PKG_ERRORS])
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -116,13 +135,17 @@ AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
# export to config.h
|
||||
if test "$app_cv_gld_reader" = "libglade"; then
|
||||
AC_DEFINE(ENABLE_LIBGLADE, 1, [Use libglade(mm) instead of GtkBuilder])
|
||||
else
|
||||
AC_DEFINE(ENABLE_LIBGLADE, 0, [Use libglade(mm) instead of GtkBuilder])
|
||||
fi
|
||||
if test "$app_cv_gld_reader" = "gtkbuilder"; then
|
||||
AC_DEFINE(ENABLE_GTKBUILDER, 1, [Use GtkBuilder instead of libglademm])
|
||||
else
|
||||
AC_DEFINE(ENABLE_GTKBUILDER, 1, [Use GtkBuilder instead of libglademm])
|
||||
fi
|
||||
|
||||
# If we move this to the start, some messages get in between, so we have to have it here.
|
||||
AC_MSG_CHECKING([for glade file support:])
|
||||
AC_MSG_CHECKING([for glade file support])
|
||||
|
||||
AC_MSG_RESULT([$app_cv_gld_reader])
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -50,19 +50,17 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# gcc / gnu environment, mingw, cygwin.
|
||||
if test "x$app_cv_compiler_common_options" = "xgnu"; then
|
||||
|
||||
if test "x$app_cv_target_os_env" = "xmingw" || test "x$app_cv_target_os_env" = "xcygwin"; then
|
||||
if test "x$app_cv_target_os_env" = "xmingw32" || test "x$app_cv_target_os_env" = "xmingw64" \
|
||||
|| test "x$app_cv_target_os_env" = "xcygwin"; then
|
||||
# mingw gcc options:
|
||||
# -mno-cygwin - generate non-cygwin executables in cygwin's mingw.
|
||||
# -mwindows - hide console window. possibly suppresses any std output / error.
|
||||
# -mms-bitfields - make structures compatible with msvc. recommended default for non-cygwin.
|
||||
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -mms-bitfields -mwindows"
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -mms-bitfields -mwindows"
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mms-bitfields -mwindows"
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -mms-bitfields"
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -mms-bitfields"
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mms-bitfields"
|
||||
fi
|
||||
|
||||
# Note: Disabled -Wconversion, it was causing lots of silly warnings under x86-64.
|
||||
app_cv_compiler_tmp_var="-Wall -Wcast-align -Wcast-qual \
|
||||
app_cv_compiler_tmp_var="-Wall -Wcast-align -Wcast-qual -Wconversion \
|
||||
-Wctor-dtor-privacy -Wfloat-equal -Wnon-virtual-dtor -Woverloaded-virtual \
|
||||
-Wpointer-arith -Wshadow -Wsign-compare -Wsign-promo -Wundef -Wwrite-strings";
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags $app_cv_compiler_tmp_var";
|
||||
@@ -80,7 +78,16 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# suncc
|
||||
elif test "x$app_cv_compiler_common_options" = "xsun"; then
|
||||
# Enable useful language extensions (e.g. __func__ in C++). Details at
|
||||
# http://docs.sun.com/app/docs/doc/819-5267/6n7c46drp?a=view
|
||||
# http://docs.sun.com/app/docs/doc/820-7599/bkapy?a=view
|
||||
# Additional options: "-staticlib=Crun -staticlib=Cstd" - link statically to
|
||||
# C++ runtime and standard libraries.
|
||||
# http://docs.sun.com/app/docs/doc/820-7599/bkaws?a=view
|
||||
|
||||
# STLport seems to be more standards-compliant, but incompatible
|
||||
# with default Cstd. Also, it's not guaranteed to keep compatibility
|
||||
# between versions. Select it with "-library=stlport4".
|
||||
# http://docs.sun.com/app/docs/doc/820-7599/bkakg?a=view
|
||||
# http://developers.sun.com/solaris/articles/cmp_stlport_libCstd.html
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags \
|
||||
+w -errtags -erroff=notemsource,notused -features=extensions";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags \
|
||||
@@ -167,11 +174,11 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# gcc, mingw
|
||||
if test "x$app_cv_compiler_optimize_options" = "xgnu"; then
|
||||
# -mtune=generic is since gcc 4.0 iirc
|
||||
if test "$app_cv_target_os_env" = "mingw" || test "$app_cv_target_os_env" = "cygwin"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s -march=i586";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s -march=i586";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s -march=i586";
|
||||
else
|
||||
if test "x$app_cv_target_os_env" = "xmingw32"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s -march=i686";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s -march=i686";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s -march=i686";
|
||||
else # mingw64, cygwin (they have new gcc), others.
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s -mtune=generic";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s -mtune=generic";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s -mtune=generic";
|
||||
@@ -214,6 +221,38 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
|
||||
|
||||
|
||||
# ---- Compiler options for Mingw's mwindows/mconsole
|
||||
|
||||
# -mwindows - hide console window. possibly suppresses any std output / error.
|
||||
# -mconsole - opposite of -mwindows, default.
|
||||
|
||||
AC_ARG_ENABLE(windows-console, AS_HELP_STRING([--enable-windows-console=yes|no|auto],
|
||||
[enable windows console (MinGW and Cygwin only). Accepted values are yes, no, auto. ]
|
||||
[Auto means disabled for optimized builds, enabled for all others. (Default: auto)]),
|
||||
[app_cv_compiler_windows_console=${enableval}], [app_cv_compiler_windows_console=auto])
|
||||
|
||||
if test "x$app_cv_compiler_windows_console" = "xauto"; then
|
||||
# disable console for optimized builds.
|
||||
if test "x$app_cv_compiler_optimize_options" != "xnone"; then
|
||||
app_cv_compiler_windows_console="no";
|
||||
else
|
||||
app_cv_compiler_windows_console="yes";
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$app_cv_target_os_env" = "xmingw32" || test "x$app_cv_target_os_env" = "xmingw64" \
|
||||
|| test "x$app_cv_target_os_env" = "xcygwin"; then
|
||||
if test "x$app_cv_compiler_windows_console" = "xno"; then
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mwindows";
|
||||
else
|
||||
# specify -mconsole even if it's the default - it should override the user-supplied setting
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mconsole";
|
||||
fi
|
||||
AC_MSG_NOTICE([Enable windows console: $app_cv_compiler_windows_console])
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# ---- Export our variables
|
||||
|
||||
if test "x$$1[]CFLAGS" = "x"; then
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports overloading between
|
||||
# extern "C" function pointer and C++ function pointer. GCC and
|
||||
# Check whether C++ compiler supports overloading of functions
|
||||
# with function pointer argument differing only in extern "C" specification,
|
||||
# that is, extern "C" function pointer and C++ function pointer. GCC and
|
||||
# Intel treat them equally, so no overloads are needed (or accepted)
|
||||
# there.
|
||||
|
||||
@@ -21,7 +22,8 @@
|
||||
# for template parameters (I don't remember the exact details).
|
||||
|
||||
|
||||
# If such support is found, HAVE_CXX_EXTERN_C_OVERLOAD is defined.
|
||||
# If such overloading support is found,
|
||||
# HAVE_CXX_EXTERN_C_OVERLOAD is defined.
|
||||
|
||||
|
||||
AC_DEFUN([APP_CXX_EXTERN_C_OVERLOAD], [
|
||||
@@ -37,8 +39,11 @@ AC_DEFUN([APP_CXX_EXTERN_C_OVERLOAD], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$ac_cv_cxx_extern_c_overload" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, ,
|
||||
[Define if the C++ complier accepts extern C function pointer overload])
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, 1,
|
||||
[Defined to 1 if the C++ complier accepts extern C function pointer overload, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, 0,
|
||||
[Defined to 1 if the C++ complier accepts extern C function pointer overload, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports C99 __func__.
|
||||
|
||||
AC_DEFUN([APP_CXX___FUNC__], [
|
||||
AC_DEFUN([APP_CXX___func__], [
|
||||
AC_CACHE_CHECK(whether $CXX recognizes __func__, app_cv_cxx___func__, [
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
@@ -17,8 +17,11 @@ AC_DEFUN([APP_CXX___FUNC__], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___func__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___func__, ,
|
||||
[Define if the C++ complier supports __func__])
|
||||
AC_DEFINE(HAVE_CXX___func__, 1,
|
||||
[Defined to 1 if the C++ complier supports __func__, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX___func__, 0,
|
||||
[Defined to 1 if the C++ complier supports __func__, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -35,8 +38,11 @@ AC_DEFUN([APP_CXX___FUNCTION__], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___FUNCTION__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, ,
|
||||
[Define if the C++ complier supports __FUNCTION__])
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, 1,
|
||||
[Defined to 1 if the C++ complier supports __FUNCTION__, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, 0,
|
||||
[Defined to 1 if the C++ complier supports __FUNCTION__, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -59,12 +59,26 @@ AC_DEFUN([APP_DETECT_OS_KERNEL], [
|
||||
app_cv_[]$1[]_os_kernel_macro="LINUX";
|
||||
;;
|
||||
|
||||
*mingw* | *cygwin*)
|
||||
i*86-*mingw* | i*86-*cygwin*)
|
||||
# mingw defines _WIN32. msvc defines _WIN32 (built-in), and WIN32 via windows.h.
|
||||
# Other mingw defines include: __WINNT, __WINNT__, __WIN32__, __i386, _X86_,
|
||||
# i386, __i386__, WIN32, __MINGW32__, WINNT (all equal to 1).
|
||||
app_cv_[]$1[]_os_kernel="windows";
|
||||
app_cv_[]$1[]_os_kernel_macro="WINDOWS";
|
||||
app_cv_[]$1[]_os_kernel="windows32";
|
||||
app_cv_[]$1[]_os_kernel_macro="WINDOWS32";
|
||||
;;
|
||||
|
||||
x86_64-*-mingw* | x86_64-*-cygwin*)
|
||||
# mingw64 defines the same stuff as 32-bit one, plus _WIN64, __MINGW64__, etc... .
|
||||
# Keep in mind that if you're generating a 32-bit application, the kernel will
|
||||
# be windows32 even if you run it on 64-bit Windows.
|
||||
app_cv_[]$1[]_os_kernel="windows64";
|
||||
app_cv_[]$1[]_os_kernel_macro="WINDOWS64";
|
||||
;;
|
||||
|
||||
*interix*)
|
||||
# Interix is a kernel on top of windows, so we treat it separately.
|
||||
app_cv_[]$1[]_os_kernel="interix";
|
||||
app_cv_[]$1[]_os_kernel_macro="INTERIX";
|
||||
;;
|
||||
|
||||
# This includes debian gnu/kfreebsd. Dragonfly is checked separately.
|
||||
@@ -124,8 +138,14 @@ AC_DEFUN([APP_DETECT_OS_KERNEL], [
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xlinux"; then
|
||||
AC_DEFINE($2[]LINUX, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xwindows"; then
|
||||
AC_DEFINE($2[]WINDOWS, 1, [$1 OS kernel])
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xwindows32"; then
|
||||
AC_DEFINE($2[]WINDOWS32, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xwindows64"; then
|
||||
AC_DEFINE($2[]WINDOWS64, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xinterix"; then
|
||||
AC_DEFINE($2[]INTERIX, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xfreebsd"; then
|
||||
AC_DEFINE($2[]FREEBSD, 1, [$1 OS kernel])
|
||||
@@ -154,7 +174,9 @@ AC_DEFUN([APP_DETECT_OS_KERNEL], [
|
||||
|
||||
# Export to Makefile.am's.
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_LINUX, [test "x${app_cv_[]$1[]_os_kernel}" = "xlinux"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_WINDOWS, [test "x${app_cv_[]$1[]_os_kernel}" = "xwindows"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_WINDOWS32, [test "x${app_cv_[]$1[]_os_kernel}" = "xwindows32"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_WINDOWS64, [test "x${app_cv_[]$1[]_os_kernel}" = "xwindows64"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_INTERIX, [test "x${app_cv_[]$1[]_os_kernel}" = "xinterix"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_FREEBSD, [test "x${app_cv_[]$1[]_os_kernel}" = "xfreebsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_DRAGONFLY, [test "x${app_cv_[]$1[]_os_kernel}" = "xdragonfly"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_OPENBSD, [test "x${app_cv_[]$1[]_os_kernel}" = "xopenbsd"])
|
||||
@@ -164,6 +186,19 @@ AC_DEFUN([APP_DETECT_OS_KERNEL], [
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_QNX, [test "x${app_cv_[]$1[]_os_kernel}" = "xqnx"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_UNKNOWN, [test "x${app_cv_[]$1[]_os_kernel}" = "xunknown"])
|
||||
|
||||
|
||||
# composite ones, for easy checking
|
||||
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_FAMILY_WINDOWS, \
|
||||
[test "x${app_cv_[]$1[]_os_kernel}" = "xwindows32" || test "x${app_cv_[]$1[]_os_kernel}" = "xwindows64" \
|
||||
|| test "x${app_cv_[]$1[]_os_kernel}" = "xinterix"])
|
||||
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xwindows32" || test "x${app_cv_[]$1[]_os_kernel}" = "xwindows64" \
|
||||
|| test "x${app_cv_[]$1[]_os_kernel}" = "xinterix"; then
|
||||
AC_DEFINE($2[]FAMILY_WINDOWS, 1, [$1 OS kernel family])
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_RESULT([${app_cv_[]$1[]_os_kernel}])
|
||||
])
|
||||
|
||||
@@ -216,9 +251,17 @@ AC_DEFUN([APP_DETECT_OS_ENV], [
|
||||
app_cv_[]$1[]_os_env="cygwin";
|
||||
app_cv_[]$1[]_os_env_macro="CYGWIN";
|
||||
;;
|
||||
*mingw*)
|
||||
app_cv_[]$1[]_os_env="mingw";
|
||||
app_cv_[]$1[]_os_env_macro="MINGW";
|
||||
i*86-*mingw*)
|
||||
app_cv_[]$1[]_os_env="mingw32";
|
||||
app_cv_[]$1[]_os_env_macro="MINGW32";
|
||||
;;
|
||||
x86_64-*-mingw*)
|
||||
app_cv_[]$1[]_os_env="mingw64";
|
||||
app_cv_[]$1[]_os_env_macro="MINGW64";
|
||||
;;
|
||||
*interix*)
|
||||
app_cv_[]$1[]_os_env="interix";
|
||||
app_cv_[]$1[]_os_env_macro="INTERIX";
|
||||
;;
|
||||
# This includes gnu/linux, debian gnu/kfreebsd, debian gnu/netbsd...
|
||||
*-gnu | gnu*)
|
||||
@@ -271,8 +314,14 @@ AC_DEFUN([APP_DETECT_OS_ENV], [
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xcygwin"; then
|
||||
AC_DEFINE($2[]CYGWIN, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xmingw"; then
|
||||
AC_DEFINE($2[]MINGW, 1, [$1 OS userspace environment])
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xmingw32"; then
|
||||
AC_DEFINE($2[]MINGW32, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xmingw64"; then
|
||||
AC_DEFINE($2[]MINGW64, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xinterix"; then
|
||||
AC_DEFINE($2[]INTERIX, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xgnu"; then
|
||||
AC_DEFINE($2[]GNU, 1, [$1 OS userspace environment])
|
||||
@@ -304,7 +353,9 @@ AC_DEFUN([APP_DETECT_OS_ENV], [
|
||||
|
||||
# Export to Makefile.am's.
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_CYGWIN, [test "x${app_cv_[]$1[]_os_env}" = "xcygwin"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_MINGW, [test "x${app_cv_[]$1[]_os_env}" = "xmingw"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_MINGW32, [test "x${app_cv_[]$1[]_os_env}" = "xmingw32"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_MINGW64, [test "x${app_cv_[]$1[]_os_env}" = "xmingw64"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_INTERIX, [test "x${app_cv_[]$1[]_os_env}" = "xinterix"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_GNU, [test "x${app_cv_[]$1[]_os_env}" = "xgnu"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_FREEBSD, [test "x${app_cv_[]$1[]_os_env}" = "xfreebsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_DRAGONFLY, [test "x${app_cv_[]$1[]_os_env}" = "xdragonfly"])
|
||||
@@ -315,6 +366,7 @@ AC_DEFUN([APP_DETECT_OS_ENV], [
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_QNX, [test "x${app_cv_[]$1[]_os_env}" = "xqnx"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_UNKNOWN, [test "x${app_cv_[]$1[]_os_env}" = "xunknown"])
|
||||
|
||||
|
||||
AC_MSG_RESULT([${app_cv_[]$1[]_os_env}])
|
||||
])
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_GET_MT_FLAGS(flags_prefix[, action-if-not-found])
|
||||
# This macro detects compiler flags which are needed to compile a multi-threaded
|
||||
# (possibly pthreads-based) applications on target OS. flags_prefixCFLAGS,
|
||||
# (preferably pthreads-based) applications on target OS. flags_prefixCFLAGS,
|
||||
# flags_prefixCXXFLAGS and flags_prefixLIBS will be initialized (or appended to)
|
||||
# with the correct flags.
|
||||
|
||||
@@ -47,7 +47,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
|
||||
|
||||
# Compilers use at least 3 defines to indicate thread-safe support to standard libs:
|
||||
# Compilers use at least 3 defines to enable thread-safe support:
|
||||
# _THREAD_SAFE, _MT, _REENTRANT.
|
||||
# We use the ones that are required for detected platform.
|
||||
|
||||
@@ -63,17 +63,20 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# suncc needs -lpthread on posix but not solaris.
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
# suncc's -mt expands to:
|
||||
# "-D_REENTRANT -lpthread" on Linux, uses pthreads (pthread.h);
|
||||
# "-D_REENTRANT -lthread" on Solaris, uses Solaris threads (thread.h).
|
||||
# To use pthreads on Solaris, use "-mt -lpthread".
|
||||
# http://docs.sun.com/app/docs/doc/820-7598/bjapp?a=view
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt -lpthread"
|
||||
app_cv_target_thread_libs="-mt"
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
fi
|
||||
;;
|
||||
|
||||
windows)
|
||||
windows*)
|
||||
# NOTE: Not sure about cygwin.
|
||||
# NOTE: This only enables multithreaded code generation. For linking
|
||||
# with pthreads-win32 you need additional flags.
|
||||
@@ -87,10 +90,20 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
;;
|
||||
|
||||
freebsd | dragonfly | netbsd | openbsd)
|
||||
interix)
|
||||
# Interix kernel is implemented on top of windows kernel.
|
||||
# Interix uses -D_REENTRANT for pthreads, automatically enabling -lpthread.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-D_REENTRANT"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
freebsd | dragonfly)
|
||||
# NOTE: Not sure about debian gnu/kfreebsd and gnu/netbsd.
|
||||
# Freebsd had -kthread, but it has been discontinued (afaik).
|
||||
# For freebsd -pthread already replaces libc with libc_r.
|
||||
# For freebsd -pthread replaces libc with libc_r.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
@@ -99,22 +112,48 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
;;
|
||||
|
||||
openbsd)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
fi
|
||||
;;
|
||||
|
||||
netbsd)
|
||||
# See sys/featuretest.h
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
fi
|
||||
;;
|
||||
|
||||
solaris)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread)
|
||||
app_cv_target_thread_cflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread).
|
||||
# _REENTRANT is needed to enable some thread-safe equivalents of standard
|
||||
# functions.
|
||||
# http://docs.sun.com/app/docs/doc/805-8005-04/6j7hcvqs4?l=ko&a=view
|
||||
app_cv_target_thread_cflags="-pthreads -D_MT -D_THREAD_SAFE -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthreads -D_MT -D_THREAD_SAFE -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthreads"
|
||||
app_cv_target_thread_found="yes"
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
# suncc's -mt expands to:
|
||||
# "-D_REENTRANT -lpthread" on Linux, uses pthreads (pthread.h);
|
||||
# "-D_REENTRANT -lthread" on Solaris, uses Solaris threads (thread.h).
|
||||
# To use pthreads on Solaris, use "-mt -lpthread".
|
||||
# http://docs.sun.com/app/docs/doc/820-7598/bjapp?a=view
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/pthreads-5?a=view
|
||||
# http://docs.sun.com/app/docs/doc/816-5137/compile-74765?a=view
|
||||
# There are two threading libraries, selectable via different switches.
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt"
|
||||
# We use POSIX threads, so append -lpthread.
|
||||
app_cv_target_thread_cflags="-mt -lpthread"
|
||||
app_cv_target_thread_cxxflags="-mt -lpthread"
|
||||
app_cv_target_thread_libs="-mt -lpthread"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
@@ -122,8 +161,6 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
darwin)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# Darwin produces mt code by default, and -pthread is an error.
|
||||
# gcc/darwin defines __APPLE__. __UNIX__ is not defined.
|
||||
# -D_THREAD_SAFE
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
# Basically, it's the same as AC_USE_SYSTEM_EXTENSIONS,
|
||||
# but uses compiler flag approach instead of config.h.
|
||||
|
||||
# The extensions used bring the system closer to the GNU,
|
||||
# X/Open (a superset of POSIX) and POSIX systems.
|
||||
|
||||
# You must call AX_COMPILER_VENDOR
|
||||
# and APP_DETECT_OS_ENV([target], ...) before using this macro.
|
||||
|
||||
@@ -66,10 +69,49 @@ AC_DEFUN([APP_USE_SYSTEM_EXTENSIONS], [
|
||||
solaris)
|
||||
# The problem with solaris is that it has too many incompatible
|
||||
# feature test macros, and there is no enable-all macro. Autoconf
|
||||
# mistakenly assumes that __EXTENSIONS__ is the one, but
|
||||
# it should be defined _in addition_ to feature test macros.
|
||||
# assumes that __EXTENSIONS__ is the one, but it should be defined
|
||||
# _in addition_ to feature test macros. Note that on its own, __EXTENSIONS__
|
||||
# still enables some useful stuff like _LARGEFILE64_SOURCE.
|
||||
# To support some posix macros, additional link objects are also required.
|
||||
# Some *_SOURCE feature test macros may be incompatible with C++.
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/standards-5?a=view
|
||||
app_cv_target_extension_cflags="-D__EXTENSIONS__"
|
||||
app_cv_target_extension_cxxflags="-D__EXTENSIONS__"
|
||||
;;
|
||||
|
||||
netbsd)
|
||||
# There is no enable-all macro.
|
||||
# (_XOPEN_SOURCE >= 500 || _NETBSD_SOURCE) is recommended.
|
||||
# The default is _NETBSD_SOURCE, _XOPEN_SOURCE overrides it.
|
||||
# The manual says that rename() will behave posix-like if _POSIX_C_SOURCE
|
||||
# is defined. However, stdio.h uses (_XOPEN_SOURCE <= 2) condition,
|
||||
# which is really bogus.
|
||||
# See sys/featuretest.h
|
||||
;;
|
||||
|
||||
mingw32)
|
||||
# This enables standards-compliant stdio behaviour (regarding printf and
|
||||
# friends), as opposed to msvc-compatible one. This is usually enabled
|
||||
# by default if one of the usual macros are encountered (_XOPEN_SOURCE,
|
||||
# _GNU_SOURCE, etc...).
|
||||
# Also, we make the win2k API available (includes console functions, etc...).
|
||||
# Other things to consider: _NO_OLDNAMES (disable "deprecated"
|
||||
# non-underscored names like chdir (use _chdir), etc...).
|
||||
# See _mingw.h for details.
|
||||
app_cv_target_extension_cflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0500"
|
||||
app_cv_target_extension_cxxflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0500"
|
||||
;;
|
||||
|
||||
mingw64)
|
||||
# Same as ming32, but enable "from xp" mode, since there's no x86_64 2k.
|
||||
app_cv_target_extension_cflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0501"
|
||||
app_cv_target_extension_cxxflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0501"
|
||||
;;
|
||||
|
||||
interix)
|
||||
# As per AC_USE_SYSTEM_EXTENSIONS.
|
||||
app_cv_target_extension_cflags="-D_ALL_SOURCE"
|
||||
app_cv_target_extension_cxxflags="-D_ALL_SOURCE"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
@@ -28,29 +28,40 @@
|
||||
|
||||
AC_DEFUN([AX_CXX_GCC_ABI_DEMANGLE],
|
||||
[AC_CACHE_CHECK(whether the compiler supports GCC C++ ABI name demangling,
|
||||
ac_cv_cxx_gcc_abi_demangle,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
ac_cv_cxx_gcc_abi_demangle,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <stdlib.h> /* not cstdlib */
|
||||
|
||||
template<typename TYPE>
|
||||
class A {};
|
||||
]], [[A<int> instance;
|
||||
int status = 0;
|
||||
char* c_name = 0;
|
||||
template<typename TYPE>
|
||||
class A {};
|
||||
]], [[
|
||||
A<int> instance;
|
||||
int status = 0;
|
||||
char* c_name = 0;
|
||||
|
||||
c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status);
|
||||
c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status);
|
||||
|
||||
std::string name(c_name);
|
||||
free(c_name);
|
||||
std::string name(c_name);
|
||||
free(c_name); /* not std::free() */
|
||||
|
||||
return name == "A<int>";
|
||||
]])],[ac_cv_cxx_gcc_abi_demangle=yes],[ac_cv_cxx_gcc_abi_demangle=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_gcc_abi_demangle" = yes; then
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE,1,
|
||||
[define if the compiler supports GCC C++ ABI name demangling])
|
||||
fi
|
||||
return name == "A<int>";
|
||||
]])],
|
||||
[ac_cv_cxx_gcc_abi_demangle=yes], [ac_cv_cxx_gcc_abi_demangle=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_gcc_abi_demangle" = yes; then
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE, 1,
|
||||
[defined to 1 if the compiler supports GCC C++ ABI name demangling, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE, 0,
|
||||
[defined to 1 if the compiler supports GCC C++ ABI name demangling, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configure a build directory according to developer flags
|
||||
|
||||
type="$1";
|
||||
configure_script="$2";
|
||||
|
||||
if [ "$type" == "" ]; then
|
||||
echo "Usage: $0 <type> [<configure_script>]"
|
||||
echo "where <type> is one of:"
|
||||
echo "debug optimized icc win32 win32-debug win64-debug sun portland open64";
|
||||
echo "<configure_script> is ../configure by default"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ "$configure_script" == "" ]; then
|
||||
configure_script="../configure";
|
||||
fi
|
||||
|
||||
|
||||
flags="";
|
||||
|
||||
case $type in
|
||||
optimized)
|
||||
flags="--disable-user-flags --enable-optimize-options --enable-tests" ;;
|
||||
debug)
|
||||
flags="--enable-debug-options --enable-tests" ;;
|
||||
icc)
|
||||
flags="CC=icc64 CXX=icpc64 --disable-user-flags --enable-tests" ;;
|
||||
win32)
|
||||
flags="CC=i386-pc-mingw32-gcc CXX=i386-pc-mingw32-g++ \
|
||||
PKG_CONFIG_PATH=/cross/w32/target/lib/pkgconfig PKG_CONFIG_LIBDIR=\"\" \
|
||||
PATH=\"/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH\" \
|
||||
--with-windows-gtk-name=gtk2-runtime-2.16.6-2010-05-12-ash --disable-user-flags \
|
||||
--enable-optimize-options --enable-tests --build=i686-linux --host=i386-pc-mingw32" ;;
|
||||
win32-debug)
|
||||
flags="CC=i386-pc-mingw32-gcc CXX=i386-pc-mingw32-g++ \
|
||||
PKG_CONFIG_PATH=/cross/w32/target/lib/pkgconfig PKG_CONFIG_LIBDIR=\"\" \
|
||||
PATH=\"/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH\" \
|
||||
--disable-user-flags --enable-debug-options --enable-tests --build=i686-linux --host=i386-pc-mingw32" ;;
|
||||
win64-debug)
|
||||
flags="CC=x86_64-pc-mingw32-gcc CXX=x86_64-pc-mingw32-g++
|
||||
PKG_CONFIG_PATH=/cross/w64/target/lib/pkgconfig \
|
||||
PKG_CONFIG_LIBDIR=\"\" PATH=\"/cross/w64/gcc-bin:/cross/w64/target/bin:$PATH\" \
|
||||
--disable-user-flags --enable-optimize-options --enable-tests --build=i686-linux \
|
||||
--host=x86_64-pc-mingw32" ;;
|
||||
sun)
|
||||
flags="CC=suncc CXX=sunCC CFLAGS=\"-errwarn=%all -I/opt/sun/target64/include\" \
|
||||
CXXFLAGS=\"-I/opt/sun/target64/include\" PATH=\"/opt/sun/sunstudio/bin:$PATH\" \
|
||||
LDFLAGS=\"-R/opt/sun/target64/lib64 -L/opt/sun/target64/lib64\" \
|
||||
PKG_CONFIG_PATH=\"/opt/sun/target64/lib64/pkgconfig:/usr/lib64/pkgconfig\" \
|
||||
PKG_CONFIG_LIBDIR=\"\" --enable-tests" ;;
|
||||
portland)
|
||||
flags="CC=pgcc CXX=pgCC LDFLAGS=\"-s\" CFLAGS=\"-Minform=warn -Bstatic_pgi\" \
|
||||
CXXFLAGS=\"-Minform=warn -Bstatic_pgi -noswitcherror -define_macro=HZ_NO_COMPILER_AUTOINCLUDE\" \
|
||||
--enable-tests" ;;
|
||||
|
||||
open64)
|
||||
flags="CC=/opt/open64/bin/opencc CXX=/opt/open64/bin/openCC CXXFLAGS=\"-Wall\" \
|
||||
--enable-tests" ;;
|
||||
esac
|
||||
|
||||
|
||||
echo "Running:"
|
||||
echo $configure_script $flags;
|
||||
|
||||
$configure_script $flags
|
||||
|
||||
|
||||
exit $?
|
||||
+158
-29
@@ -1,5 +1,5 @@
|
||||
|
||||
AC_INIT([GSmartControl], [0.8.0rc4], [], [gsmartcontrol])
|
||||
AC_INIT([GSmartControl],[0.8.6],[],[gsmartcontrol])
|
||||
|
||||
AC_CONFIG_SRCDIR([configure.ac])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -27,9 +27,18 @@ AC_PROG_CXX
|
||||
#AC_LANG([C])
|
||||
AC_LANG([C++])
|
||||
|
||||
# to be able to generate static libs
|
||||
# Needed for generating static libs
|
||||
AC_CHECK_TOOL(RANLIB, ranlib)
|
||||
|
||||
# Win32 resource file compilation
|
||||
AC_CHECK_TOOL(WINDRES, windres)
|
||||
|
||||
# Win32 external dll stripping (already detected by autoconf)
|
||||
# AC_CHECK_TOOL(STRIP, strip)
|
||||
|
||||
# Defines LN_S, needed for man page installation.
|
||||
AC_PROG_LN_S
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
@@ -46,6 +55,7 @@ AX_COMPILER_VENDOR
|
||||
# (also define automake conditionals).
|
||||
APP_DETECT_OS_KERNEL([target], [CONFIG_KERNEL_])
|
||||
APP_DETECT_OS_ENV([target], [CONFIG_OS_ENV_])
|
||||
APP_DETECT_OS_KERNEL([build], [CONFIG_HOST_KERNEL_])
|
||||
|
||||
# Detect common (warning, debug, optimize) compiler flags and
|
||||
# export them to C(XX)FLAGS, LDFLAGS.
|
||||
@@ -54,7 +64,13 @@ APP_DETECT_OS_ENV([target], [CONFIG_OS_ENV_])
|
||||
APP_COMPILER_OPTIONS([])
|
||||
|
||||
# Thread support for known configurations.
|
||||
APP_GET_MT_FLAGS([])
|
||||
# Sun compiler (at least on linux) has some runtime issues with stringstream
|
||||
# unless we use the thread flags. Also, Linux-based gdb fails to debug
|
||||
# a gcc-compiled binary for some reason.
|
||||
# Do this for all systems except mingw.
|
||||
if test "$app_cv_target_os_env" != "mingw32" && test "$app_cv_target_os_env" != "mingw64"; then
|
||||
APP_GET_MT_FLAGS([])
|
||||
fi
|
||||
|
||||
# Enable _GNU_SOURCE, etc...
|
||||
APP_USE_SYSTEM_EXTENSIONS([])
|
||||
@@ -98,7 +114,7 @@ AX_CXX_GCC_ABI_DEMANGLE
|
||||
AC_CXX_VERBOSE_TERMINATE_HANDLER
|
||||
|
||||
# detect __func__ support (defines HAVE_CXX___func__)
|
||||
APP_CXX___FUNC__
|
||||
APP_CXX___func__
|
||||
|
||||
# detect __FUNCTION__ support (defines HAVE_CXX___FUNCTION__)
|
||||
APP_CXX___FUNCTION__
|
||||
@@ -118,7 +134,8 @@ AC_CHECK_FUNCS([strtoll _strtoi64], [break])
|
||||
# but let's ignore it. Note: They may be supported by system libc,
|
||||
# but not enabled by default (e.g. by glibc feature macros). In that case,
|
||||
# defining them still leads to undefined symbols at link time, so we don't do it.
|
||||
# Header check is the best way to determine availability:
|
||||
# Header check is the best way to determine availability.
|
||||
# This defines HAVE_DECL_<symbol> to 1 or 0.
|
||||
AC_CHECK_DECLS([strtof, strtold], [], [], [[#include <stdlib.h>]])
|
||||
# link check only:
|
||||
# AC_CHECK_FUNCS([strtof strtold])
|
||||
@@ -152,23 +169,37 @@ AM_CONDITIONAL([ENABLE_TESTS], [test "$with_tests" = "yes"])
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
AC_ARG_ENABLE(abort-if-no-gtkmm, AS_HELP_STRING([--disable-abort-if-no-gtkmm],
|
||||
[disable abort if no gtkmm is found (default: configure aborts when gtkmm is not found)]),
|
||||
[app_cv_abort_if_no_gtkmm=${enableval}], [app_cv_abort_if_no_gtkmm=yes])
|
||||
|
||||
AC_MSG_NOTICE([Abort if no gtkmm is found: $app_cv_abort_if_no_gtkmm])
|
||||
|
||||
# iconview is available since 2.6.0. gthread is not enabled by default.
|
||||
pkg_modules="gtkmm-2.4 >= 2.6.0 gthread-2.0 >= 2.0"
|
||||
pkg_modules="gtkmm-2.4 >= 2.6.0" # gthread-2.0 >= 2.0
|
||||
|
||||
# define ENABLE_GLIB and friends if it's found.
|
||||
gtkmm_found="no"
|
||||
|
||||
PKG_CHECK_MODULES([GTKMM], [$pkg_modules], [
|
||||
AC_DEFINE([ENABLE_GLIB], [1], [Whether GLib is installed])
|
||||
AC_DEFINE([ENABLE_GLIBMM], [1], [Whether GLibmm is installed])
|
||||
gtkmm_found="yes"
|
||||
], [
|
||||
PKG_CHECK_MODULES([GTKMM], [$pkg_modules],
|
||||
[gtkmm_found="yes"], [gtkmm_found="no"])
|
||||
|
||||
if test "x$gtkmm_found" = "xyes"; then
|
||||
AC_DEFINE([ENABLE_GLIB], [1], [Defined to 1 if GLib is installed, 0 otherwise])
|
||||
AC_DEFINE([ENABLE_GLIBMM], [1], [Defined to 1 if glibmm is installed, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE([ENABLE_GLIB], [0], [Defined to 1 if GLib is installed, 0 otherwise])
|
||||
AC_DEFINE([ENABLE_GLIBMM], [0], [Defined to 1 if glibmm is installed, 0 otherwise])
|
||||
fi
|
||||
|
||||
if test "x$gtkmm_found" = "xno"; then
|
||||
if test "x$app_cv_abort_if_no_gtkmm" = "xno"; then
|
||||
AC_MSG_WARN([$GTKMM_PKG_ERRORS])
|
||||
AC_MSG_WARN([The program will be unable to compile fully.])
|
||||
])
|
||||
|
||||
# use this instead of the above one to enable abort-on-not-found behaviour.
|
||||
# PKG_CHECK_MODULES([GTKMM], [$pkg_modules])
|
||||
else
|
||||
AC_MSG_ERROR([$GTKMM_PKG_ERRORS])
|
||||
fi
|
||||
fi
|
||||
|
||||
# GTK flags must be prepended, or glib_config.h conflict between
|
||||
# gtk 2.x and 1.2 may occur.
|
||||
@@ -201,7 +232,7 @@ PCRE_LIBS="";
|
||||
PKG_CHECK_MODULES(PCRE, [libpcre], [pcre_found=yes], [pcre_found=no])
|
||||
|
||||
# if not found, try pcre-config (solaris had it but not pkg-config).
|
||||
if test "$pcre_found" = "no"; then
|
||||
if test "x$pcre_found" = "xno"; then
|
||||
AC_PATH_PROG(pcre_config_binary, [pcre-config])
|
||||
if test "x$pcre_config_binary" != "x"; then
|
||||
PCRE_CFLAGS="`pcre-config --cflags`"
|
||||
@@ -222,7 +253,101 @@ LIBS="$LIBS $PCRE_LIBS"
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Test stuff here...
|
||||
# <nothing>
|
||||
|
||||
#SDL_VERSION=1.2.0
|
||||
#AM_PATH_SDL($SDL_VERSION, :,
|
||||
# AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]) )
|
||||
#CFLAGS="$CFLAGS $SDL_CFLAGS"
|
||||
#CXXFLAGS="$CXXFLAGS $SDL_CFLAGS "
|
||||
#LIBS="$LIBS $SDL_LIBS"
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Win32 distribution support (NSIS, zip)
|
||||
|
||||
AC_ARG_WITH([nsis], [AS_HELP_STRING([--with-nsis=<location>|auto],
|
||||
[specify makensis.exe location to support making NSIS packages]
|
||||
[ (default: "C:\Program Files\NSIS\makensis.exe" for windows, ]
|
||||
["~/.wine/drive_c/Program Files/NSIS/Unicode/makensis.exe" for others)])],
|
||||
[with_nsis=${withval}], [with_nsis=auto])
|
||||
|
||||
AC_ARG_ENABLE([nsis-wine], [AS_HELP_STRING([--enable-nsis-wine=yes|no|auto],
|
||||
[use wine to run makensis.exe when making NSIS packages (default: auto, which is no for windows, yes for others)])],
|
||||
[with_nsis_wine=${enableval}], [with_nsis_wine=yes])
|
||||
|
||||
AC_ARG_WITH([windows-bindir], [AS_HELP_STRING([--with-windows-bindir],
|
||||
[specify location of Windows dlls and executables when making Windows packages (default: /cross/w32/target/bin)])],
|
||||
[with_windows_bindir=${withval}], [with_windows_bindir=auto])
|
||||
|
||||
AC_ARG_WITH([windows-gtk-name], [AS_HELP_STRING([--with-windows-gtk-name],
|
||||
[specify name of Windows GTK+ runtime (installer and unpacked directory) when making Windows packages. It will be looked in windows-bindir.])],
|
||||
[with_windows_gtk_name=${withval}], [with_windows_gtk_name=])
|
||||
|
||||
if test "x$with_nsis" = "xauto" || test "x$with_nsis" = "x"; then
|
||||
# if building on windows, use native paths
|
||||
if test "x$app_cv_build_os_kernel" = "xwindows32" || test "x$app_cv_build_os_kernel" = "xwindows64"; then
|
||||
with_nsis="\"C:\\Program Files\\NSIS\\makensis.exe\"";
|
||||
else
|
||||
with_nsis="~/\".wine/drive_c/Program Files/NSIS/Unicode/makensis.exe\"";
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$with_nsis_wine" = "xauto"; then
|
||||
# if not building on windows, use wine
|
||||
if test "x$app_cv_build_os_kernel" = "xwindows32" || test "x$app_cv_build_os_kernel" = "xwindows64"; then
|
||||
with_nsis_wine="no";
|
||||
else
|
||||
with_nsis_wine="yes";
|
||||
fi
|
||||
fi
|
||||
|
||||
NSIS_EXEC="$with_nsis";
|
||||
if test "x$with_nsis_wine" != "xno"; then
|
||||
NSIS_EXEC="wine $with_nsis";
|
||||
fi
|
||||
|
||||
if test "x$with_windows_bindir" = "xauto" || test "x$with_windows_bindir" = "x"; then
|
||||
with_windows_bindir="/cross/w32/target/bin"
|
||||
fi
|
||||
WINDOWS_BINDIR="$with_windows_bindir";
|
||||
|
||||
GTK_INSTALLER_NAME="$with_windows_gtk_name";
|
||||
|
||||
AC_SUBST(NSIS_EXEC)
|
||||
AC_SUBST(WINDOWS_BINDIR)
|
||||
AC_SUBST(GTK_INSTALLER_NAME)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Win32 security manifest support
|
||||
|
||||
WINDOWS_ARCH=""
|
||||
if test "x$app_cv_target_os_kernel" = "xwindows32"; then
|
||||
WINDOWS_ARCH="x86"
|
||||
elif test "x$app_cv_target_os_kernel" = "xwindows64"; then
|
||||
WINDOWS_ARCH="amd64"
|
||||
fi
|
||||
|
||||
AC_SUBST(WINDOWS_ARCH)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
RES_FILES="src/res/gsc_about_dialog.glade \
|
||||
src/res/gsc_add_device_window.glade \
|
||||
src/res/gsc_executor_log_window.glade \
|
||||
src/res/gsc_help_window.glade \
|
||||
src/res/gsc_info_window.glade \
|
||||
@@ -309,7 +434,8 @@ _AM_SUBST_NOTMAKE([RES_TARGETS])
|
||||
|
||||
ADDITIONAL_FLAGS="-DPACKAGE_PKGDATA_DIR=\"\\\"\$(pkgdatadir)\\\"\" \
|
||||
-DPACKAGE_SYSCONF_DIR=\"\\\"\$(sysconfdir)\\\"\" \
|
||||
-DTOP_SRC_DIR=\"\\\"\$(top_srcdir)\\\"\""
|
||||
-DTOP_SRC_DIR=\"\\\"\$(top_srcdir)\\\"\" \
|
||||
-DHZ_USE_GLOBAL_MACROS=1"
|
||||
|
||||
#CFLAGS="$CFLAGS $ADDITIONAL_FLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $ADDITIONAL_FLAGS"
|
||||
@@ -322,16 +448,16 @@ CXXFLAGS="$CXXFLAGS $ADDITIONAL_FLAGS"
|
||||
# Add pcrecpp too, because its files use #<file> on each other.
|
||||
ADDITIONAL_INCLUDES="-I\$(top_builddir) -I\$(top_srcdir)/src -I\$(top_srcdir)/src/pcrecpp"
|
||||
|
||||
# -include works with gcc, intel and pathscale, but doesn't work with sun and pgi.
|
||||
# -include works with gcc, intel, pathscale and sunstudio since 12u1, but doesn't work
|
||||
# with pgi and older sunstudio (the one in solaris10, for example).
|
||||
# Note: some gcc-frontend-based compilers may have to be added here
|
||||
# (e.g. gccfss (gcc frontend / sun backend), etc...).
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel" \
|
||||
|| test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
# This auto-includes this file when compiling any file. Benefits include pch support.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -include global_macros.h"
|
||||
else # sun, pgi, others...
|
||||
# This forces the file to be included manually.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -DHZ_NO_COMPILER_AUTOINCLUDE"
|
||||
# We use -include only when using pch.
|
||||
if test "x$app_cv_compiler_gcc_pch" = "xyes"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel" || test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
# This auto-includes this file when compiling any file. Benefits include pch support.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -include global_macros.h"
|
||||
fi
|
||||
fi
|
||||
|
||||
# our flags must be before all the others
|
||||
@@ -402,12 +528,14 @@ AC_SUBST(AUTODIRS)
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
AC_CONFIG_FILES([ data/gsmartcontrol_gnome.desktop data/gsmartcontrol_kde.desktop \
|
||||
data/gsmartcontrol_other.desktop \
|
||||
AC_CONFIG_FILES([ data/gsmartcontrol.desktop \
|
||||
data/nsis/distribution.txt data/nsis/distribution-nogtk.txt data/nsis/gsmartcontrol.nsi \
|
||||
debian.dist/changelog \
|
||||
src/gsc_winres.rc src/gsmartcontrol.exe.manifest \
|
||||
gsmartcontrol.spec version compilation_flags ])
|
||||
|
||||
|
||||
AC_CONFIG_FILES([data/gsmartcontrol_root.sh], [chmod +x data/gsmartcontrol_root.sh])
|
||||
AC_CONFIG_FILES([data/gsmartcontrol-root], [chmod +x data/gsmartcontrol-root])
|
||||
|
||||
|
||||
# these are all the makefiles to generate
|
||||
@@ -415,7 +543,8 @@ AC_CONFIG_FILES([data/gsmartcontrol_root.sh], [chmod +x data/gsmartcontrol_root.
|
||||
AC_CONFIG_FILES([Makefile src/Makefile src/applib/Makefile src/res/Makefile src/hz/Makefile \
|
||||
src/libdebug/Makefile src/pcrecpp/Makefile src/rconfig/Makefile src/rmn/Makefile \
|
||||
data/Makefile data/16/Makefile data/22/Makefile data/24/Makefile data/32/Makefile \
|
||||
data/48/Makefile data/64/Makefile data/128/Makefile])
|
||||
data/48/Makefile data/64/Makefile data/128/Makefile data/256/Makefile data/nsis/Makefile \
|
||||
debian.dist/Makefile])
|
||||
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
This directory contains scripts and an example crontab to allow GSmartControl
|
||||
to read smartctl data from cron-generated files. This allows users to read
|
||||
somewhat recent smartctl information without having to run GSmartControl as
|
||||
root.
|
||||
|
||||
Put the scripts into /usr/local/bin, run GSmartControl and set smartctl path
|
||||
to "/usr/local/bin/smartctl_subst.sh" (without quotes). An example crontab
|
||||
runs cron_gather_smart.sh script every 10 minutes, storing its output to
|
||||
"/var/run/smart-$devname". The smartctl_subst.sh script prints the contents of
|
||||
this file instead of running smartctl, thus eliminating the need to run
|
||||
GSmartControl as root when reading SMART values.
|
||||
|
||||
Note: These scripts provide read-only capabilities only, they don't allow
|
||||
changing SMART settings or running self-tests.
|
||||
|
||||
Contributed by Alex Butcher <alex dot butcher 'at' assursys.co.uk>.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 2010 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_unlicense.txt file
|
||||
############################################################################
|
||||
|
||||
device="$1";
|
||||
|
||||
if [ "$device" = "" ]; then
|
||||
echo "Usage: $0 <device>"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
dev_base="`basename \"$device\"`"
|
||||
out_file=/var/run/smart-"$dev_base"
|
||||
|
||||
# Change the path to smartctl if necessary.
|
||||
smartctl -a "$device" 2>&1 > "$out_file"
|
||||
|
||||
chmod 644 "$out_file"
|
||||
@@ -0,0 +1,2 @@
|
||||
*/10 * * * * root /usr/local/bin/cron-smart.sh /dev/sda
|
||||
*/10 * * * * root /usr/local/bin/cron-smart.sh /dev/sdb
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 2010 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_unlicense.txt file
|
||||
############################################################################
|
||||
|
||||
if [ "$1" = "-V" ]; then
|
||||
smartctl -V 2>&1
|
||||
exit
|
||||
fi
|
||||
|
||||
while [ $# -ge 1 ]; do
|
||||
device="$1"
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$device" = "" ]; then
|
||||
echo "Usage: $0 <device>"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
dev_base="`basename \"$device\"`"
|
||||
out_file=/var/run/smart-"$dev_base"
|
||||
|
||||
cat "$out_file"
|
||||
@@ -0,0 +1,4 @@
|
||||
appicondir = $(datadir)/icons/hicolor/256x256/apps
|
||||
appicon_DATA = gsmartcontrol.png
|
||||
|
||||
EXTRA_DIST = $(appicon_DATA)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
+27
-10
@@ -1,9 +1,23 @@
|
||||
SUBDIRS = 16 22 24 32 48 64 128
|
||||
|
||||
SUBDIRS = 16 22 24 32 48 64 128 256 nsis
|
||||
|
||||
|
||||
dist_man_MANS = gsmartcontrol.1
|
||||
|
||||
install-extra-mans:
|
||||
cd $(DESTDIR)$(mandir)/man1 && $(LN_S) -f gsmartcontrol.1 gsmartcontrol-root.1
|
||||
|
||||
uninstall-extra-mans:
|
||||
cd $(DESTDIR)$(mandir)/man1 && rm -f gsmartcontrol-root.1
|
||||
|
||||
|
||||
# This command is needed if installing with make install (the cache
|
||||
# file is ignored for rpms).
|
||||
gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
|
||||
|
||||
install-data-hook: update-icon-cache
|
||||
uninstall-hook: update-icon-cache
|
||||
install-data-hook: install-extra-mans update-icon-cache
|
||||
uninstall-hook: uninstall-extra-mans update-icon-cache
|
||||
|
||||
update-icon-cache:
|
||||
@-if test -z "$(DESTDIR)"; then \
|
||||
echo "Updating GTK icon cache."; \
|
||||
@@ -14,7 +28,7 @@ update-icon-cache:
|
||||
fi
|
||||
|
||||
|
||||
# installs to /usr/share/appname
|
||||
# Application data, installs to /usr/share/appname
|
||||
appdatadir = $(pkgdatadir)
|
||||
appdata_DATA = icon_cddvd.png icon_hdd.png
|
||||
|
||||
@@ -22,19 +36,22 @@ appdata_DATA = icon_cddvd.png icon_hdd.png
|
||||
# pkgdatadir = $(datadir)/gsmartcontrol
|
||||
# pkgdata_DATA =
|
||||
|
||||
# Desktop files
|
||||
desktopdir = $(datadir)/applications
|
||||
desktop_DATA = gsmartcontrol_gnome.desktop gsmartcontrol_kde.desktop \
|
||||
gsmartcontrol_other.desktop
|
||||
desktop_DATA = gsmartcontrol.desktop
|
||||
|
||||
|
||||
# Same as 48/gsmartcontrol.png
|
||||
# Application pixmap (fallback icon for desktop files).
|
||||
# Same as 48/gsmartcontrol.png.
|
||||
# Also, xpm for debian menu, 32x32.
|
||||
pixmapsdir = $(datadir)/pixmaps
|
||||
pixmaps_DATA = 48/gsmartcontrol.png
|
||||
pixmaps_DATA = 48/gsmartcontrol.png gsmartcontrol.xpm
|
||||
|
||||
|
||||
EXTRA_DIST = $(appdata_DATA) $(pixmaps_DATA)
|
||||
# Put everything inside the distribution
|
||||
EXTRA_DIST = $(appdata_DATA) gsmartcontrol.ico gsmartcontrol.xpm
|
||||
|
||||
|
||||
bin_SCRIPTS = gsmartcontrol_root.sh
|
||||
bin_SCRIPTS = gsmartcontrol-root
|
||||
CLEANFILES = $(bin_SCRIPTS)
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
# Run gsmartcontrol with root, asking for root password first.
|
||||
# export GSMARTCONTROL_SU to override a su command (e.g. "kdesu -c").
|
||||
|
||||
EXEC_BIN="@prefix@/bin/gsmartcontrol";
|
||||
prog_name="gsmartcontrol"
|
||||
|
||||
DESKTOP="$1";
|
||||
|
||||
# This works for --help too
|
||||
if [ "$DESKTOP" = "" ]; then
|
||||
DESKTOP="auto"; # default
|
||||
|
||||
elif [ "$DESKTOP" != "auto" ] && [ "$DESKTOP" != "kde" ] && \
|
||||
[ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
|
||||
echo "Usage: $0 [<auto|kde|gnome|other> [<${prog_name}_options>] ]";
|
||||
exit 1;
|
||||
fi
|
||||
shift; # remove $1
|
||||
|
||||
|
||||
# Auto-detect current desktop if auto was specified.
|
||||
if [ "$DESKTOP" = "auto" ]; then
|
||||
# KDE_SESSION_UID is present on kde3 and kde4.
|
||||
# Note that it may be empty (but still set)
|
||||
if [ "${KDE_SESSION_UID+set}" = "set" ]; then
|
||||
DESKTOP="kde";
|
||||
# same with gnome
|
||||
elif [ "${GNOME_DESKTOP_SESSION_ID+set}" = "set" ]; then
|
||||
DESKTOP="gnome";
|
||||
else
|
||||
DESKTOP="other";
|
||||
fi
|
||||
fi
|
||||
|
||||
# echo $DESKTOP;
|
||||
|
||||
|
||||
# They're basically the same, only the order is different.
|
||||
# sux requires xterm to ask for the password.
|
||||
# xdg-su is basically like this script, except worse :)
|
||||
# su-to-root is a debian/ubuntu official method (although gksu is available).
|
||||
gnome_sus="su-to-root gnomesu gksu kdesu beesu xdg-su sux";
|
||||
kde_sus="su-to-root kdesu gnomesu gksu beesu xdg-su sux";
|
||||
other_sus="$gnome_sus";
|
||||
|
||||
|
||||
candidates="";
|
||||
found_su=""
|
||||
|
||||
if [ "$DESKTOP" = "gnome" ]; then
|
||||
candidates="$gnome_sus";
|
||||
elif [ "$DESKTOP" = "kde" ]; then
|
||||
candidates="$kde_sus";
|
||||
elif [ "$DESKTOP" = "other" ]; then
|
||||
candidates="$other_sus";
|
||||
fi
|
||||
|
||||
if [ "$GSMARTCONTROL_SU" = "" ]; then
|
||||
for subin in $candidates; do
|
||||
which $subin &>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
found_su="$subin";
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found_su" = "" ]; then
|
||||
xmessage "Error launching ${prog_name}: No suitable su mechanism found.
|
||||
Try installing kdesu, gnomesu, gksu, beesu or sux first.";
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# gnomesu and gksu (but not kdesu, not sure about others) fail to adopt
|
||||
# root's PATH. Since the user's PATH may not contain /usr/sbin (with smartctl)
|
||||
# on some distributions (e.g. mandriva), add it manually. We also add
|
||||
# /usr/local/sbin, since that's the default location of custom-compiled smartctl.
|
||||
# Add these directories _before_ existing PATH, so that the user is not
|
||||
# tricked into running it from some other path (we're running as root with
|
||||
# the user's env after all).
|
||||
# Note that beesu won't show a GUI login box if /usr/sbin is before /usr/bin,
|
||||
# so add it first as well.
|
||||
EXTRA_PATHS="/usr/bin:/usr/sbin:/usr/local/sbin";
|
||||
export PATH="$EXTRA_PATHS:$PATH"
|
||||
|
||||
|
||||
# echo $found_su;
|
||||
|
||||
# Examples:
|
||||
# gnomesu -c 'gsmartcontrol --no-scan'
|
||||
# kdesu -c 'gsmartcontrol --no-scan'
|
||||
# beesu -P 'gsmartcontrol --no-scan'
|
||||
# su-to-root -X -c 'gsmartcontrol --no-scan'
|
||||
# xterm -e sux -c 'gsmartcontrol --no-scan' # sux asks for password in a terminal
|
||||
|
||||
full_cmd="";
|
||||
|
||||
if [ "$GSMARTCONTROL_SU" != "" ]; then
|
||||
full_cmd="$GSMARTCONTROL_SU '$EXEC_BIN $@'";
|
||||
|
||||
elif [ "$found_su" = "sux" ]; then
|
||||
full_cmd="xterm -e sux -c '$EXEC_BIN $@'";
|
||||
|
||||
elif [ "$found_su" = "gksu" ]; then
|
||||
full_cmd="$found_su '$EXEC_BIN $@'";
|
||||
|
||||
elif [ "$found_su" = "beesu" ]; then
|
||||
full_cmd="$found_su -P '$EXEC_BIN $@'";
|
||||
|
||||
elif [ "$found_su" = "su-to-root" ]; then
|
||||
full_cmd="$found_su -X -c '$EXEC_BIN $@'";
|
||||
|
||||
else # gnomesu, kdesu, xdg-su
|
||||
full_cmd="$found_su -c '$EXEC_BIN $@'";
|
||||
fi
|
||||
|
||||
|
||||
#echo $full_cmd
|
||||
eval $full_cmd
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
.TH GSmartControl "1" "" "gsmartcontrol " "User Commands"
|
||||
.SH NAME
|
||||
GSmartControl \- Hard disk drive health inspection tool
|
||||
.SH SYNOPSIS
|
||||
\fBgsmartcontrol\fP [OPTIONS]
|
||||
|
||||
\fBgsmartcontrol\-root\fP [\fI<desktop>\fP [OPTIONS]]
|
||||
.SH DESCRIPTION
|
||||
\fBGSmartControl\fP is a graphical user interface for smartctl (from
|
||||
smartmontools), which is a tool for querying and controlling SMART
|
||||
(Self-Monitoring, Analysis, and Reporting Technology) data on modern hard disk
|
||||
drives. It allows you to inspect the drive's SMART data to determine its
|
||||
health, as well as run various tests on it.
|
||||
.PP
|
||||
This manual page documents briefly the \fBgsmartcontrol\fP and
|
||||
\fBgsmartcontrol\-root\fP commands.
|
||||
.PP
|
||||
\fBgsmartcontrol\-root\fP command launches \fBgsmartcontrol\fP with
|
||||
administrative privileges. The \fIdesktop\fP argument specifies which desktop
|
||||
is currently running, for automatic selection of native su mechanism. Valid
|
||||
values for \fIdesktop\fP are \fBauto\fP, \fBkde\fP, \fBgnome\fP, \fBother\fP.
|
||||
|
||||
.SH OPTIONS
|
||||
.SS "Help Options:"
|
||||
.TP
|
||||
\fB\-?\fP, \fB\-\-help\fP
|
||||
Show help options
|
||||
.TP
|
||||
\fB\-\-help\-all\fP
|
||||
Show all help options
|
||||
.TP
|
||||
\fB\-\-help\-gtk\fP
|
||||
Show GTK+ options
|
||||
.TP
|
||||
\fB\-\-help\-debug\fR
|
||||
Show logging options
|
||||
.SS "Application Options:"
|
||||
.TP
|
||||
\fB\-l\fP, \fB\-\-no\-locale\fP
|
||||
Disable locale
|
||||
.TP
|
||||
\fB\-V\fP, \fB\-\-version\fP
|
||||
Display version information
|
||||
.TP
|
||||
\fB\-\-no\-scan\fP
|
||||
Don't scan devices on startup
|
||||
.TP
|
||||
\fB\-\-no\-hide\-tabs\fP
|
||||
Don't hide non\-identity tabs when SMART is disabled. Useful for debugging.
|
||||
.TP
|
||||
\fB\-\-add\-virtual\fP
|
||||
Load smartctl data from file, creating a virtual drive
|
||||
.TP
|
||||
\fB\-\-add\-device\fP
|
||||
Add this device to device list. Useful with \fB\-\-no\-scan\fP to list certain drives only.
|
||||
.TP
|
||||
\fB\-\-display\fP=\fIDISPLAY\fP
|
||||
X display to use
|
||||
.TP
|
||||
\fB\-v\fP, \fB\-\-verbose\fP
|
||||
Enable verbose logging; same as \fB\-\-verbosity\-level\fP 5
|
||||
.TP
|
||||
\fB\-q\fP, \fB\-\-quiet\fP
|
||||
Disable logging; same as \fB\-\-verbosity\-level\fP 0
|
||||
.TP
|
||||
\fB\-b\fP, \fB\-\-verbosity\-level\fP
|
||||
Set verbosity level [0\-5]
|
||||
.PP
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2008 \- 2009 Alexander Shaduri <ashaduri \'at\' gmail.com>
|
||||
.PP
|
||||
.SH AUTHOR
|
||||
This manual page was originally written by Giuseppe Iuculano
|
||||
<giuseppe@iuculano.it>, for the Debian project.
|
||||
@@ -1,8 +1,5 @@
|
||||
[Desktop Entry]
|
||||
|
||||
# Desktop file for kde only.
|
||||
OnlyShowIn=KDE;
|
||||
|
||||
# desktop file version
|
||||
Version=1.0
|
||||
Type=Application
|
||||
@@ -25,7 +22,8 @@ Icon=gsmartcontrol
|
||||
#X-KDE-SubstituteUID=true
|
||||
#X-KDE-RootOnly=true
|
||||
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" kde
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol-root"
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,394 @@
|
||||
/* XPM */
|
||||
static char * gsmartcontrol_xpm[] = {
|
||||
"32 32 359 2",
|
||||
" c None",
|
||||
". c #ABAAAA",
|
||||
"+ c #CCCCCC",
|
||||
"@ c #C5C4C4",
|
||||
"# c #C2C1C1",
|
||||
"$ c #D2D1D1",
|
||||
"% c #C8C7C7",
|
||||
"& c #C8C7C8",
|
||||
"* c #C9C8C8",
|
||||
"= c #CAC8C9",
|
||||
"- c #CAC9C9",
|
||||
"; c #C8C6C7",
|
||||
"> c #C7C6C6",
|
||||
", c #CFCDCE",
|
||||
"' c #D1D0D0",
|
||||
") c #C6C5C6",
|
||||
"! c #CFCECE",
|
||||
"~ c #B9B7B7",
|
||||
"{ c #D4D4D4",
|
||||
"] c #DCDBDC",
|
||||
"^ c #D8D7D7",
|
||||
"/ c #D6D5D5",
|
||||
"( c #D6D5D6",
|
||||
"_ c #D7D6D6",
|
||||
": c #D9D8D8",
|
||||
"< c #DBDADB",
|
||||
"[ c #DAD9DA",
|
||||
"} c #D7D7D7",
|
||||
"| c #D6D6D6",
|
||||
"1 c #DAD9D9",
|
||||
"2 c #E2E1E1",
|
||||
"3 c #B0AFAF",
|
||||
"4 c #D3D2D2",
|
||||
"5 c #CDCCCC",
|
||||
"6 c #CDCDCD",
|
||||
"7 c #CECDCD",
|
||||
"8 c #CECECE",
|
||||
"9 c #CFCFCF",
|
||||
"0 c #D0CFCF",
|
||||
"a c #C0BFBF",
|
||||
"b c #9C9A9B",
|
||||
"c c #6E6B6B",
|
||||
"d c #807E7F",
|
||||
"e c #C8C8C8",
|
||||
"f c #CAC9CA",
|
||||
"g c #CACACA",
|
||||
"h c #CBCACA",
|
||||
"i c #CCCBCB",
|
||||
"j c #CCCBCC",
|
||||
"k c #D0CECF",
|
||||
"l c #C3C2C2",
|
||||
"m c #A09E9F",
|
||||
"n c #B5B4B4",
|
||||
"o c #AFADAE",
|
||||
"p c #787576",
|
||||
"q c #8D8B8B",
|
||||
"r c #D4D3D3",
|
||||
"s c #C7C6C7",
|
||||
"t c #C7C7C7",
|
||||
"u c #C9C8C9",
|
||||
"v c #C9C9C9",
|
||||
"w c #CACAC9",
|
||||
"x c #BFBEBE",
|
||||
"y c #A3A1A2",
|
||||
"z c #A09D9E",
|
||||
"A c #B4B2B2",
|
||||
"B c #B6B4B4",
|
||||
"C c #827F80",
|
||||
"D c #969595",
|
||||
"E c #C4C3C3",
|
||||
"F c #C4C4C4",
|
||||
"G c #C5C5C5",
|
||||
"H c #C6C5C5",
|
||||
"I c #C6C6C6",
|
||||
"J c #C9C7C8",
|
||||
"K c #B9B7B8",
|
||||
"L c #A5A4A4",
|
||||
"M c #A4A3A3",
|
||||
"N c #A7A5A5",
|
||||
"O c #B3B1B2",
|
||||
"P c #BFBDBD",
|
||||
"Q c #8D8A8B",
|
||||
"R c #A09F9F",
|
||||
"S c #DDDCDC",
|
||||
"T c #C0C0C0",
|
||||
"U c #C3C1C2",
|
||||
"V c #C3C2C3",
|
||||
"W c #C3C3C3",
|
||||
"X c #C4C3C4",
|
||||
"Y c #B2B1B1",
|
||||
"Z c #A8A7A7",
|
||||
"` c #ABA9A9",
|
||||
" . c #CFCECF",
|
||||
".. c #C2C0C1",
|
||||
"+. c #989697",
|
||||
"@. c #A8A6A7",
|
||||
"#. c #DEDDDD",
|
||||
"$. c #DEDDDE",
|
||||
"%. c #C1C0C0",
|
||||
"&. c #C2C1C2",
|
||||
"*. c #B1B0B0",
|
||||
"=. c #ADACAC",
|
||||
"-. c #AFAEAE",
|
||||
";. c #BDBCBC",
|
||||
">. c #B3B2B2",
|
||||
",. c #B4B3B4",
|
||||
"'. c #B8B8B8",
|
||||
"). c #D5D4D4",
|
||||
"!. c #C0BFBE",
|
||||
"~. c #C1C0C1",
|
||||
"{. c #C3C1C1",
|
||||
"]. c #C4C4C3",
|
||||
"^. c #B2B0B1",
|
||||
"/. c #B3B2B3",
|
||||
"(. c #B4B3B3",
|
||||
"_. c #A1A0A0",
|
||||
":. c #B9B8B8",
|
||||
"<. c #C4C2C3",
|
||||
"[. c #BDBBBC",
|
||||
"}. c #B5B4B3",
|
||||
"|. c #B6B4B5",
|
||||
"1. c #B7B5B6",
|
||||
"2. c #B7B6B7",
|
||||
"3. c #B8B7B7",
|
||||
"4. c #B8B7B8",
|
||||
"5. c #BCBABB",
|
||||
"6. c #BBBABA",
|
||||
"7. c #BFBEBF",
|
||||
"8. c #C1C1C1",
|
||||
"9. c #C1BFC0",
|
||||
"0. c #BCBBBB",
|
||||
"a. c #BEBCBD",
|
||||
"b. c #BEBDBD",
|
||||
"c. c #9B999A",
|
||||
"d. c #9D9B9B",
|
||||
"e. c #C2C2C2",
|
||||
"f. c #D4D3D4",
|
||||
"g. c #CECDCE",
|
||||
"h. c #C7C5C5",
|
||||
"i. c #A4A2A3",
|
||||
"j. c #A19F9F",
|
||||
"k. c #C6C4C5",
|
||||
"l. c #DCDCDC",
|
||||
"m. c #D0CFD0",
|
||||
"n. c #CECCCD",
|
||||
"o. c #A2A1A1",
|
||||
"p. c #939292",
|
||||
"q. c #E1E0E0",
|
||||
"r. c #E3E3E3",
|
||||
"s. c #B3B3B3",
|
||||
"t. c #CCCACB",
|
||||
"u. c #D2D2D2",
|
||||
"v. c #D5D3D4",
|
||||
"w. c #A7A6A6",
|
||||
"x. c #959494",
|
||||
"y. c #E3E2E2",
|
||||
"z. c #DCDBDB",
|
||||
"A. c #CBC9CA",
|
||||
"B. c #E1E0E1",
|
||||
"C. c #DFDEDE",
|
||||
"D. c #CECCCC",
|
||||
"E. c #CDCCCD",
|
||||
"F. c #D2D0D0",
|
||||
"G. c #D2D0D1",
|
||||
"H. c #B5B4B5",
|
||||
"I. c #B1AFB0",
|
||||
"J. c #EDECEC",
|
||||
"K. c #D1CFCF",
|
||||
"L. c #CDCBCC",
|
||||
"M. c #D5D5D5",
|
||||
"N. c #DCDADA",
|
||||
"O. c #C5C4C5",
|
||||
"P. c #D2D1D2",
|
||||
"Q. c #D5D4D5",
|
||||
"R. c #DADADA",
|
||||
"S. c #DBDADA",
|
||||
"T. c #DDDCDD",
|
||||
"U. c #D7D6D7",
|
||||
"V. c #E8E7E7",
|
||||
"W. c #D8D8D8",
|
||||
"X. c #D8D6D6",
|
||||
"Y. c #D9D8D9",
|
||||
"Z. c #DBDBDB",
|
||||
"`. c #DDDDDD",
|
||||
" + c #474747",
|
||||
".+ c #ECEBEB",
|
||||
"++ c #F3F3F3",
|
||||
"@+ c #E4E3E3",
|
||||
"#+ c #E0DFDF",
|
||||
"$+ c #E5E5E5",
|
||||
"%+ c #EFEFEF",
|
||||
"&+ c #EBEAEB",
|
||||
"*+ c #E6E5E5",
|
||||
"=+ c #E0E0E0",
|
||||
"-+ c #E4E4E4",
|
||||
";+ c #E5E4E4",
|
||||
">+ c #ECECEC",
|
||||
",+ c #666666",
|
||||
"'+ c #585757",
|
||||
")+ c #D9D9DA",
|
||||
"!+ c #E2E2E2",
|
||||
"~+ c #E6E5E6",
|
||||
"{+ c #E1E1E1",
|
||||
"]+ c #E6E6E6",
|
||||
"^+ c #E7E7E7",
|
||||
"/+ c #898989",
|
||||
"(+ c #767575",
|
||||
"_+ c #E0DFE0",
|
||||
":+ c #E9E9E9",
|
||||
"<+ c #BDBDBD",
|
||||
"[+ c #B6B6B6",
|
||||
"}+ c #B0B0B0",
|
||||
"|+ c #ACACAC",
|
||||
"1+ c #ACABAC",
|
||||
"2+ c #A7A7A7",
|
||||
"3+ c #DFDFDF",
|
||||
"4+ c #E5E5E4",
|
||||
"5+ c #E9E8E8",
|
||||
"6+ c #E8E8E8",
|
||||
"7+ c #E3E2E3",
|
||||
"8+ c #D7D5D5",
|
||||
"9+ c #8E8D8D",
|
||||
"0+ c #807F7F",
|
||||
"a+ c #494848",
|
||||
"b+ c #5A5758",
|
||||
"c+ c #605E5F",
|
||||
"d+ c #646262",
|
||||
"e+ c #555354",
|
||||
"f+ c #1F1F1F",
|
||||
"g+ c #282626",
|
||||
"h+ c #323031",
|
||||
"i+ c #3D3C3C",
|
||||
"j+ c #494748",
|
||||
"k+ c #555353",
|
||||
"l+ c #5A5959",
|
||||
"m+ c #3E3D3D",
|
||||
"n+ c #434242",
|
||||
"o+ c #444343",
|
||||
"p+ c #414041",
|
||||
"q+ c #3E3E3E",
|
||||
"r+ c #4A4949",
|
||||
"s+ c #706D6E",
|
||||
"t+ c #6B6969",
|
||||
"u+ c #6A6869",
|
||||
"v+ c #696469",
|
||||
"w+ c #656065",
|
||||
"x+ c #595757",
|
||||
"y+ c #A5A5A5",
|
||||
"z+ c #767676",
|
||||
"A+ c #8A8888",
|
||||
"B+ c #4B4849",
|
||||
"C+ c #5C5A5A",
|
||||
"D+ c #686565",
|
||||
"E+ c #524F50",
|
||||
"F+ c #000000",
|
||||
"G+ c #090607",
|
||||
"H+ c #171415",
|
||||
"I+ c #262324",
|
||||
"J+ c #363334",
|
||||
"K+ c #454343",
|
||||
"L+ c #4A4748",
|
||||
"M+ c #212020",
|
||||
"N+ c #2A292A",
|
||||
"O+ c #2C2B2B",
|
||||
"P+ c #272626",
|
||||
"Q+ c #242424",
|
||||
"R+ c #242323",
|
||||
"S+ c #3C3B3B",
|
||||
"T+ c #726F70",
|
||||
"U+ c #6C696A",
|
||||
"V+ c #6B676A",
|
||||
"W+ c #7A916C",
|
||||
"X+ c #7B926B",
|
||||
"Y+ c #605F60",
|
||||
"Z+ c #9C9B9C",
|
||||
"`+ c #606060",
|
||||
" @ c #8F8D8D",
|
||||
".@ c #494747",
|
||||
"+@ c #595657",
|
||||
"@@ c #615E5F",
|
||||
"#@ c #656162",
|
||||
"$@ c #525050",
|
||||
"%@ c #020101",
|
||||
"&@ c #0C0A0A",
|
||||
"*@ c #1A1818",
|
||||
"=@ c #282525",
|
||||
"-@ c #454243",
|
||||
";@ c #494647",
|
||||
">@ c #2A2929",
|
||||
",@ c #393838",
|
||||
"'@ c #363536",
|
||||
")@ c #323131",
|
||||
"!@ c #2B292A",
|
||||
"~@ c #282727",
|
||||
"{@ c #444243",
|
||||
"]@ c #696666",
|
||||
"^@ c #666268",
|
||||
"/@ c #709D48",
|
||||
"(@ c #7BAD4A",
|
||||
"_@ c #68686A",
|
||||
":@ c #8F8E8F",
|
||||
"<@ c #4E4D4E",
|
||||
"[@ c #8E8C8D",
|
||||
"}@ c #484546",
|
||||
"|@ c #555253",
|
||||
"1@ c #5D595A",
|
||||
"2@ c #5F5B5C",
|
||||
"3@ c #514F50",
|
||||
"4@ c #0F0D0D",
|
||||
"5@ c #211E1F",
|
||||
"6@ c #312E2F",
|
||||
"7@ c #413D3E",
|
||||
"8@ c #222121",
|
||||
"9@ c #2E2D2D",
|
||||
"0@ c #312F30",
|
||||
"a@ c #262425",
|
||||
"b@ c #464344",
|
||||
"c@ c #696667",
|
||||
"d@ c #666263",
|
||||
"e@ c #5F5E5F",
|
||||
"f@ c #5A5B5B",
|
||||
"g@ c #797577",
|
||||
"h@ c #7A7A7A",
|
||||
"i@ c #4C4A4A",
|
||||
"j@ c #2A2728",
|
||||
"k@ c #2C292A",
|
||||
"l@ c #302D2E",
|
||||
"m@ c #312F2F",
|
||||
"n@ c #2E2C2C",
|
||||
"o@ c #100F0F",
|
||||
"p@ c #110F10",
|
||||
"q@ c #141212",
|
||||
"r@ c #1B1919",
|
||||
"s@ c #242222",
|
||||
"t@ c #2D2B2B",
|
||||
"u@ c #322F30",
|
||||
"v@ c #2F2D2D",
|
||||
"w@ c #2B2829",
|
||||
"x@ c #292728",
|
||||
"y@ c #363233",
|
||||
"z@ c #332F30",
|
||||
"A@ c #312D2F",
|
||||
"B@ c #2A2627",
|
||||
"C@ c #424040",
|
||||
"D@ c #454444",
|
||||
"E@ c #737373",
|
||||
"F@ c #828282",
|
||||
"G@ c #939293",
|
||||
"H@ c #9C9C9C",
|
||||
"I@ c #A3A3A3",
|
||||
"J@ c #A9A9A9",
|
||||
"K@ c #ADADAD",
|
||||
"L@ c #B2B2B2",
|
||||
"M@ c #B5B5B5",
|
||||
"N@ c #A4A4A4",
|
||||
"O@ c #959595",
|
||||
"P@ c #8C8C8C",
|
||||
"Q@ c #707070",
|
||||
"R@ c #FFFFFF",
|
||||
" ",
|
||||
" . + @ # $ % & * = - ; > * - - - * , ' ) ! ~ ",
|
||||
" = { ' ] ^ { / / ( _ : < [ ^ ^ } ^ | 1 2 } 3 ",
|
||||
" - 4 ' ' 5 6 6 6 7 7 8 9 ! ! 9 9 0 0 $ 5 a b c ",
|
||||
" d 4 [ * e - - f g h h h i i j + 5 5 k l m n o p ",
|
||||
" q _ r @ > > s s t % % * * u v - w 5 x y z A B C ",
|
||||
" D 1 7 l E F @ @ G H H I > > > J * K L M N O P Q ",
|
||||
" R S % T U U l V W E X F @ @ > E Y Z ` > .* ..+. ",
|
||||
" @.#.$.W %.# # # &.l l V E G T *.=.-.*.5 ;.>.,.Z ",
|
||||
" n '.).[ !.T ~.# ..{.U l ].x Y ^.>.A /.(.x ;.O _. ",
|
||||
" :.^.<.h a %.%.# # # &.U [.}.|.1.2.3.4.K K a 5.N ",
|
||||
" 6.i H 7.%.8.# &.# l * % E 9.[.5.0.[.;.a.b.;., %.c. ",
|
||||
" d.> 0 a # &.e.V V % ^ f.j g - % %.....&.l V l g.h.i. ",
|
||||
" j./ i # E E @ k.H l.g.%.# l E H <.b.; > % % % m.n.o. ",
|
||||
" p.q.7 @ ) > % % - r.) > % * * g f s.5 t.i i i u.v.w. ",
|
||||
" x.y.z.> u - g A.- B.C.D.E.! 0 7 (.6.$ ' ' F.G.).^ H. ",
|
||||
" I.7 J.K.L.7 7 ! ! m.S 1 m.- %.3.8./ ).M./ | _ : N.; ",
|
||||
" O., F.f.P.4 4 4 f.f.r / Q.4 4 ^ R.: : 1 [ S.< S T.U. ",
|
||||
" 4 V.| ).| _ W._ X.^ : Y.1 S.Z.z.] S S `.#.C.C.2 V.q. + ",
|
||||
" S..+++@+`.#+$+%+&+*+2 #+=+q.y.-+-+-+;+$+$+*+>+++Z.*+,+ ",
|
||||
" '+S.# $ >+r.m.e.# 6 )+!+~+*+@+B.=+{+-+]+]+^+]+^+j 5 y./+ ",
|
||||
" (+b.3 _+! m.#+:+q.r > <+[+}+|+3 '.b.8.> e 5 7 ! ^+j 1+2+ ",
|
||||
" x.] ! r / ^ W.R.S 3+2 y.@+4+5+6+^+~+*+;+7+#+C.#.S.8+: V ",
|
||||
" 9+0+a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+n+p+q+r+s+t+u+v+w+x+y+ ",
|
||||
" z+A+B+C+d+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+ ",
|
||||
" `+ @.@+@@@#@$@%@&@*@=@J+-@;@>@,@'@)@!@~@{@c ]@^@/@(@_@:@ ",
|
||||
" <@[@}@|@1@2@3@F+%@4@5@6@7@-@8@9@9@0@~@a@b@c@#@d@e@f@g@h@ ",
|
||||
" i@j@k@l@m@n@o@p@q@r@s@t@u@!@l@v@v@w@x@l@y@z@6@A@B@C@D@ ",
|
||||
" E@F@G@H@I@J@K@}+L@M@M@M@s.}+|+N@H@O@P@F@Q@ ",
|
||||
" R@R@R@R@R@R@R@R@R@ ",
|
||||
" ",
|
||||
" "};
|
||||
@@ -1,27 +0,0 @@
|
||||
[Desktop Entry]
|
||||
|
||||
# Desktop file for gnome only.
|
||||
OnlyShowIn=GNOME;
|
||||
|
||||
# desktop file version
|
||||
Version=1.0
|
||||
Type=Application
|
||||
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
GenericName=Hard Disk Health Inspection
|
||||
# tooltip
|
||||
Comment=Monitor and control SMART data on hard disks
|
||||
|
||||
# If it's a name only, it looks for "name.[png|xpm]" file in
|
||||
# $XDG_DATA_DIRS/icons and /usr/share/pixmaps.
|
||||
# An absolute file path is also supported.
|
||||
Icon=gsmartcontrol
|
||||
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" gnome
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
@@ -1,27 +0,0 @@
|
||||
[Desktop Entry]
|
||||
|
||||
# Desktop file for non-gnome and non-kde only.
|
||||
NotShowIn=GNOME;KDE;
|
||||
|
||||
# desktop file version
|
||||
Version=1.0
|
||||
Type=Application
|
||||
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
GenericName=Hard Disk Health Inspection
|
||||
# tooltip
|
||||
Comment=Monitor and control SMART data on hard disks
|
||||
|
||||
# If it's a name only, it looks for "name.[png|xpm]" file in
|
||||
# $XDG_DATA_DIRS/icons and /usr/share/pixmaps.
|
||||
# An absolute file path is also supported.
|
||||
Icon=gsmartcontrol
|
||||
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" other
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
# Run gsmartcontrol with root, asking for root password first.
|
||||
|
||||
EXEC_BIN="@prefix@/bin/gsmartcontrol";
|
||||
prog_name="gsmartcontrol"
|
||||
|
||||
DESKTOP="$1";
|
||||
|
||||
# This works for --help too
|
||||
if [ "$DESKTOP" = "" ]; then
|
||||
DESKTOP="other"; # default
|
||||
|
||||
elif [ "$DESKTOP" != "kde" ] && [ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
|
||||
echo "Usage: $0 <desktop_name> [<${prog_name}_options>]";
|
||||
echo "Desktop name may be kde, gnome, other.";
|
||||
exit 1;
|
||||
fi
|
||||
shift; # remove $1
|
||||
|
||||
|
||||
# They're basically the same, only the order is different.
|
||||
# sux requires xterm to ask for the password.
|
||||
# xdg-su is basically like this script, except worse :)
|
||||
gnome_sus="gnomesu gksu kdesu xdg-su sux";
|
||||
kde_sus="kdesu gnomesu gksu xdg-su sux";
|
||||
other_sus="$gnome_sus";
|
||||
|
||||
|
||||
candidates="";
|
||||
found_su=""
|
||||
|
||||
if [ "$DESKTOP" = "gnome" ]; then
|
||||
candidates="$gnome_sus";
|
||||
elif [ "$DESKTOP" = "kde" ]; then
|
||||
candidates="$kde_sus";
|
||||
elif [ "$DESKTOP" = "other" ]; then
|
||||
candidates="$other_sus";
|
||||
fi
|
||||
|
||||
for subin in $candidates; do
|
||||
which $subin &>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
found_su="$subin";
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found_su" = "" ]; then
|
||||
xmessage "Error launching ${prog_name}: No suitable su mechanism found.
|
||||
Try installing gnomesu, kdesu or sux first.";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# echo $found_su;
|
||||
|
||||
# gnomesu -c 'gsmartcontrol --no-scan'
|
||||
# kdesu -c 'gsmartcontrol --no-scan'
|
||||
# xterm -e sux -c 'gsmartcontrol --no-scan' # sux asks for password in a terminal
|
||||
|
||||
full_cmd=""
|
||||
if [ "$found_su" = "sux" ]; then
|
||||
full_cmd="xterm -e sux -c '$EXEC_BIN $@'"
|
||||
|
||||
elif [ "$found_su" = "gksu" ]; then
|
||||
full_cmd="$found_su '$EXEC_BIN $@'"
|
||||
|
||||
else # gnomesu, kdesu, xdg-su
|
||||
full_cmd="$found_su -c '$EXEC_BIN $@'"
|
||||
fi
|
||||
|
||||
|
||||
eval $full_cmd
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
EXTRA_DIST = distribution.txt.in gsmartcontrol.nsi.in nsi_install.ico nsi_uninstall.ico
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
GSmartControl - Hard disk drive health inspection tool
|
||||
Version @VERSION@
|
||||
|
||||
The latest version of this distribution, as well as the source code of
|
||||
GSmartControl, can be found at
|
||||
http://gsmartcontrol.berlios.de
|
||||
and
|
||||
http://developer.berlios.de/project/showfiles.php?group_id=10075
|
||||
|
||||
You need GTK+ for Windows Runtime package to use this program. You can get one
|
||||
at http://gtk-win.sf.net (you must download at least version 2.16.6-2010-02-21
|
||||
of gtk2-runtime).
|
||||
|
||||
|
||||
This distribution includes:
|
||||
|
||||
* GSmartControl binary (gsmartcontrol.exe) and associated resources. The
|
||||
binary was compiled for 32-bit Windows, and should work on both 32-bit and
|
||||
64-bit Windows. The binary was statically compiled against Gtkmm
|
||||
(http://www.gtkmm.org/) and related libraries, and PCRE (http://www.pcre.org/).
|
||||
|
||||
* Smartctl binaries (from smartmontools 5.41, http://smartmontools.sf.net/)
|
||||
- smartctl-nc.exe (compiled without console output), smartctl.exe (compiled
|
||||
with console output).
|
||||
|
||||
|
||||
The combined distribution is multi-licensed under GNU GPL versions 2 and 3.
|
||||
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
GSmartControl - Hard disk drive health inspection tool
|
||||
Version @VERSION@
|
||||
|
||||
The latest version of this distribution, as well as the source code of
|
||||
GSmartControl, can be found at
|
||||
http://gsmartcontrol.berlios.de
|
||||
and
|
||||
http://developer.berlios.de/project/showfiles.php?group_id=10075
|
||||
|
||||
|
||||
This distribution includes:
|
||||
|
||||
* GSmartControl binary (gsmartcontrol.exe) and associated resources. The
|
||||
binary was compiled for 32-bit Windows, and should work on both 32-bit and
|
||||
64-bit Windows. The binary was statically compiled against Gtkmm
|
||||
(http://www.gtkmm.org/) and related libraries, and PCRE (http://www.pcre.org/).
|
||||
|
||||
* Smartctl binaries (from smartmontools 5.41, http://smartmontools.sf.net/)
|
||||
- smartctl-nc.exe (compiled without console output), smartctl.exe (compiled
|
||||
with console output).
|
||||
|
||||
* GTK+ for Windows Runtime package (@GTK_INSTALLER_NAME@)
|
||||
from http://gtk-win.sf.net, either in original or unpacked form.
|
||||
|
||||
|
||||
The combined distribution is multi-licensed under GNU GPL versions 2 and 3.
|
||||
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
|
||||
@@ -0,0 +1,519 @@
|
||||
|
||||
; NSIS2 Script
|
||||
; by Alexander Shaduri <ashaduri 'at' gmail.com>.
|
||||
; Compatible with NSIS Unicode 2.45.
|
||||
; Public Domain
|
||||
|
||||
; pass /DNO_GTK to makensis to disable inclusion of gtk.
|
||||
|
||||
; gtk installer name for embedding
|
||||
!define GTK_INSTALLER_EXE "@GTK_INSTALLER_NAME@.exe"
|
||||
|
||||
!define PRODUCT_VERSION "@VERSION@"
|
||||
!define PRODUCT_NAME "GSmartControl"
|
||||
!define PRODUCT_NAME_SMALL "gsmartcontrol"
|
||||
!define PRODUCT_PUBLISHER "Alexander Shaduri"
|
||||
!define PRODUCT_WEB_SITE "http://gsmartcontrol.berlios.de"
|
||||
|
||||
;!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\AppMainExe.exe"
|
||||
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||
|
||||
!define REGISTRY_APP_PATHS "Software\Microsoft\Windows\CurrentVersion\App Paths"
|
||||
|
||||
|
||||
!include "FileFunc.nsh" ; GetOptions
|
||||
|
||||
|
||||
|
||||
; --------------- General Settings
|
||||
|
||||
|
||||
; This is needed for proper start menu item manipulation (for all users) in vista
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; This compressor gives us the best results
|
||||
SetCompressor /SOLID lzma
|
||||
|
||||
; Do a CRC check before installing
|
||||
CRCCheck On
|
||||
|
||||
; This is used in titles
|
||||
Name "${PRODUCT_NAME}" ; ${PRODUCT_VERSION}
|
||||
|
||||
; Output File Name
|
||||
!ifdef NO_GTK
|
||||
OutFile "${PRODUCT_NAME_SMALL}-${PRODUCT_VERSION}-nogtk.exe"
|
||||
!else
|
||||
OutFile "${PRODUCT_NAME_SMALL}-${PRODUCT_VERSION}.exe"
|
||||
!endif
|
||||
|
||||
|
||||
; The Default Installation Directory:
|
||||
; Try to install to the same directory as runtime.
|
||||
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
|
||||
; If already installed, try here
|
||||
InstallDirRegKey HKLM "SOFTWARE\${PRODUCT_NAME}" "InstallationDirectory"
|
||||
|
||||
|
||||
ShowInstDetails show
|
||||
ShowUnInstDetails show
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; --------------------- MUI INTERFACE
|
||||
|
||||
; MUI 2.0 compatible install
|
||||
!include "MUI2.nsh"
|
||||
!include "InstallOptions.nsh" ; section description macros
|
||||
|
||||
; Backgound Colors. uncomment to enable fullscreen.
|
||||
; BGGradient 0000FF 000000 FFFFFF
|
||||
|
||||
; MUI Settings
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "nsi_install.ico"
|
||||
!define MUI_UNICON "nsi_uninstall.ico"
|
||||
|
||||
|
||||
; Things that need to be extracted on first (keep these lines before any File command!).
|
||||
; Only useful for BZIP2 compression.
|
||||
;!insertmacro MUI_RESERVEFILE_LANGDLL
|
||||
;!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
|
||||
|
||||
|
||||
; Language Selection Dialog Settings
|
||||
;!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
|
||||
;!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
|
||||
;!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"
|
||||
|
||||
!ifdef NO_GTK
|
||||
!define LICENSE_FILE "doc\distribution-nogtk.txt"
|
||||
!else
|
||||
!define LICENSE_FILE "doc\distribution.txt"
|
||||
!endif
|
||||
|
||||
; Pages to show during installation
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}"
|
||||
!ifndef NO_GTK
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE on_components_page_leave
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!endif
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
;!define MUI_FINISHPAGE_RUN "$INSTDIR\gsmartcontrol.exe"
|
||||
;!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\Example.file"
|
||||
;!define MUI_FINISHPAGE_RUN_NOTCHECKED
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
||||
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
|
||||
|
||||
; Uninstaller page
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
|
||||
|
||||
; Language files
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
|
||||
; --------------- END MUI
|
||||
|
||||
LangString TEXT_IO_TITLE ${LANG_ENGLISH} "GSmartControl"
|
||||
|
||||
|
||||
var install_option_removeold ; uninstall the old version first (if present): yes (default), no.
|
||||
|
||||
|
||||
|
||||
; ----------------- INSTALLATION TYPES
|
||||
|
||||
; InstType "Recommended"
|
||||
; InstType "Full"
|
||||
; InstType "Minimal"
|
||||
|
||||
|
||||
|
||||
|
||||
Section "!GSmartControl" SecMain
|
||||
SectionIn 1 RO
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
SetOverwrite Off ; don't overwrite the config file
|
||||
; File "gsmartcontrol.conf"
|
||||
|
||||
SetOverwrite On
|
||||
File gsmartcontrol.exe
|
||||
File gsmartcontrol.exe.manifest
|
||||
File gsmartcontrol.ico
|
||||
File icon_*.png
|
||||
; File *.dll
|
||||
File smartctl-nc.exe
|
||||
File smartctl.exe
|
||||
|
||||
; Include the "doc" directory completely, excluding the file we're not using (e.g. the -nogtk file in gtk installer).
|
||||
!ifdef NO_GTK
|
||||
File /r /x distribution.txt doc
|
||||
!else
|
||||
File /r /x distribution-nogtk.txt doc
|
||||
!endif
|
||||
|
||||
; Add Shortcuts (this inherits the exe's run permissions)
|
||||
CreateShortCut "$SMPROGRAMS\GSmartControl.lnk" "$INSTDIR\gsmartcontrol.exe" "" \
|
||||
"$INSTDIR\gsmartcontrol.ico" "" SW_SHOWNORMAL "" "GSmartControl - Hard disk drive health inspection tool"
|
||||
|
||||
SectionEnd
|
||||
|
||||
|
||||
|
||||
!ifndef NO_GTK
|
||||
|
||||
; The SecGtkPrivate and SecGtkPublic sections are mutually exclusive.
|
||||
|
||||
Section "GTK+ (for this program only)" SecGtkPrivate
|
||||
SectionIn 1
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
AddSize 12200 ; ~ size of unpacked gtk
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${GTK_INSTALLER_EXE}"
|
||||
; TODO: in the future, when we have translations for this program,
|
||||
; make the GTK+ translations installation dependent on their installation status.
|
||||
ExecWait '"${GTK_INSTALLER_EXE}" /sideeffects=no /dllpath=root /translations=no /compatdlls=no /S /D=$INSTDIR'
|
||||
Delete "$INSTDIR\${GTK_INSTALLER_EXE}"
|
||||
SectionEnd
|
||||
|
||||
; disabled by default
|
||||
Section /o "GTK+ (shared installation)" SecGtkPublic
|
||||
SectionIn 1
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
AddSize 12200 ; ~ size of unpacked gtk
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${GTK_INSTALLER_EXE}"
|
||||
ExecWait '"${GTK_INSTALLER_EXE}"'
|
||||
Delete "$INSTDIR\${GTK_INSTALLER_EXE}"
|
||||
SectionEnd
|
||||
|
||||
!endif ; !NO_GTK
|
||||
|
||||
|
||||
!ifndef NO_GTK
|
||||
var gtk_mode ; "public", "private" or "none"
|
||||
var gtk_tmp ; temporary variable
|
||||
!endif
|
||||
|
||||
|
||||
; Executed on installation start
|
||||
Function .onInit
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
|
||||
${GetOptions} "$CMDLINE" "/removeold=" $install_option_removeold
|
||||
|
||||
Call PreventMultipleInstances
|
||||
|
||||
Call DetectPrevInstallation
|
||||
|
||||
; ask for gtk only if it's a non-gtk installer.
|
||||
!ifdef NO_GTK
|
||||
Call AskForGtk
|
||||
!endif
|
||||
|
||||
!ifndef NO_GTK
|
||||
StrCpy $gtk_mode "private" ; default
|
||||
!endif
|
||||
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
||||
function .onselchange
|
||||
|
||||
!ifndef NO_GTK
|
||||
; Remember which gtk section was selected.
|
||||
; Deselect the other section.
|
||||
|
||||
; If it was private, we check if public is checked and uncheck private.
|
||||
|
||||
StrCmp $gtk_mode "private" check_public ; old selection
|
||||
StrCmp $gtk_mode "public" check_private ; old selection
|
||||
goto check_exit
|
||||
|
||||
check_public:
|
||||
SectionGetFlags ${SecGtkPublic} $gtk_tmp ; see if it's checked
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SF_SELECTED}
|
||||
IntCmp $gtk_tmp ${SF_SELECTED} "" check_exit check_exit
|
||||
SectionGetFlags ${SecGtkPrivate} $gtk_tmp ; unselect the other one
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SECTION_OFF}
|
||||
SectionSetFlags ${SecGtkPrivate} $gtk_tmp
|
||||
goto check_exit
|
||||
|
||||
check_private:
|
||||
SectionGetFlags ${SecGtkPrivate} $gtk_tmp ; see if it's checked
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SF_SELECTED}
|
||||
IntCmp $gtk_tmp ${SF_SELECTED} "" check_exit check_exit
|
||||
SectionGetFlags ${SecGtkPublic} $gtk_tmp ; unselect the other one
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SECTION_OFF}
|
||||
SectionSetFlags ${SecGtkPublic} $gtk_tmp
|
||||
|
||||
check_exit:
|
||||
|
||||
|
||||
; store the current mode
|
||||
StrCpy $gtk_mode "none"
|
||||
|
||||
SectionGetFlags ${SecGtkPrivate} $gtk_tmp
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SF_SELECTED}
|
||||
IntCmp $gtk_tmp ${SF_SELECTED} "" mode_end_private mode_end_private
|
||||
StrCpy $gtk_mode "private"
|
||||
mode_end_private:
|
||||
|
||||
SectionGetFlags ${SecGtkPublic} $gtk_tmp
|
||||
IntOp $gtk_tmp $gtk_tmp & ${SF_SELECTED}
|
||||
IntCmp $gtk_tmp ${SF_SELECTED} "" mode_end_public mode_end_public
|
||||
StrCpy $gtk_mode "public"
|
||||
mode_end_public:
|
||||
|
||||
; MessageBox MB_ICONINFORMATION|MB_OK "gtk_mode: $gtk_mode" /SD IDOK
|
||||
!endif ; !NO_GTK
|
||||
|
||||
functionend
|
||||
|
||||
|
||||
!ifndef NO_GTK
|
||||
Function on_components_page_leave
|
||||
StrCmp $gtk_mode "none" "" noabort
|
||||
Call AskForGtk
|
||||
noabort:
|
||||
FunctionEnd
|
||||
!endif ; !NO_GTK
|
||||
|
||||
|
||||
|
||||
|
||||
; Section descriptions
|
||||
!ifndef NO_GTK ; this page is shown only when using gtk
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecMain} "GSmartControl - hard disk drive health inspection tool"
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecGtkPrivate} "GTK+ libraries, needed by GSmartControl. \
|
||||
This will install a private version of GTK+, usable only by GSmartControl."
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecGtkPublic} "GTK+ libraries, needed by GSmartControl. \
|
||||
This will install a system-wide version of GTK+, shareable with other programs."
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
!endif
|
||||
|
||||
|
||||
; ------------------ POST INSTALL
|
||||
|
||||
|
||||
var gtk_dll_abs_path
|
||||
|
||||
Section -post
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
|
||||
; Don't set any paths for this exe if it has a private GTK+ installation.
|
||||
!ifndef NO_GTK
|
||||
StrCmp $gtk_mode "private" skip_exe_PATH
|
||||
!endif
|
||||
; set a special path for this exe, as GTK may not be in a global path.
|
||||
ReadRegStr $gtk_dll_abs_path HKLM "SOFTWARE\GTK\2.0" "DllPath"
|
||||
WriteRegStr HKLM "${REGISTRY_APP_PATHS}\gsmartcontrol.exe" "Path" "$gtk_dll_abs_path"
|
||||
!ifndef NO_GTK
|
||||
skip_exe_PATH:
|
||||
!endif
|
||||
|
||||
!ifndef NO_GTK
|
||||
WriteRegStr HKLM "SOFTWARE\${PRODUCT_NAME}" "GtkInstalledMode" "$gtk_mode"
|
||||
!endif
|
||||
|
||||
WriteRegStr HKLM "SOFTWARE\${PRODUCT_NAME}" "InstallationDirectory" "$INSTDIR"
|
||||
WriteRegStr HKLM "SOFTWARE\${PRODUCT_NAME}" "Vendor" "${PRODUCT_PUBLISHER}"
|
||||
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\gsmartcontrol_uninst.exe"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\gsmartcontrol.ico"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||
WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
|
||||
WriteRegDWORD HKLM "${PRODUCT_UNINST_KEY}" "NoModify" 1
|
||||
WriteRegDWORD HKLM "${PRODUCT_UNINST_KEY}" "NoRepair" 1
|
||||
|
||||
; We don't need this, MUI takes care for us
|
||||
; WriteRegStr HKCU "Software\${PRODUCT_NAME}" "Installer Language" $sUAGE
|
||||
|
||||
; write out uninstaller
|
||||
WriteUninstaller "$INSTDIR\gsmartcontrol_uninst.exe"
|
||||
|
||||
; uninstall shortcut
|
||||
;CreateDirectory "$SMPROGRAMS\GSmartControl"
|
||||
;CreateShortCut "$SMPROGRAMS\GSmartControl\Uninstall GSmartControl.lnk" "$INSTDIR\gsmartcontrol_uninst.exe" "" ""
|
||||
|
||||
SectionEnd ; post
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; ---------------- UNINSTALL
|
||||
|
||||
|
||||
|
||||
Function un.onUninstSuccess
|
||||
HideWindow
|
||||
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." /SD IDOK
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
||||
|
||||
Section Uninstall
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
SetAutoClose false
|
||||
|
||||
!ifndef NO_GTK
|
||||
ReadRegStr $gtk_mode HKLM "SOFTWARE\${PRODUCT_NAME}" "GtkInstalledMode"
|
||||
StrCmp $gtk_mode "private" "" skip_gtk_remove
|
||||
; remove private GTK+, specify the same custom options are during installation
|
||||
ExecWait "$INSTDIR\gtk2_runtime_uninst.exe /remove_config=yes /sideeffects=no /dllpath=root /translations=no /compatdlls=no /S"
|
||||
; _?=$INSTDIR
|
||||
; Delete "$INSTDIR\gtk2_runtime_uninst.exe" ; If using _? flag, it won't get deleted automatically, do it manually.
|
||||
skip_gtk_remove:
|
||||
!endif
|
||||
|
||||
; add delete commands to delete whatever files/registry keys/etc you installed here.
|
||||
Delete "$INSTDIR\gsmartcontrol_uninst.exe"
|
||||
|
||||
DeleteRegKey HKLM "SOFTWARE\${PRODUCT_NAME}"
|
||||
DeleteRegKey HKLM "${PRODUCT_UNINST_KEY}"
|
||||
|
||||
Delete "$INSTDIR\gsmartcontrol.exe"
|
||||
Delete "$INSTDIR\gsmartcontrol.exe.manifest"
|
||||
Delete "$INSTDIR\gsmartcontrol.ico"
|
||||
Delete "$INSTDIR\icon_*.png"
|
||||
; Delete "$INSTDIR\*.dll"
|
||||
Delete "$INSTDIR\smartctl-nc.exe"
|
||||
Delete "$INSTDIR\smartctl.exe"
|
||||
|
||||
RMDir /r "$INSTDIR\doc"
|
||||
|
||||
; clean up generated stuff
|
||||
Delete "$INSTDIR\*stdout.txt"
|
||||
Delete "$INSTDIR\*stderr.txt"
|
||||
|
||||
RMDir "$INSTDIR" ; only if empty
|
||||
|
||||
!ifndef NO_GTK
|
||||
StrCmp $gtk_mode "private" skip_exe_PATH_remove
|
||||
!endif
|
||||
DeleteRegKey HKLM "${REGISTRY_APP_PATHS}\gsmartcontrol.exe"
|
||||
!ifndef NO_GTK
|
||||
skip_exe_PATH_remove:
|
||||
!endif
|
||||
|
||||
Delete "$SMPROGRAMS\GSmartControl.lnk"
|
||||
;Delete "$SMPROGRAMS\GSmartControl\Uninstall GSmartControl.lnk"
|
||||
|
||||
SectionEnd ; end of uninstall section
|
||||
|
||||
|
||||
|
||||
; --------------- Helpers
|
||||
|
||||
; Detect previous installation
|
||||
Function DetectPrevInstallation
|
||||
; if /removeold=no option is given, don't check anything.
|
||||
StrCmp $install_option_removeold "no" old_detect_done
|
||||
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
push $R0
|
||||
|
||||
; detect previous installation
|
||||
ReadRegStr $R0 HKLM "${PRODUCT_UNINST_KEY}" "UninstallString"
|
||||
StrCmp $R0 "" old_detect_done
|
||||
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
|
||||
previous version or `Cancel` to continue anyway." \
|
||||
/SD IDOK IDOK old_uninst
|
||||
; Abort
|
||||
goto old_detect_done
|
||||
|
||||
; Run the old uninstaller
|
||||
old_uninst:
|
||||
ClearErrors
|
||||
IfSilent old_silent_uninst old_nosilent_uninst
|
||||
|
||||
old_nosilent_uninst:
|
||||
ExecWait '$R0'
|
||||
goto old_uninst_continue
|
||||
|
||||
old_silent_uninst:
|
||||
ExecWait '$R0 /S _?=$INSTDIR'
|
||||
|
||||
old_uninst_continue:
|
||||
|
||||
IfErrors old_no_remove_uninstaller
|
||||
|
||||
; You can either use Delete /REBOOTOK in the uninstaller or add some code
|
||||
; here to remove to remove the uninstaller. Use a registry key to check
|
||||
; whether the user has chosen to uninstall. If you are using an uninstaller
|
||||
; components page, make sure all sections are uninstalled.
|
||||
old_no_remove_uninstaller:
|
||||
|
||||
old_detect_done: ; old installation not found, all ok
|
||||
|
||||
pop $R0
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
||||
; detect GTK installation (any of available versions)
|
||||
Function AskForGtk
|
||||
SetShellVarContext all ; use all user variables as opposed to current user
|
||||
push $R0
|
||||
|
||||
ReadRegStr $R0 HKLM "SOFTWARE\GTK\2.0" "DllPath"
|
||||
StrCmp $R0 "" no_gtk have_gtk
|
||||
|
||||
no_gtk:
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||
"GTK2-Runtime is not installed. This product needs it to function properly.$\n\
|
||||
Please install GTK2-Runtime from http://gtk-win.sf.net/ first.$\n$\n\
|
||||
Click 'Cancel' to abort the installation \
|
||||
or 'OK' to continue anyway." \
|
||||
/SD IDOK IDOK have_gtk
|
||||
;Abort ; Abort has different meaning from onpage callbacks, so use Quit
|
||||
Quit
|
||||
goto end_gtk_check
|
||||
|
||||
have_gtk:
|
||||
; do nothing
|
||||
|
||||
end_gtk_check:
|
||||
|
||||
pop $R0
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
||||
; Prevent running multiple instances of the installer
|
||||
Function PreventMultipleInstances
|
||||
Push $R0
|
||||
System::Call 'kernel32::CreateMutexA(i 0, i 0, t ${PRODUCT_NAME}) ?e'
|
||||
Pop $R0
|
||||
StrCmp $R0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." /SD IDOK
|
||||
Abort
|
||||
Pop $R0
|
||||
FunctionEnd
|
||||
|
||||
|
||||
|
||||
; eof
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
@@ -0,0 +1,6 @@
|
||||
|
||||
noinst_DATA = changelog.in compat control copyright menu postinst postrm rules
|
||||
|
||||
# include the generated file too
|
||||
EXTRA_DIST=changelog.in changelog compat control copyright menu postinst \
|
||||
postrm rules
|
||||
@@ -0,0 +1,5 @@
|
||||
gsmartcontrol (@VERSION@+nmu1) unstable; urgency=low
|
||||
|
||||
* Permanently Initial Release.
|
||||
|
||||
-- Alexander Shaduri <ashaduriREMOVETHIS@gmail.com> Sat, 15 Nov 2008 00:12:04 +0400
|
||||
@@ -0,0 +1 @@
|
||||
5
|
||||
@@ -0,0 +1,21 @@
|
||||
Source: gsmartcontrol
|
||||
Section: utils
|
||||
Priority: extra
|
||||
Homepage: http://gsmartcontrol.berlios.de/
|
||||
Maintainer: Alexander Shaduri <ashaduriREMOVETHIS@gmail.com>
|
||||
# technically, we don't need libglademm if gtkmm >= 2.12, but it won't get
|
||||
# into Depends if it's not needed, so let's leave it here.
|
||||
Build-Depends: debhelper (>= 5), autotools-dev,
|
||||
libpcre3-dev, libgtkmm-2.4-dev (>= 2.6.0), libglademm-2.4-dev
|
||||
Standards-Version: 3.7.3
|
||||
|
||||
Package: gsmartcontrol
|
||||
Architecture: any
|
||||
#Depends: ${shlibs:Depends}, ${misc:Depends}, smartmontools, menu
|
||||
Depends: ${shlibs:Depends}, smartmontools, menu
|
||||
Description: Hard disk drive health inspection tool
|
||||
GSmartControl is a graphical user interface for smartctl (from smartmontools
|
||||
package), which is a tool for querying and controlling SMART
|
||||
(Self-Monitoring, Analysis, and Reporting Technology) data on modern hard
|
||||
disk drives. It allows you to inspect the drive's SMART data to determine its
|
||||
health, as well as run various tests on it.
|
||||
@@ -0,0 +1,32 @@
|
||||
This package was debianized by Alexander Shaduri <ashaduri 'at' gmail.com> on
|
||||
Sat, 15 Nov 2008 00:12:04 +0400.
|
||||
|
||||
It was downloaded from <http://gsmartcontrol.berlios.de/>
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
|
||||
License:
|
||||
|
||||
This product is multi-licensed under GNU GPL versions 2 and 3.
|
||||
You are free to choose which one you use.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under
|
||||
the terms of either version 2 or (at your option) version 3 of the GNU General
|
||||
Public License as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public Licenses for more details.
|
||||
|
||||
You should have received copies of these licenses along with this program.
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public Licenses can be found in `/usr/share/common-licenses/GPL-2' and
|
||||
`/usr/share/common-licenses/GPL-3'.
|
||||
|
||||
The Debian packaging is (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com> and
|
||||
is licensed under the GPLv2 and GPLv3, see above.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
?package(gsmartcontrol):needs="X11" section="Applications/System/Hardware"\
|
||||
title="GSmartControl" command="/usr/bin/gsmartcontrol-root"\
|
||||
longtitle="Hard Disk Health Inspection"\
|
||||
icon="/usr/share/pixmaps/gsmartcontrol.xpm"
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if test -x /usr/bin/update-menus; then update-menus; fi
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if test -x /usr/bin/update-menus; then update-menus; fi
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
|
||||
config.status: configure
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
|
||||
cp -f /usr/share/misc/config.sub config.sub
|
||||
endif
|
||||
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
|
||||
cp -f /usr/share/misc/config.guess config.guess
|
||||
endif
|
||||
./configure --host=$(DEB_HOST_GNU_TYPE) \
|
||||
--build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man \
|
||||
--infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs"
|
||||
|
||||
# Add --enable-optimize-options=auto to configure line
|
||||
# for optimized build (may not work on older gcc versions).
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: config.status
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
$(MAKE)
|
||||
#docbook-to-man debian/gsmartcontrol.sgml > gsmartcontrol.1
|
||||
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
-$(MAKE) clean
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/gsmartcontrol.
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/gsmartcontrol install-strip
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs ChangeLog
|
||||
dh_installdocs
|
||||
# dh_installexamples
|
||||
# dh_install
|
||||
dh_installmenu
|
||||
# dh_installdebconf
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
# dh_python
|
||||
# dh_installinit
|
||||
# dh_installcron
|
||||
# dh_installinfo
|
||||
dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_perl
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[Project]
|
||||
Manager=KDevCustomBuildSystem
|
||||
Name=gsmartcontrol
|
||||
+82
-14
@@ -22,7 +22,7 @@
|
||||
<kdevautoproject>
|
||||
<general>
|
||||
<activetarget>src/gsmartcontrol</activetarget>
|
||||
<useconfiguration>debuggy</useconfiguration>
|
||||
<useconfiguration>open64</useconfiguration>
|
||||
</general>
|
||||
<run>
|
||||
<mainprogram>/10/devel/projects/gsmartcontrol/current/gsmartcontrol/debuggy</mainprogram>
|
||||
@@ -76,7 +76,7 @@
|
||||
<f77flags/>
|
||||
</optimized>
|
||||
<debuggy>
|
||||
<configargs>--disable-user-flags --enable-debug-options --enable-tests</configargs>
|
||||
<configargs>--enable-debug-options --enable-tests</configargs>
|
||||
<builddir>debuggy</builddir>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
@@ -87,8 +87,8 @@
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompilerbinary/>
|
||||
<cxxcompilerbinary/>
|
||||
<ccompilerbinary>gcc-4.4</ccompilerbinary>
|
||||
<cxxcompilerbinary>g++-4.4</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<f77flags/>
|
||||
</debuggy>
|
||||
@@ -102,8 +102,8 @@
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>icc</ccompilerbinary>
|
||||
<cxxcompilerbinary>icpc</cxxcompilerbinary>
|
||||
<ccompilerbinary>icc64</ccompilerbinary>
|
||||
<cxxcompilerbinary>icpc64</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
@@ -111,7 +111,7 @@
|
||||
</icc>
|
||||
<win32>
|
||||
<envvars/>
|
||||
<configargs>--disable-user-flags --enable-debug-options --enable-tests --target=i386-mingw32msvc --host=i386-mingw32msvc --build=i686-linux PKG_CONFIG_PATH=/target/lib/pkgconfig PKG_CONFIG_LIBDIR=/target/lib PATH="/opt/cross-tools/bin:/target/bin:$PATH"</configargs>
|
||||
<configargs>--with-windows-gtk-name=gtk2-runtime-2.16.6-2010-02-24-ash --disable-user-flags --enable-optimize-options --enable-tests --build=i686-linux --host=i386-pc-mingw32 PKG_CONFIG_PATH=/cross/w32/target/lib/pkgconfig PKG_CONFIG_LIBDIR="" PATH="/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH"</configargs>
|
||||
<builddir>win32</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
@@ -119,8 +119,8 @@
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>i386-mingw32msvc-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-mingw32msvc-g++</cxxcompilerbinary>
|
||||
<ccompilerbinary>i386-pc-mingw32-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-pc-mingw32-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
@@ -128,21 +128,21 @@
|
||||
</win32>
|
||||
<suncc>
|
||||
<envvars>
|
||||
<envvar value="/opt/sun/sunstudio12/bin:$PATH" name="PATH" />
|
||||
<envvar value="/opt/sun/sunstudio/bin:$PATH" name="PATH" />
|
||||
</envvars>
|
||||
<configargs>--enable-tests</configargs>
|
||||
<configargs>--enable-tests PKG_CONFIG_PATH="/opt/sun/target64/lib64/pkgconfig:/usr/lib64/pkgconfig" PKG_CONFIG_LIBDIR=""</configargs>
|
||||
<builddir>suncc</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags>-s</ldflags>
|
||||
<ldflags>-R/opt/sun/target64/lib64 -L/opt/sun/target64/lib64</ldflags>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>suncc</ccompilerbinary>
|
||||
<cxxcompilerbinary>sunCC</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags>-errwarn=%all</cflags>
|
||||
<cxxflags>-DGLIBMM_HAVE_SUN_REVERSE_ITERATOR -DSIGC_HAVE_SUN_REVERSE_ITERATOR</cxxflags>
|
||||
<cflags>-errwarn=%all -I/opt/sun/target64/include</cflags>
|
||||
<cxxflags>-I/opt/sun/target64/include</cxxflags>
|
||||
<f77flags/>
|
||||
</suncc>
|
||||
<portland>
|
||||
@@ -162,6 +162,74 @@
|
||||
<cxxflags>-Minform=warn -Bstatic_pgi -noswitcherror -define_macro=HZ_NO_COMPILER_AUTOINCLUDE</cxxflags>
|
||||
<f77flags/>
|
||||
</portland>
|
||||
<win32-debug>
|
||||
<envvars/>
|
||||
<configargs>--disable-user-flags --enable-debug-options --enable-tests --build=i686-linux --host=i386-pc-mingw32 PKG_CONFIG_PATH=/cross/w32/target/lib/pkgconfig PKG_CONFIG_LIBDIR="" PATH="/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH"</configargs>
|
||||
<builddir>win32-debug</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>i386-pc-mingw32-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-pc-mingw32-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</win32-debug>
|
||||
<win64-debug>
|
||||
<envvars/>
|
||||
<configargs>--disable-user-flags --enable-optimize-options --enable-tests --build=i686-linux --host=x86_64-pc-mingw32 PKG_CONFIG_PATH=/cross/w64/target/lib/pkgconfig PKG_CONFIG_LIBDIR="" PATH="/cross/w64/gcc-bin:/cross/w64/target/bin:$PATH"</configargs>
|
||||
<builddir>win64-debug</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>x86_64-pc-mingw32-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>x86_64-pc-mingw32-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</win64-debug>
|
||||
<default>
|
||||
<envvars/>
|
||||
<configargs/>
|
||||
<builddir/>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary/>
|
||||
<cxxcompilerbinary/>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</default>
|
||||
<open64>
|
||||
<envvars/>
|
||||
<configargs>--enable-tests</configargs>
|
||||
<builddir>open64</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>/opt/open64/bin/opencc</ccompilerbinary>
|
||||
<cxxcompilerbinary>/opt/open64/bin/openCC</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags>-Wall</cxxflags>
|
||||
<f77flags/>
|
||||
</open64>
|
||||
</configurations>
|
||||
<make>
|
||||
<envvars>
|
||||
|
||||
+57
-18
@@ -1,15 +1,20 @@
|
||||
Name: gsmartcontrol
|
||||
Version: @VERSION@
|
||||
Version: @VERSION@
|
||||
Release: 1as
|
||||
License: GPLv2, GPLv3
|
||||
Vendor: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Url: http://gsmartcontrol.berlios.de
|
||||
Vendor: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Packager: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Group: Hardware/Other
|
||||
Source: gsmartcontrol-%{version}.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
Summary: GSmartControl - Hard Disk Health Inspection Tool
|
||||
|
||||
%if 0%{?mandriva_version}
|
||||
Group: System/Kernel and hardware
|
||||
%else
|
||||
Group: Hardware/Other
|
||||
%endif
|
||||
|
||||
# Support build service rpmlint. Disabled - the build service
|
||||
# stopped recognizing the flag for some architectures.
|
||||
# %if 0%{?opensuse_bs} && 0%{?suse_version} >= 1010
|
||||
@@ -22,16 +27,24 @@ Summary: GSmartControl - Hard Disk Health Inspection Tool
|
||||
# (with the respective -devel packages of the libraries for build requirements).
|
||||
# For non-specified distributions we don't specify any dependencies to avoid errors.
|
||||
|
||||
# For mandriva, these contain the su programs.
|
||||
# Suggests: libgnomesu, gksu, kdebase-progs
|
||||
|
||||
|
||||
# SUSE / OpenSUSE. SLES also defines the correct suse_version.
|
||||
%if 0%{?suse_version}
|
||||
|
||||
%if 0%{?%suse_version} >= 1030
|
||||
Requires: smartmontools, pcre, gtkmm2 >= 2.12.0
|
||||
BuildRequires: gcc-c++ libstdc++-devel pcre-devel, gtkmm2-devel >= 2.12.0
|
||||
BuildRequires: gcc-c++, libstdc++-devel, pcre-devel, gtkmm2-devel >= 2.12.0
|
||||
%else
|
||||
%if 0%{?%suse_version} == 1020
|
||||
Requires: smartmontools, pcre, gtkmm2 >= 2.6.0, libglademm >= 2.4.0
|
||||
BuildRequires: gcc-c++ libstdc++-devel pcre-devel, gtkmm2-devel >= 2.6.0, libglademm-devel >= 2.4.0
|
||||
BuildRequires: gcc-c++, libstdc++-devel, pcre-devel, gtkmm2-devel >= 2.6.0, libglademm-devel >= 2.4.0
|
||||
%else
|
||||
Requires: smartmontools, pcre, gtkmm24 >= 2.6.0, libglademm >= 2.4.0
|
||||
BuildRequires: gcc-c++, libstdc++-devel, pcre-devel, gtkmm24-devel >= 2.6.0, libglademm-devel >= 2.4.0
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%endif
|
||||
@@ -43,24 +56,31 @@ BuildRequires: gcc-c++ libstdc++-devel pcre-devel, gtkmm2-devel >= 2.6.0, libgla
|
||||
# I'm not sure about centos and rhel versions
|
||||
%if 0%{?fedora_version} >= 8 || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
|
||||
Requires: smartmontools, pcre, gtkmm24 >= 2.12.0
|
||||
BuildRequires: gcc-c++ pcre-devel, gtkmm24-devel >= 2.12.0
|
||||
BuildRequires: gcc-c++, pcre-devel, gtkmm24-devel >= 2.12.0
|
||||
%else
|
||||
Requires: smartmontools, pcre, gtkmm24 >= 2.6.0, libglademm24 >= 2.4.0
|
||||
BuildRequires: gcc-c++ pcre-devel, gtkmm24-devel >= 2.6.0, libglademm24-devel >= 2.4.0
|
||||
BuildRequires: gcc-c++, pcre-devel, gtkmm24-devel >= 2.6.0, libglademm24-devel >= 2.4.0
|
||||
%endif
|
||||
|
||||
# Fedora doesn't include gnomesu or anything similar except beesu (since 11), so force it.
|
||||
# usermode-gtk is for consolehelper-gtk (optional for beesu, needed for GUI auth).
|
||||
%if 0%{?fedora_version} >= 11
|
||||
Requires: beesu, usermode-gtk
|
||||
%endif
|
||||
|
||||
%endif
|
||||
|
||||
|
||||
# Mandriva
|
||||
# Mandriva. Check the latest official spec file at
|
||||
# http://svn.mandriva.com/cgi-bin/viewvc.cgi/packages/cooker/gsmartcontrol/current/
|
||||
%if 0%{?mandriva_version}
|
||||
|
||||
%if 0%{?mandriva_version} >= 2008
|
||||
Requires: smartmontools, libpcre0, libgtkmm2.4_1 >= 2.12.0
|
||||
BuildRequires: gcc-c++ gcc-cpp libpcre-devel, libgtkmm2.4-devel >= 2.12.0
|
||||
Requires: smartmontools, libpcre0, gtkmm2.4 >= 2.12.0
|
||||
BuildRequires: gcc-c++, gcc-cpp, pcre-devel, gtkmm2.4-devel >= 2.12.0, desktop-file-utils
|
||||
%else
|
||||
Requires: smartmontools, libpcre0, libgtkmm2.4_1 >= 2.6.0, libglademm2.4_1 >= 2.4.0
|
||||
BuildRequires: gcc-c++ gcc-cpp libpcre-devel, libgtkmm2.4-devel >= 2.6.0, libglademm2.4_1-devel >= 2.4.0
|
||||
Requires: smartmontools, libpcre0, gtkmm2.4 >= 2.6.0, libglademm2.4 >= 2.4.0
|
||||
BuildRequires: gcc-c++, gcc-cpp, pcre-devel, gtkmm2.4-devel >= 2.6.0, libglademm2.4-devel >= 2.4.0, desktop-file-utils
|
||||
%endif
|
||||
|
||||
%endif
|
||||
@@ -76,13 +96,14 @@ SMART data to determine its health, as well as run various tests on it.
|
||||
|
||||
|
||||
%setup -q
|
||||
%if 0%{?mandriva_version} <= 2006
|
||||
%configure
|
||||
# Don't use configure parameters - let rpm set them.
|
||||
# --prefix=/usr --enable-default-gcc-options --enable-gcc-optimize
|
||||
|
||||
%else
|
||||
%configure --enable-optimize-options=auto
|
||||
%endif
|
||||
|
||||
%build
|
||||
# Setup for parallel builds
|
||||
# Set up for parallel builds
|
||||
numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :`
|
||||
if [ "$numprocs" = "0" ]; then
|
||||
numprocs=1
|
||||
@@ -94,7 +115,18 @@ make -j$numprocs
|
||||
|
||||
%install
|
||||
# %makeinstall
|
||||
make DESTDIR=%buildroot install
|
||||
make DESTDIR=%buildroot install-strip
|
||||
# Remove the icon cache file "make install" generates, to avoid package conflicts.
|
||||
rm -f $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/icon-theme.cache
|
||||
|
||||
|
||||
%if 0%{?mandriva_version}
|
||||
desktop-file-install --vendor="" \
|
||||
--remove-category="Application" \
|
||||
--add-category="System" \
|
||||
--add-category="X-MandrivaLinux-System-Configuration-Hardware;Settings;HardwareSettings" \
|
||||
--dir $RPM_BUILD_ROOT%{_datadir}/applications $RPM_BUILD_ROOT%{_datadir}/applications/%{name}.desktop
|
||||
%endif
|
||||
|
||||
|
||||
%clean
|
||||
@@ -108,6 +140,7 @@ rm -rf %buildroot
|
||||
# %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/*
|
||||
|
||||
%doc %{_datadir}/doc/gsmartcontrol
|
||||
%doc %{_mandir}/man1/*
|
||||
|
||||
%{_datadir}/gsmartcontrol
|
||||
# %{_datadir}/gsmartcontrol/*
|
||||
@@ -116,11 +149,17 @@ rm -rf %buildroot
|
||||
%{_datadir}/pixmaps/*
|
||||
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Dec 10 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Fixes for Fedora 14.
|
||||
|
||||
* Fri Nov 14 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Updated .spec file to incorporate changes from the official Mandriva package.
|
||||
|
||||
* Mon Oct 06 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Updated .spec file to support OpenSUSE < 10.3, Fedora and friends,
|
||||
Mandriva (for OpenSUSE Build Service).
|
||||
|
||||
* Mon Sep 15 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Initial .spec file.
|
||||
|
||||
|
||||
+29
-6
@@ -1,16 +1,39 @@
|
||||
AM_CPPFLAGS = $(all_includes)
|
||||
METASOURCES = AUTO
|
||||
|
||||
SUBDIRS = libdebug hz rmn rconfig pcrecpp applib res
|
||||
|
||||
|
||||
if TARGET_OS_KERNEL_FAMILY_WINDOWS
|
||||
WINRES_OBJ = gsc_winres_win32.o
|
||||
endif
|
||||
|
||||
# use different name for object file to avoid make auto-rules
|
||||
gsc_winres_win32.o: $(top_srcdir)/data/gsmartcontrol.ico gsc_winres.rc
|
||||
cp -f $(top_srcdir)/data/gsmartcontrol.ico .
|
||||
$(WINDRES) gsc_winres.rc gsc_winres_win32.o
|
||||
|
||||
mostlyclean-local:
|
||||
rm -f gsmartcontrol.ico
|
||||
|
||||
noinst_DATA = gsc_winres.rc.in gsmartcontrol.exe.manifest.in
|
||||
|
||||
|
||||
# if TARGET_OS_KERNEL_FAMILY_WINDOWS
|
||||
# WIN_MAIN_SRC = win_main.cpp
|
||||
# endif
|
||||
|
||||
|
||||
bin_PROGRAMS = gsmartcontrol
|
||||
|
||||
SUBDIRS = libdebug hz rmn rconfig pcrecpp applib res
|
||||
gsmartcontrol_LDADD = $(top_builddir)/src/applib/libapplib.a \
|
||||
$(top_builddir)/src/pcrecpp/libpcrecpp.a $(top_builddir)/src/libdebug/libdebug.a \
|
||||
$(top_builddir)/src/res/libres.a
|
||||
$(top_builddir)/src/res/libres.a $(WINRES_OBJ)
|
||||
|
||||
noinst_HEADERS = global_macros.h gsc_about_dialog.h gsc_executor_error_dialog.h \
|
||||
noinst_HEADERS = global_macros.h gsc_about_dialog.h gsc_add_device_window.h gsc_executor_error_dialog.h \
|
||||
gsc_executor_log_window.h gsc_help_window.h gsc_info_window.h gsc_init.h gsc_main_window.h \
|
||||
gsc_main_window_iconview.h gsc_preferences_window.h gsc_settings.h gsc_text_window.h
|
||||
gsmartcontrol_SOURCES = gsc_about_dialog.cpp gsc_executor_error_dialog.cpp \
|
||||
gsc_executor_log_window.cpp gsc_help_window.cpp gsc_info_window.cpp gsc_init.cpp gsc_main.cpp \
|
||||
gsc_main_window.cpp gsc_preferences_window.cpp
|
||||
gsmartcontrol_SOURCES = $(WIN_MAIN_SRC) gsc_about_dialog.cpp gsc_add_device_window.cpp \
|
||||
gsc_executor_error_dialog.cpp gsc_executor_log_window.cpp gsc_help_window.cpp gsc_info_window.cpp \
|
||||
gsc_init.cpp gsc_main.cpp gsc_main_window.cpp gsc_preferences_window.cpp
|
||||
|
||||
|
||||
+19
-12
@@ -1,21 +1,24 @@
|
||||
AM_CPPFLAGS = $(all_includes)
|
||||
METASOURCES = AUTO
|
||||
noinst_LIBRARIES = libapplib.a
|
||||
libapplib_a_SOURCES = app_gtkmm_utils.cpp cmdex.cpp cmdex_sync.cpp \
|
||||
cmdex_sync_gui.cpp gui_utils.cpp selftest.cpp smartctl_parser.cpp storage_detector.cpp \
|
||||
storage_device.cpp storage_property.cpp storage_property_descr.cpp
|
||||
noinst_HEADERS = app_gtkmm_features.h app_gtkmm_utils.h app_pcrecpp.h \
|
||||
app_ui_res_utils.h cmdex.h cmdex_sync.h cmdex_sync_gui.h gui_utils.h selftest.h smartctl_executor.h \
|
||||
smartctl_executor_gui.h smartctl_parser.h storage_detector.h storage_device.h \
|
||||
storage_property.h storage_property_colors.h storage_property_descr.h storage_settings.h \
|
||||
wrapping_label.h
|
||||
libapplib_a_SOURCES = app_gtkmm_utils.cpp app_pango_utils.cpp cmdex.cpp \
|
||||
cmdex_sync.cpp cmdex_sync_gui.cpp executor_factory.cpp gui_utils.cpp selftest.cpp smartctl_executor.cpp \
|
||||
smartctl_parser.cpp storage_detector.cpp storage_detector_linux.cpp storage_detector_other.cpp \
|
||||
storage_detector_win32.cpp storage_device.cpp storage_property.cpp \
|
||||
storage_property_descr.cpp
|
||||
noinst_HEADERS = app_gtkmm_features.h app_gtkmm_utils.h app_pango_utils.h \
|
||||
app_pcrecpp.h app_ui_res_utils.h cmdex.h cmdex_sync.h cmdex_sync_gui.h executor_factory.h gui_utils.h \
|
||||
selftest.h smartctl_executor.h smartctl_executor_gui.h smartctl_parser.h \
|
||||
storage_detector.h storage_detector_helpers.h storage_detector_linux.h storage_detector_other.h \
|
||||
storage_detector_win32.h storage_device.h storage_property.h storage_property_colors.h \
|
||||
storage_property_descr.h storage_settings.h tw_cli_executor.h wrapping_label.h
|
||||
|
||||
# don't use absolute path for the current dir's .a, because the make
|
||||
# dependency resolver won't get it (needed for parallel builds)
|
||||
|
||||
storage_detector_test_SOURCES = storage_detector_test.cpp
|
||||
storage_detector_test_LDADD = libapplib.a \
|
||||
$(top_builddir)/src/pcrecpp/libpcrecpp.a $(top_builddir)/src/libdebug/libdebug.a
|
||||
app_ui_res_utils_test_SOURCES = app_ui_res_utils_test.cpp app_ui_res_utils_test_data.cpp
|
||||
app_ui_res_utils_test_LDADD = libapplib.a \
|
||||
$(top_builddir)/src/libdebug/libdebug.a
|
||||
|
||||
smartctl_executor_test_SOURCES = smartctl_executor_test.cpp
|
||||
smartctl_executor_test_LDADD = libapplib.a \
|
||||
@@ -25,6 +28,10 @@ smartctl_parser_test_SOURCES = smartctl_parser_test.cpp
|
||||
smartctl_parser_test_LDADD = libapplib.a \
|
||||
$(top_builddir)/src/pcrecpp/libpcrecpp.a $(top_builddir)/src/libdebug/libdebug.a
|
||||
|
||||
storage_detector_test_SOURCES = storage_detector_test.cpp
|
||||
storage_detector_test_LDADD = libapplib.a \
|
||||
$(top_builddir)/src/pcrecpp/libpcrecpp.a $(top_builddir)/src/libdebug/libdebug.a
|
||||
|
||||
spawn_test_SOURCES = spawn_test.cpp
|
||||
|
||||
# Build them first
|
||||
@@ -34,7 +41,7 @@ SUBDIRS=../libdebug ../pcrecpp
|
||||
# we don't list them in a separate variable because otherwise kdevelop won't see them.
|
||||
noinst_PROGRAMS =
|
||||
if ENABLE_TESTS
|
||||
noinst_PROGRAMS += smartctl_executor_test smartctl_parser_test \
|
||||
noinst_PROGRAMS += app_ui_res_utils_test smartctl_executor_test smartctl_parser_test \
|
||||
storage_detector_test spawn_test
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
// New tooltip API is available since 2.12
|
||||
#if !APP_GTKMM_CHECK_VERSION(2, 12, 0)
|
||||
#define APP_GTKMM_OLD_TOOLTIPS
|
||||
#define APP_GTKMM_OLD_TOOLTIPS 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
|
||||
#include "app_gtkmm_features.h" // APP_GTKMM_OLD_TOOLTIPS
|
||||
|
||||
#ifdef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS
|
||||
#include <gtk/gtk.h> // gtk_tooltips_*
|
||||
#endif
|
||||
|
||||
#include "app_pango_utils.h" // app_pango_strip_markup()
|
||||
#include "app_gtkmm_utils.h"
|
||||
|
||||
|
||||
@@ -53,7 +54,7 @@ void app_gtkmm_set_widget_tooltip(Gtk::Widget& widget,
|
||||
const Glib::ustring& tooltip_text, bool use_markup)
|
||||
{
|
||||
// set_tooltip_* is available since 2.12
|
||||
#ifndef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if !(defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS)
|
||||
if (use_markup) {
|
||||
widget.set_tooltip_markup(tooltip_text);
|
||||
} else {
|
||||
@@ -67,16 +68,10 @@ void app_gtkmm_set_widget_tooltip(Gtk::Widget& widget,
|
||||
if (tooltips) {
|
||||
if (use_markup) {
|
||||
// strip markup
|
||||
gchar* stripped = 0;
|
||||
if (pango_parse_markup(tooltip_text.c_str(), -1, 0, NULL, &stripped, NULL, NULL) && stripped) {
|
||||
gtk_tooltips_set_tip(tooltips, widget.gobj(), stripped, "");
|
||||
Glib::ustring stripped;
|
||||
if (app_pango_strip_markup(tooltip_text, stripped)) {
|
||||
gtk_tooltips_set_tip(tooltips, widget.gobj(), stripped.c_str(), "");
|
||||
}
|
||||
g_free(stripped);
|
||||
|
||||
// alternate method, check if it works (AttrList has bool() since gtkmm 2.10):
|
||||
// char dummy = 0;
|
||||
// Glib::ustring stripped;
|
||||
// if (Pango::AttrList(tooltip_text, 0, stripped, dummy).gobj()) ...
|
||||
|
||||
} else {
|
||||
gtk_tooltips_set_tip(tooltips, widget.gobj(), tooltip_text.c_str(), "");
|
||||
@@ -112,7 +107,7 @@ void app_gtkmm_combobox_unset_model(Gtk::ComboBox* box)
|
||||
|
||||
|
||||
|
||||
#ifdef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -165,7 +160,7 @@ void gtkmm_set_treeview_tooltip_column(Gtk::TreeView* treeview,
|
||||
if (!treeview)
|
||||
return;
|
||||
|
||||
#ifndef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if !(defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS)
|
||||
treeview->set_tooltip_column(col_tooltip.index()); // gtkmm has only index-based api here
|
||||
|
||||
#else // manually set tooltips when hovering over cells
|
||||
@@ -182,7 +177,7 @@ void gtkmm_set_iconview_tooltip_column(Gtk::IconView* iconview,
|
||||
if (!iconview)
|
||||
return;
|
||||
|
||||
#ifndef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if !(defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS)
|
||||
iconview->set_tooltip_column(col_tooltip.index()); // gtkmm has only index-based api here
|
||||
|
||||
#else // manually set tooltips when hovering over cells
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
// Note: This works only if the column has custom widget set.
|
||||
Gtk::Widget* app_gtkmm_get_column_header(Gtk::TreeViewColumn& column);
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <pango/pango.h> // pango_parse_markup()
|
||||
|
||||
#include "app_pango_utils.h"
|
||||
|
||||
|
||||
|
||||
// Returns true if markup was successfully stripped
|
||||
bool app_pango_strip_markup(const Glib::ustring& str, Glib::ustring& stripped)
|
||||
{
|
||||
gchar* gstripped = 0;
|
||||
bool ok = false;
|
||||
if (pango_parse_markup(str.c_str(), -1, 0, NULL, &gstripped, NULL, NULL) && gstripped) {
|
||||
stripped = gstripped;
|
||||
ok = true;
|
||||
}
|
||||
g_free(gstripped);
|
||||
|
||||
// alternative method, check if it works (AttrList has bool() cast since gtkmm 2.10):
|
||||
// char dummy = 0;
|
||||
// if (Pango::AttrList(str, 0, stripped, dummy).gobj()) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool app_pango_strip_markup(const std::string& str, std::string& stripped)
|
||||
{
|
||||
gchar* gstripped = 0;
|
||||
bool ok = false;
|
||||
if (pango_parse_markup(str.c_str(), -1, 0, NULL, &gstripped, NULL, NULL) && gstripped) {
|
||||
stripped = gstripped;
|
||||
ok = true;
|
||||
}
|
||||
g_free(gstripped);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_PANGO_UTILS_H
|
||||
#define APP_PANGO_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <glibmm.h> // ustring
|
||||
|
||||
|
||||
|
||||
// strip markup of a string. returns true on success.
|
||||
bool app_pango_strip_markup(const Glib::ustring& str, Glib::ustring& stripped);
|
||||
|
||||
|
||||
bool app_pango_strip_markup(const std::string& str, std::string& stripped);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
|
||||
inline pcrecpp::RE_Options app_pcre_get_options(const char* modifiers)
|
||||
{
|
||||
// ANYCRLF means any of crlf, cr, lf. Used in ^ and $.
|
||||
// This overrides the build-time newline setting of pcre.
|
||||
#ifdef PCRE_NEWLINE_ANYCRLF
|
||||
pcrecpp::RE_Options options(PCRE_NEWLINE_ANYCRLF);
|
||||
#else
|
||||
pcrecpp::RE_Options options;
|
||||
#endif
|
||||
|
||||
if (modifiers) {
|
||||
char c = '\0';
|
||||
@@ -58,6 +64,8 @@ inline pcrecpp::RE_Options app_pcre_get_options(const char* modifiers)
|
||||
// Note: Slashes should be escaped within the pattern.
|
||||
// If the string doesn't start with a slash, it is treated as an ordinary pattern
|
||||
// without modifiers.
|
||||
// This function will make a RE object with ANYCRLF option set for portability
|
||||
// across various pcre builds.
|
||||
inline pcrecpp::RE app_pcre_re(const std::string& perl_pattern)
|
||||
{
|
||||
if (perl_pattern.size() >= 2 && perl_pattern[0] == '/') {
|
||||
@@ -71,7 +79,7 @@ inline pcrecpp::RE app_pcre_re(const std::string& perl_pattern)
|
||||
app_pcre_get_options(perl_pattern.substr(endpos + 1).c_str()));
|
||||
}
|
||||
|
||||
return pcrecpp::RE(perl_pattern);
|
||||
return pcrecpp::RE(perl_pattern, app_pcre_get_options(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +202,12 @@ inline bool app_pcre_replace_once(const pcrecpp::RE& re, const std::string& repl
|
||||
|
||||
|
||||
|
||||
// Escape a string to be used as a regular expression
|
||||
inline std::string app_pcre_escape(const std::string& str)
|
||||
{
|
||||
return pcrecpp::RE::QuoteMeta(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -12,19 +12,21 @@
|
||||
|
||||
#include "hz/hz_config.h" // feature test macros (ENABLE_*)
|
||||
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
#include <libglademm.h>
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
#include <gtkmm/builder.h>
|
||||
#endif
|
||||
|
||||
#if GLIBMM_EXCEPTIONS_ENABLED
|
||||
// Old glibmm versions had exceptions but didn't define this at all.
|
||||
// New ones define it to 0 if there are no glibmm exceptions.
|
||||
#if !defined GLIBMM_EXCEPTIONS_ENABLED || GLIBMM_EXCEPTIONS_ENABLED
|
||||
#include <memory> // std::auto_ptr
|
||||
#endif
|
||||
|
||||
#include "app_gtkmm_features.h" // APP_GTKMM_OLD_TOOLTIPS
|
||||
|
||||
#ifdef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS
|
||||
#include <gtk/gtk.h> // gtk_tooltips_*
|
||||
#endif
|
||||
|
||||
@@ -44,7 +46,7 @@
|
||||
// Or, if you're using compiled-in buffers, it will make them available.
|
||||
|
||||
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
|
||||
#define APP_UI_RES_DATA_INIT(res_name) \
|
||||
HZ_RES_DATA_INIT_NAMED(res_name##_ui, #res_name ".glade", UIResDataBase); \
|
||||
@@ -56,7 +58,7 @@
|
||||
}
|
||||
|
||||
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
|
||||
#define APP_UI_RES_DATA_INIT(res_name) \
|
||||
HZ_RES_DATA_INIT_NAMED(res_name##_ui, #res_name ".ui", UIResDataBase); \
|
||||
@@ -84,7 +86,7 @@
|
||||
|
||||
|
||||
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
|
||||
typedef Glib::RefPtr<Gnome::Glade::Xml> app_ui_res_ref_t;
|
||||
|
||||
@@ -97,7 +99,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
#if GLIBMM_EXCEPTIONS_ENABLED
|
||||
#if !defined GLIBMM_EXCEPTIONS_ENABLED || GLIBMM_EXCEPTIONS_ENABLED
|
||||
try {
|
||||
// Glib::RefPtr<Gnome::Glade::Xml> ref = Gnome::Glade::Xml::create("main_window.glade");
|
||||
ref = Gnome::Glade::Xml::create_from_buffer(reinterpret_cast<const char*>(buf),
|
||||
@@ -124,7 +126,7 @@
|
||||
}
|
||||
|
||||
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
|
||||
typedef Glib::RefPtr<Gtk::Builder> app_ui_res_ref_t;
|
||||
|
||||
@@ -137,7 +139,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
#if GLIBMM_EXCEPTIONS_ENABLED
|
||||
#if !defined GLIBMM_EXCEPTIONS_ENABLED || GLIBMM_EXCEPTIONS_ENABLED
|
||||
try {
|
||||
// ref->add_from_file("main_window.ui");
|
||||
ref->add_from_string(reinterpret_cast<const char*>(buf), static_cast<gsize>(buf_size));
|
||||
@@ -178,6 +180,8 @@
|
||||
inline bool app_ui_res_create_from(app_ui_res_ref_t& ref,
|
||||
const unsigned char* buf, unsigned int buf_size, std::string& error_msg)
|
||||
{
|
||||
error_msg = "Neither Gtk::Builder (gtkmm >= 2.12) nor libglademm were present during compilation."
|
||||
" Recompile when either dependency is resolved.";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -217,9 +221,9 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
|
||||
typedef hz::InstanceManager<Child, MultiInstance> instance_class;
|
||||
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
friend class Gnome::Glade::Xml; // allow construction through libglade
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
friend class Gtk::Builder; // allow construction through gtkbuilder
|
||||
#endif
|
||||
friend class hz::InstanceManager<Child, MultiInstance>; // allow construction through instance class
|
||||
@@ -232,9 +236,9 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
return hz::InstanceManager<Child, MultiInstance>::get_single_instance();
|
||||
|
||||
std::string error;
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
app_ui_res_ref_t ui;
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
app_ui_res_ref_t ui = Gtk::Builder::create();
|
||||
#else // none, just avoid compilation errors
|
||||
app_ui_res_ref_t ui = 0;
|
||||
@@ -299,9 +303,9 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
|
||||
Glib::Object* lookup_object(const Glib::ustring& name)
|
||||
{
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
return static_cast<Glib::Object*>(lookup_widget(name)); // all glade objects are widgets, it's an upcast
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
return ref_ui_->get_object(name).operator->(); // silly RefPtr doesn't have get().
|
||||
#else // none, just avoid compilation errors
|
||||
return 0;
|
||||
@@ -327,6 +331,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
|
||||
// This is needed by APP_GLADE_ macros
|
||||
typedef Child self_type;
|
||||
typedef WidgetType widget_type;
|
||||
|
||||
|
||||
// protected constructor / destructor, use create() / destroy() instead of new / delete.
|
||||
@@ -337,7 +342,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
: WidgetType(gtkcobj), ref_ui_(ref_ui)
|
||||
{
|
||||
// if gtkmm is older than 2.12, use the old tooltips API
|
||||
#ifdef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS
|
||||
// attach it to the window
|
||||
this->create_tooltips_data(this);
|
||||
#endif
|
||||
@@ -358,7 +363,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
{ }
|
||||
|
||||
|
||||
#ifdef APP_GTKMM_OLD_TOOLTIPS
|
||||
#if defined APP_GTKMM_OLD_TOOLTIPS && APP_GTKMM_OLD_TOOLTIPS
|
||||
// differentiate Window and its children from other widgets through overloading
|
||||
|
||||
void create_tooltips_data(Gtk::Window* window)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/window.h>
|
||||
#include <gtkmm/main.h>
|
||||
|
||||
#include "app_ui_res_utils.h"
|
||||
// #include "hz/instance_manager.h"
|
||||
|
||||
|
||||
|
||||
class AppUiResTestWindow;
|
||||
|
||||
// class AppUiResTestWindow : public Gtk::Window
|
||||
// class AppUiResTestWindow : public hz::InstanceManager<AppUiResTestWindow, false>, public Gtk::Window
|
||||
class AppUiResTestWindow : public AppUIResWidget<AppUiResTestWindow, false>
|
||||
{
|
||||
public:
|
||||
|
||||
// name of glade/ui file without a .glade/.ui extension and quotes
|
||||
APP_UI_RES_DATA_INIT(app_ui_res_test_window);
|
||||
|
||||
|
||||
enum action_t {
|
||||
action_quit
|
||||
};
|
||||
|
||||
// AppUiResTestWindow()
|
||||
AppUiResTestWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& ref_ui)
|
||||
: AppUIResWidget<AppUiResTestWindow, false>(gtkcobj, ref_ui)
|
||||
{
|
||||
Gtk::Box* vbox = Gtk::manage(new Gtk::VBox(false, 5));
|
||||
add(*vbox);
|
||||
|
||||
Gtk::Button* button = Gtk::manage(new Gtk::Button("Clicky"));
|
||||
vbox->pack_start(*button, Gtk::PACK_SHRINK);
|
||||
// button->signal_clicked().connect(sigc::mem_fun(*this, &AppUiResTestWindow::on_button_clicked));
|
||||
button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &AppUiResTestWindow::on_button_clicked2), action_quit));
|
||||
|
||||
|
||||
Gtk::Label* label = Gtk::manage(new Gtk::Label("test"));
|
||||
vbox->pack_start(*label, Gtk::PACK_SHRINK);
|
||||
|
||||
this->signal_delete_event().connect(sigc::mem_fun(*this, &AppUiResTestWindow::on_delete_event));
|
||||
|
||||
show_all();
|
||||
}
|
||||
|
||||
virtual ~AppUiResTestWindow()
|
||||
{ }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void on_button_clicked()
|
||||
{
|
||||
std::cerr << "AppUiResTestWindow::on_button_clicked()\n";
|
||||
}
|
||||
|
||||
void on_button_clicked2(action_t action_type)
|
||||
{
|
||||
std::cerr << "AppUiResTestWindow::on_button_clicked2()\n";
|
||||
}
|
||||
|
||||
bool on_delete_event(GdkEventAny* e)
|
||||
{
|
||||
Gtk::Main::quit();
|
||||
return true; // action handled
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Gtk::Main m(&argc, &argv);
|
||||
|
||||
// AppUiResTestWindow* app = new AppUiResTestWindow();
|
||||
AppUiResTestWindow::create();
|
||||
|
||||
m.run();
|
||||
|
||||
// delete app;
|
||||
AppUiResTestWindow::destroy();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "hz/hz_config.h" // feature test macros (ENABLE_*)
|
||||
|
||||
|
||||
// A simple empty window definition
|
||||
|
||||
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
|
||||
|
||||
|
||||
extern const unsigned char app_ui_res_test_window_ui[] = {
|
||||
|
||||
0x3C,
|
||||
0x3F,
|
||||
0x78,
|
||||
0x6D,
|
||||
0x6C,
|
||||
0x20,
|
||||
0x76,
|
||||
0x65,
|
||||
0x72,
|
||||
0x73,
|
||||
0x69,
|
||||
0x6F,
|
||||
0x6E,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x31,
|
||||
0x2E,
|
||||
0x30,
|
||||
0x22,
|
||||
0x20,
|
||||
0x65,
|
||||
0x6E,
|
||||
0x63,
|
||||
0x6F,
|
||||
0x64,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x67,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x55,
|
||||
0x54,
|
||||
0x46,
|
||||
0x2D,
|
||||
0x38,
|
||||
0x22,
|
||||
0x20,
|
||||
0x73,
|
||||
0x74,
|
||||
0x61,
|
||||
0x6E,
|
||||
0x64,
|
||||
0x61,
|
||||
0x6C,
|
||||
0x6F,
|
||||
0x6E,
|
||||
0x65,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x6E,
|
||||
0x6F,
|
||||
0x22,
|
||||
0x3F,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x3C,
|
||||
0x21,
|
||||
0x44,
|
||||
0x4F,
|
||||
0x43,
|
||||
0x54,
|
||||
0x59,
|
||||
0x50,
|
||||
0x45,
|
||||
0x20,
|
||||
0x67,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x64,
|
||||
0x65,
|
||||
0x2D,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x74,
|
||||
0x65,
|
||||
0x72,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x20,
|
||||
0x53,
|
||||
0x59,
|
||||
0x53,
|
||||
0x54,
|
||||
0x45,
|
||||
0x4D,
|
||||
0x20,
|
||||
0x22,
|
||||
0x67,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x64,
|
||||
0x65,
|
||||
0x2D,
|
||||
0x32,
|
||||
0x2E,
|
||||
0x30,
|
||||
0x2E,
|
||||
0x64,
|
||||
0x74,
|
||||
0x64,
|
||||
0x22,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x3C,
|
||||
0x67,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x64,
|
||||
0x65,
|
||||
0x2D,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x74,
|
||||
0x65,
|
||||
0x72,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x77,
|
||||
0x69,
|
||||
0x64,
|
||||
0x67,
|
||||
0x65,
|
||||
0x74,
|
||||
0x20,
|
||||
0x63,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x73,
|
||||
0x73,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x47,
|
||||
0x74,
|
||||
0x6B,
|
||||
0x57,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x64,
|
||||
0x6F,
|
||||
0x77,
|
||||
0x22,
|
||||
0x20,
|
||||
0x69,
|
||||
0x64,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x61,
|
||||
0x70,
|
||||
0x70,
|
||||
0x5F,
|
||||
0x75,
|
||||
0x69,
|
||||
0x5F,
|
||||
0x72,
|
||||
0x65,
|
||||
0x73,
|
||||
0x5F,
|
||||
0x74,
|
||||
0x65,
|
||||
0x73,
|
||||
0x74,
|
||||
0x5F,
|
||||
0x77,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x64,
|
||||
0x6F,
|
||||
0x77,
|
||||
0x22,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x70,
|
||||
0x72,
|
||||
0x6F,
|
||||
0x70,
|
||||
0x65,
|
||||
0x72,
|
||||
0x74,
|
||||
0x79,
|
||||
0x20,
|
||||
0x6E,
|
||||
0x61,
|
||||
0x6D,
|
||||
0x65,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x74,
|
||||
0x69,
|
||||
0x74,
|
||||
0x6C,
|
||||
0x65,
|
||||
0x22,
|
||||
0x20,
|
||||
0x74,
|
||||
0x72,
|
||||
0x61,
|
||||
0x6E,
|
||||
0x73,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x74,
|
||||
0x61,
|
||||
0x62,
|
||||
0x6C,
|
||||
0x65,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x79,
|
||||
0x65,
|
||||
0x73,
|
||||
0x22,
|
||||
0x3E,
|
||||
0x54,
|
||||
0x65,
|
||||
0x73,
|
||||
0x74,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x70,
|
||||
0x72,
|
||||
0x6F,
|
||||
0x70,
|
||||
0x65,
|
||||
0x72,
|
||||
0x74,
|
||||
0x79,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x63,
|
||||
0x68,
|
||||
0x69,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x70,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x68,
|
||||
0x6F,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x65,
|
||||
0x72,
|
||||
0x2F,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x63,
|
||||
0x68,
|
||||
0x69,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x77,
|
||||
0x69,
|
||||
0x64,
|
||||
0x67,
|
||||
0x65,
|
||||
0x74,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x67,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x64,
|
||||
0x65,
|
||||
0x2D,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x74,
|
||||
0x65,
|
||||
0x72,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x3E,
|
||||
0xA,
|
||||
|
||||
0x0 };
|
||||
|
||||
extern const unsigned int app_ui_res_test_window_ui_size = 319;
|
||||
|
||||
|
||||
|
||||
|
||||
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
|
||||
|
||||
|
||||
extern const unsigned char app_ui_res_test_window_ui[] = {
|
||||
|
||||
0x3C,
|
||||
0x3F,
|
||||
0x78,
|
||||
0x6D,
|
||||
0x6C,
|
||||
0x20,
|
||||
0x76,
|
||||
0x65,
|
||||
0x72,
|
||||
0x73,
|
||||
0x69,
|
||||
0x6F,
|
||||
0x6E,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x31,
|
||||
0x2E,
|
||||
0x30,
|
||||
0x22,
|
||||
0x3F,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x3C,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x74,
|
||||
0x65,
|
||||
0x72,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x6F,
|
||||
0x62,
|
||||
0x6A,
|
||||
0x65,
|
||||
0x63,
|
||||
0x74,
|
||||
0x20,
|
||||
0x63,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x73,
|
||||
0x73,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x47,
|
||||
0x74,
|
||||
0x6B,
|
||||
0x57,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x64,
|
||||
0x6F,
|
||||
0x77,
|
||||
0x22,
|
||||
0x20,
|
||||
0x69,
|
||||
0x64,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x61,
|
||||
0x70,
|
||||
0x70,
|
||||
0x5F,
|
||||
0x75,
|
||||
0x69,
|
||||
0x5F,
|
||||
0x72,
|
||||
0x65,
|
||||
0x73,
|
||||
0x5F,
|
||||
0x74,
|
||||
0x65,
|
||||
0x73,
|
||||
0x74,
|
||||
0x5F,
|
||||
0x77,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x64,
|
||||
0x6F,
|
||||
0x77,
|
||||
0x22,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x70,
|
||||
0x72,
|
||||
0x6F,
|
||||
0x70,
|
||||
0x65,
|
||||
0x72,
|
||||
0x74,
|
||||
0x79,
|
||||
0x20,
|
||||
0x6E,
|
||||
0x61,
|
||||
0x6D,
|
||||
0x65,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x74,
|
||||
0x69,
|
||||
0x74,
|
||||
0x6C,
|
||||
0x65,
|
||||
0x22,
|
||||
0x20,
|
||||
0x74,
|
||||
0x72,
|
||||
0x61,
|
||||
0x6E,
|
||||
0x73,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x74,
|
||||
0x61,
|
||||
0x62,
|
||||
0x6C,
|
||||
0x65,
|
||||
0x3D,
|
||||
0x22,
|
||||
0x79,
|
||||
0x65,
|
||||
0x73,
|
||||
0x22,
|
||||
0x3E,
|
||||
0x54,
|
||||
0x65,
|
||||
0x73,
|
||||
0x74,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x70,
|
||||
0x72,
|
||||
0x6F,
|
||||
0x70,
|
||||
0x65,
|
||||
0x72,
|
||||
0x74,
|
||||
0x79,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x63,
|
||||
0x68,
|
||||
0x69,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x70,
|
||||
0x6C,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x68,
|
||||
0x6F,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x65,
|
||||
0x72,
|
||||
0x2F,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x63,
|
||||
0x68,
|
||||
0x69,
|
||||
0x6C,
|
||||
0x64,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x20,
|
||||
0x20,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x6F,
|
||||
0x62,
|
||||
0x6A,
|
||||
0x65,
|
||||
0x63,
|
||||
0x74,
|
||||
0x3E,
|
||||
0xA,
|
||||
0x3C,
|
||||
0x2F,
|
||||
0x69,
|
||||
0x6E,
|
||||
0x74,
|
||||
0x65,
|
||||
0x72,
|
||||
0x66,
|
||||
0x61,
|
||||
0x63,
|
||||
0x65,
|
||||
0x3E,
|
||||
0xA,
|
||||
|
||||
0x0 };
|
||||
|
||||
extern const unsigned int app_ui_res_test_window_ui_size = 224;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+99
-244
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -14,15 +14,17 @@
|
||||
// #include <unistd.h> // close()
|
||||
#endif
|
||||
|
||||
#include "hz/process_signal.h" // hz::process_signal_send, win32's W*
|
||||
#include "hz/tls.h"
|
||||
#include "hz/tls_policy_glib.h"
|
||||
#include "hz/debug.h"
|
||||
#include "hz/string_num.h" // hz::number_to_string()
|
||||
#include "hz/env_tools.h" // hz::ScopedEnv
|
||||
#include "hz/scoped_ptr.h"
|
||||
|
||||
#include "cmdex.h"
|
||||
|
||||
|
||||
|
||||
using hz::Error;
|
||||
using hz::ErrorLevel;
|
||||
|
||||
@@ -36,41 +38,24 @@ extern "C" {
|
||||
// callbacks
|
||||
|
||||
|
||||
// NOTE: These functions are called in a separate threads!
|
||||
|
||||
inline void cmdex_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data)
|
||||
{
|
||||
Cmdex::on_child_watch_handler(arg_pid, waitpid_status, data);
|
||||
}
|
||||
|
||||
|
||||
inline gboolean cmdex_on_channel_io_stdout_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stdout(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_as_available(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stdout);
|
||||
return Cmdex::on_channel_io(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stdout);
|
||||
}
|
||||
|
||||
inline gboolean cmdex_on_channel_io_stderr_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stderr(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_as_available(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stderr);
|
||||
return Cmdex::on_channel_io(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stderr);
|
||||
}
|
||||
|
||||
|
||||
inline gboolean cmdex_on_channel_io_stdout_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_buffered(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stdout);
|
||||
}
|
||||
|
||||
inline gboolean cmdex_on_channel_io_stderr_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_buffered(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stderr);
|
||||
}
|
||||
|
||||
|
||||
inline void cmdex_on_buffered_source_destroy(gpointer data);
|
||||
|
||||
|
||||
|
||||
// this is executed in another thread!
|
||||
inline gboolean cmdex_on_term_timeout(gpointer data)
|
||||
{
|
||||
DBG_FUNCTION_ENTER_MSG;
|
||||
@@ -80,7 +65,6 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
// this is executed in another thread!
|
||||
inline gboolean cmdex_on_kill_timeout(gpointer data)
|
||||
{
|
||||
DBG_FUNCTION_ENTER_MSG;
|
||||
@@ -99,13 +83,11 @@ extern "C" {
|
||||
|
||||
bool Cmdex::execute()
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
|
||||
if (this->running_ || this->stopped_cleanup_needed(false))
|
||||
if (this->running_ || this->stopped_cleanup_needed())
|
||||
return false;
|
||||
|
||||
cleanup_members();
|
||||
clear_errors(false); // don't lock
|
||||
clear_errors();
|
||||
str_stdout_.clear();
|
||||
str_stderr_.clear();
|
||||
|
||||
@@ -115,77 +97,98 @@ bool Cmdex::execute()
|
||||
|
||||
// Make command vector
|
||||
|
||||
int argcp = 0; // number of args
|
||||
gchar** argvp = 0; // args vector
|
||||
GError* shell_error = 0;
|
||||
if (!g_shell_parse_argv(cmd.c_str(), &argcp, &argvp, &shell_error)) {
|
||||
push_error(Error<void>("gshell", ErrorLevel::error, shell_error->message), false);
|
||||
g_error_free(shell_error);
|
||||
hz::scoped_ptr<gchar*> argvp(0, g_strfreev); // args vector
|
||||
|
||||
g_strfreev(argvp);
|
||||
return false;
|
||||
{
|
||||
int argcp = 0; // number of args
|
||||
hz::scoped_ptr<GError> shell_error(0, g_error_free);
|
||||
if (!g_shell_parse_argv(cmd.c_str(), &argcp, &argvp.get_ref(), &shell_error.get_ref())) {
|
||||
push_error(Error<void>("gshell", ErrorLevel::error, shell_error->message), false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Reset the locale - otherwise it may mangle the output.
|
||||
|
||||
// Set the locale for a child to Classic - otherwise it may mangle the output.
|
||||
// TODO: make this controllable.
|
||||
const gchar* old_lang_gchar = g_getenv("LANG");
|
||||
bool old_lang_set = (old_lang_gchar);
|
||||
std::string old_lang = (old_lang_gchar ? old_lang_gchar : "");
|
||||
if (old_lang_set)
|
||||
g_setenv("LANG", "C", true);
|
||||
bool change_lang = true;
|
||||
#ifdef _WIN32
|
||||
// LANG is posix-only, so it has no effect on win32.
|
||||
// Unfortunately, I was unable to find a way to execute a child with a different
|
||||
// locale in win32. Locale seems to be non-inheritable, so setting it here won't help.
|
||||
change_lang = false;
|
||||
#endif
|
||||
|
||||
hz::ScopedEnv lang_env("LANG", "C", change_lang);
|
||||
|
||||
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Executing \"" << cmd << "\".\n");
|
||||
|
||||
|
||||
/*
|
||||
if (argvp) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Dumping argvp:\n");
|
||||
gchar** elem = argvp.get();
|
||||
while (*elem) {
|
||||
debug_out_dump("app", *elem << "\n");
|
||||
++elem;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Execute the command
|
||||
|
||||
gchar* curr_dir = g_get_current_dir();
|
||||
GError* spawn_error = 0;
|
||||
hz::scoped_ptr<gchar> curr_dir(g_get_current_dir(), g_free);
|
||||
hz::scoped_ptr<GError> spawn_error(0, g_error_free);
|
||||
|
||||
if (!g_spawn_async_with_pipes(curr_dir, argvp, NULL,
|
||||
GSpawnFlags(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD),
|
||||
NULL, NULL, // child setup function
|
||||
&this->pid_, 0, &fd_stdout_, &fd_stderr_, &spawn_error)) {
|
||||
|
||||
push_error(Error<void>("gspawn", ErrorLevel::error, spawn_error->message), false);
|
||||
g_error_free(spawn_error);
|
||||
|
||||
g_free(curr_dir);
|
||||
g_strfreev(argvp);
|
||||
|
||||
if (old_lang_set)
|
||||
g_setenv("LANG", old_lang.c_str(), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_free(curr_dir);
|
||||
g_strfreev(argvp);
|
||||
|
||||
if (old_lang_set)
|
||||
g_setenv("LANG", old_lang.c_str(), true);
|
||||
/*
|
||||
#if defined APP_CMDEX_USE_SYNC && APP_CMDEX_USE_SYNC
|
||||
|
||||
hz::scoped_ptr<gchar*> stdout_str(0, g_free);
|
||||
hz::scoped_ptr<gchar*> stderr_str(0, g_free);
|
||||
gint exit_status = 0;
|
||||
|
||||
g_timer_start(timer_); // start the timer
|
||||
|
||||
if (!g_spawn_sync(curr_dir.get(), argvp.get(), NULL,
|
||||
GSpawnFlags(G_SPAWN_SEARCH_PATH),
|
||||
NULL, NULL, // child setup function
|
||||
&stdout_str.get_ref(), &stderr_str.get_ref(), &exit_status, &spawn_error.get_ref()))
|
||||
{
|
||||
// no data is returned to &-parameters on error.
|
||||
push_error(Error<void>("gspawn", ErrorLevel::error, spawn_error->message), false);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
channel_stdout_ = g_io_channel_win32_new_fd(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_win32_new_fd(fd_stderr_);
|
||||
#else
|
||||
channel_stdout_ = g_io_channel_unix_new(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_unix_new(fd_stderr_);
|
||||
#endif
|
||||
#else // async way:
|
||||
*/
|
||||
if (!g_spawn_async_with_pipes(curr_dir.get(), argvp.get(), NULL,
|
||||
GSpawnFlags(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD),
|
||||
NULL, NULL, // child setup function
|
||||
&this->pid_, 0, &fd_stdout_, &fd_stderr_, &spawn_error.get_ref()))
|
||||
{
|
||||
// no data is returned to &-parameters on error.
|
||||
push_error(Error<void>("gspawn", ErrorLevel::error, spawn_error->message), false);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_timer_start(timer_); // start the timer
|
||||
|
||||
// #endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
channel_stdout_ = g_io_channel_win32_new_fd(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_win32_new_fd(fd_stderr_);
|
||||
#else
|
||||
channel_stdout_ = g_io_channel_unix_new(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_unix_new(fd_stderr_);
|
||||
#endif
|
||||
|
||||
// The internal encoding is always UTF8. To read command output correctly, use
|
||||
// "" for binary data, or set io encoding to current locale.
|
||||
// If using locales, call g_locale_to_utf8() or g_convert() afterwards.
|
||||
|
||||
// blocking writes if the pipe is full helps for small-pipe systems (see man 7 pipe).
|
||||
GIOFlags channel_flags = GIOFlags(~G_IO_FLAG_NONBLOCK);
|
||||
int channel_flags = ~G_IO_FLAG_NONBLOCK;
|
||||
|
||||
// Note about GError's here:
|
||||
// What do we do? The command is already running, so let's ignore these
|
||||
@@ -196,55 +199,35 @@ bool Cmdex::execute()
|
||||
// a double-shutdown.
|
||||
// g_io_channel_set_close_on_unref(channel_stdout_, true); // close() on fd
|
||||
g_io_channel_set_encoding(channel_stdout_, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stdout_, channel_flags, 0);
|
||||
g_io_channel_set_flags(channel_stdout_, GIOFlags(g_io_channel_get_flags(channel_stdout_) & channel_flags), 0);
|
||||
g_io_channel_set_buffer_size(channel_stdout_, channel_stdout_buffer_size_);
|
||||
}
|
||||
if (channel_stderr_) {
|
||||
// g_io_channel_set_close_on_unref(channel_stderr_, true); // close() on fd
|
||||
g_io_channel_set_encoding(channel_stderr_, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stderr_, channel_flags, 0);
|
||||
g_io_channel_set_flags(channel_stderr_, GIOFlags(g_io_channel_get_flags(channel_stderr_) & channel_flags), 0);
|
||||
g_io_channel_set_buffer_size(channel_stderr_, channel_stderr_buffer_size_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Note: glib callbacks _are_ invoked in separate threads,
|
||||
// so proper locking is necessary.
|
||||
// This is different from gtk callbacks, which are directly invoked from main loop
|
||||
// in the same thread.
|
||||
|
||||
GIOCondition cond = GIOCondition(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL);
|
||||
gint io_thread_priority = G_PRIORITY_HIGH; // channel reader callback thread must read enough so that the loss is minimal
|
||||
// Channel reader callback must be called before other stuff so that the loss is minimal.
|
||||
gint io_priority = G_PRIORITY_HIGH;
|
||||
|
||||
if (this->stdout_make_str_as_available_) {
|
||||
this->event_source_id_stdout_ = g_io_add_watch_full(channel_stdout_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stdout_as_available, this, NULL);
|
||||
} else {
|
||||
this->event_source_id_stdout_ = g_io_add_watch_full(channel_stdout_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stdout_buffered, this, cmdex_on_buffered_source_destroy);
|
||||
}
|
||||
this->event_source_id_stdout_ = g_io_add_watch_full(channel_stdout_, io_priority, cond,
|
||||
&cmdex_on_channel_io_stdout, this, NULL);
|
||||
|
||||
if (this->stderr_make_str_as_available_) {
|
||||
this->event_source_id_stderr_ = g_io_add_watch_full(channel_stderr_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stderr_as_available, this, NULL);
|
||||
} else {
|
||||
this->event_source_id_stderr_ = g_io_add_watch_full(channel_stderr_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stderr_buffered, this, cmdex_on_buffered_source_destroy);
|
||||
}
|
||||
this->event_source_id_stderr_ = g_io_add_watch_full(channel_stderr_, io_priority, cond,
|
||||
&cmdex_on_channel_io_stderr, this, NULL);
|
||||
|
||||
|
||||
// If using SPAWN_DO_NOT_REAP_CHILD, this is needed to avoid zombies.
|
||||
// Note: Do NOT use glibmm slot, it doesn't work here.
|
||||
// The watch function is protected by mutex and won't be called before execute() exits.
|
||||
// This is AFTER the channels so that it doesn't get called before the channels are attached (is this needed?).
|
||||
// (the child stops being a zombie as soon as wait*() exits and this handler is called).
|
||||
g_child_watch_add(this->pid_, &cmdex_child_watch_handler, this);
|
||||
|
||||
|
||||
|
||||
this->running_ = true; // process is running now.
|
||||
// actually, it may be already stopped, but the watcher function is blocked
|
||||
// until we exit, so the actions are serialized.
|
||||
this->running_ = true; // the process is running now.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -255,8 +238,6 @@ bool Cmdex::execute()
|
||||
// send SIGTERM(15) (terminate)
|
||||
bool Cmdex::try_stop(hz::signal_t sig)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
|
||||
if (!this->running_ || this->pid_ <= 0)
|
||||
return false;
|
||||
|
||||
@@ -281,12 +262,11 @@ bool Cmdex::try_stop(hz::signal_t sig)
|
||||
void Cmdex::set_stop_timeouts(int term_timeout_msec, int kill_timeout_msec)
|
||||
{
|
||||
DBG_ASSERT(term_timeout_msec == 0 || kill_timeout_msec == 0 || kill_timeout_msec > term_timeout_msec);
|
||||
ScopedLock locker(object_mutex_); // member access / serialization lock
|
||||
|
||||
if (!this->running_) // process not running
|
||||
return;
|
||||
|
||||
unset_stop_timeouts(false);
|
||||
unset_stop_timeouts();
|
||||
|
||||
if (term_timeout_msec != 0)
|
||||
event_source_id_term = g_timeout_add(term_timeout_msec, &cmdex_on_term_timeout, this);
|
||||
@@ -298,10 +278,8 @@ void Cmdex::set_stop_timeouts(int term_timeout_msec, int kill_timeout_msec)
|
||||
|
||||
|
||||
|
||||
void Cmdex::unset_stop_timeouts(bool do_lock)
|
||||
void Cmdex::unset_stop_timeouts()
|
||||
{
|
||||
ScopedLock locker(object_mutex_, do_lock); // member access / serialization lock
|
||||
|
||||
if (event_source_id_term) {
|
||||
GSource* source_term = g_main_context_find_source_by_id(NULL, event_source_id_term);
|
||||
if (source_term)
|
||||
@@ -323,14 +301,12 @@ void Cmdex::unset_stop_timeouts(bool do_lock)
|
||||
void Cmdex::stopped_cleanup()
|
||||
{
|
||||
// DBG_FUNCTION_ENTER_MSG;
|
||||
ScopedLock locker(object_mutex_); // member access / serialization lock
|
||||
|
||||
if (this->running_ || !this->stopped_cleanup_needed(false)) // huh?
|
||||
if (this->running_ || !this->stopped_cleanup_needed()) // huh?
|
||||
return;
|
||||
|
||||
// remove stop timeout callbacks
|
||||
unset_stop_timeouts(false);
|
||||
|
||||
unset_stop_timeouts();
|
||||
|
||||
// various statuses (see waitpid (2)):
|
||||
if (WIFEXITED(waitpid_status_)) { // exited normally
|
||||
@@ -368,29 +344,19 @@ void Cmdex::stopped_cleanup()
|
||||
|
||||
|
||||
|
||||
// NOTE: This function is called in a separate thread!
|
||||
// Called when child exits
|
||||
void Cmdex::on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data)
|
||||
{
|
||||
// DBG_FUNCTION_ENTER_MSG;
|
||||
Cmdex* self = static_cast<Cmdex*>(data);
|
||||
|
||||
self->lock();
|
||||
|
||||
g_timer_stop(self->timer_); // stop the timer
|
||||
|
||||
// wait until the IO channels are closed
|
||||
// while (!(self->event_source_stdout_closed && self->event_source_stderr_closed)) {
|
||||
// self->unlock();
|
||||
// g_usleep(75*1000); // 75ms
|
||||
// self->lock();
|
||||
// }
|
||||
|
||||
self->waitpid_status_ = waitpid_status;
|
||||
self->child_watch_handler_called_ = true;
|
||||
self->running_ = false; // process is not running anymore
|
||||
|
||||
|
||||
// Remove fd IO callbacks. They may actually be removed already.
|
||||
// Remove fd IO callbacks. They may actually be removed already (note sure about this).
|
||||
// This will force calling the iochannel callback (they may not be called
|
||||
// otherwise at all if there was no output).
|
||||
if (self->event_source_id_stdout_) {
|
||||
@@ -410,13 +376,9 @@ void Cmdex::on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer da
|
||||
// close(self->fd_stdout_);
|
||||
// close(self->fd_stderr_);
|
||||
|
||||
|
||||
// Note: This callback is called in non-main thread!
|
||||
if (self->exited_callback_)
|
||||
self->exited_callback_(self->exited_callback_data_);
|
||||
|
||||
|
||||
self->unlock();
|
||||
// DBG_FUNCTION_EXIT_MSG;
|
||||
}
|
||||
|
||||
@@ -424,13 +386,10 @@ void Cmdex::on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer da
|
||||
|
||||
|
||||
|
||||
|
||||
// NOTE: This function is called in a separate thread!
|
||||
// This means that all data access must be guarded by mutexes, etc...
|
||||
gboolean Cmdex::on_channel_io_as_available(GIOChannel* source,
|
||||
gboolean Cmdex::on_channel_io(GIOChannel* source,
|
||||
GIOCondition cond, Cmdex* self, channel_t type)
|
||||
{
|
||||
// debug_out_dump("app", "Cmdex::on_channel_io_as_available("
|
||||
// debug_out_dump("app", "Cmdex::on_channel_io("
|
||||
// << (type == channel_type_stdout ? "STDOUT" : "STDERR") << ") " << int(cond) << "\n");
|
||||
|
||||
bool continue_events = true;
|
||||
@@ -446,8 +405,6 @@ gboolean Cmdex::on_channel_io_as_available(GIOChannel* source,
|
||||
const gsize count = 1;
|
||||
gchar buf[count] = {0};
|
||||
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
|
||||
GIOChannel* channel = 0;
|
||||
std::string* output_str = 0;
|
||||
if (type == channel_type_stdout) {
|
||||
@@ -459,12 +416,11 @@ gboolean Cmdex::on_channel_io_as_available(GIOChannel* source,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// while there's anything to read, read it
|
||||
do {
|
||||
GError* channel_error = 0;
|
||||
hz::scoped_ptr<GError> channel_error(0, g_error_free);
|
||||
gsize bytes_read = 0;
|
||||
GIOStatus status = g_io_channel_read_chars(channel, buf, count, &bytes_read, &channel_error);
|
||||
GIOStatus status = g_io_channel_read_chars(channel, buf, count, &bytes_read, &channel_error.get_ref());
|
||||
if (bytes_read)
|
||||
output_str->append(buf, bytes_read);
|
||||
|
||||
@@ -480,107 +436,6 @@ gboolean Cmdex::on_channel_io_as_available(GIOChannel* source,
|
||||
}
|
||||
} while (g_io_channel_get_buffer_condition(channel) & G_IO_IN);
|
||||
|
||||
|
||||
// false if the source should be removed, true otherwise.
|
||||
return continue_events;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// this must be thread-local, because many instances of Cmdex may call this
|
||||
// from various threads. stdout and stderr are in different threads, so they won't get mixed.
|
||||
// there's one-channel-per-thread situation here, so thread-local works well.
|
||||
|
||||
static hz::thread_local_ptr<std::string, hz::TlsPolicyGlib> s_final_str;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The problem with final_str is that it may acummulate data if this function
|
||||
// is never called with (continue_events = false) condition. This may
|
||||
// actually happen with terminated spawned programs.
|
||||
// So, we clean final_str manually from source_destroy callback.
|
||||
// This callback is executed from in the same thread as on_channel_io_buffered,
|
||||
// so we get the same variable (tests show cleared s_final_str, but is this really
|
||||
// so? this function is executed during on_child_watch_handler (if spawn-terminated)).
|
||||
inline void cmdex_on_buffered_source_destroy(gpointer data)
|
||||
{
|
||||
// DBG_FUNCTION_ENTER_MSG;
|
||||
s_final_str.reset(); // .reset(), not ->clear - we don't want memory leaks in stopped threads.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// NOTE: This function is called in a separate thread!
|
||||
// This means that all data access must be guarded by mutexes, etc...
|
||||
gboolean Cmdex::on_channel_io_buffered(GIOChannel* source,
|
||||
GIOCondition cond, Cmdex* self, channel_t type)
|
||||
{
|
||||
// debug_out_dump("app", "Cmdex::on_channel_io_buffered("
|
||||
// << (type == channel_type_stdout ? "STDOUT" : "STDERR") << ") " << int(cond) << "\n");
|
||||
|
||||
bool continue_events = true;
|
||||
if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
|
||||
continue_events = false; // there'll be no more data
|
||||
}
|
||||
|
||||
if (!s_final_str.get()) {
|
||||
s_final_str.reset(new std::string);
|
||||
s_final_str->reserve(g_io_channel_get_buffer_size(source));
|
||||
}
|
||||
|
||||
// const gsize count = 4 * 1024;
|
||||
// read the bytes one by one. without this, a buffered iochannel hangs while waiting for data.
|
||||
// we don't use unbuffered iochannels - they may lose data on program exit.
|
||||
const gsize count = 1;
|
||||
static char buf[count] = {0};
|
||||
|
||||
// while there's anything to read, read it
|
||||
do {
|
||||
GError* channel_error = 0;
|
||||
gsize bytes_read = 0;
|
||||
GIOStatus status = g_io_channel_read_chars(source, buf, count, &bytes_read, &channel_error);
|
||||
if (bytes_read)
|
||||
s_final_str->append(buf, bytes_read);
|
||||
|
||||
if (channel_error) {
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
self->push_error(Error<void>("giochannel", ErrorLevel::error, channel_error->message), false);
|
||||
break; // stop on next invocation (is this correct?)
|
||||
}
|
||||
|
||||
// IO_STATUS_NORMAL and IO_STATUS_AGAIN (resource unavailable) are continuable.
|
||||
if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
|
||||
continue_events = false;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (g_io_channel_get_buffer_condition(source) & G_IO_IN);
|
||||
|
||||
|
||||
if (!continue_events) { // need locking
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
|
||||
if (type == channel_type_stdout) {
|
||||
// set the source to be closed (the actual closing is done when we return false).
|
||||
// this is needed for the caller to wait until all the channels are stopped.
|
||||
self->str_stdout_ = *s_final_str;
|
||||
|
||||
} else if (type == channel_type_stderr) {
|
||||
self->str_stderr_ = *s_final_str;
|
||||
}
|
||||
|
||||
// glib may re-use this thread, so do a TLS cleanup.
|
||||
// also, manual cleanup is needed for policies which don't support automatic one.
|
||||
// source_destroy callback already does this, but it won't hurt.
|
||||
s_final_str.reset(); // this will delete the previous contents.
|
||||
}
|
||||
|
||||
// DBG_FUNCTION_EXIT_MSG;
|
||||
|
||||
// false if the source should be removed, true otherwise.
|
||||
|
||||
+22
-97
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -10,41 +10,34 @@
|
||||
#include <string>
|
||||
#include <glib.h>
|
||||
|
||||
#include "hz/process_signal.h" // hz::SIGNAL_*, hz::process_signal_send (cpp), win32's W* (cpp)
|
||||
#include "hz/process_signal.h" // hz::SIGNAL_*
|
||||
#include "hz/error_holder.h"
|
||||
#include "hz/sync.h"
|
||||
#include "hz/sync_policy_glib.h"
|
||||
#include "hz/sync.h" // hz::SyncPolicyNone
|
||||
|
||||
|
||||
|
||||
/*
|
||||
There are two ways to detect when the command exits:
|
||||
|
||||
1. Add a callback to signal_exited. The callback will be executed
|
||||
in non-main thread, which means that all data access MUST be
|
||||
very carefully evaluated (and locked in both threads).
|
||||
1. Add a callback to signal_exited.
|
||||
|
||||
2. Manually poll stopped_cleanup_needed() from the main thread.
|
||||
2. Manually poll stopped_cleanup_needed() (from the same thread).
|
||||
|
||||
In both cases, stopped_cleanup() must be called afterwards,
|
||||
from the _main_ thread.
|
||||
In both cases, stopped_cleanup() must be called afterwards
|
||||
(from the main thread).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// inheriting from sigc::trackable automatically disconnects this class's
|
||||
// slots upon destruction.
|
||||
class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
class Cmdex : public hz::ErrorHolder<hz::SyncPolicyNone> {
|
||||
|
||||
public:
|
||||
|
||||
using hz::ErrorHolder<hz::SyncPolicyGlib>::ptr_error_list_t; // auto-deleting container
|
||||
using hz::ErrorHolder<hz::SyncPolicyGlib>::error_list_t;
|
||||
|
||||
typedef hz::ErrorHolder<hz::SyncPolicyGlib>::ErrorScopedLock ScopedLock;
|
||||
typedef hz::ErrorHolder<hz::SyncPolicyGlib>::ErrorLockPolicy LockPolicy;
|
||||
using hz::ErrorHolder<hz::SyncPolicyNone>::ptr_error_list_t; // auto-deleting container
|
||||
using hz::ErrorHolder<hz::SyncPolicyNone>::error_list_t;
|
||||
|
||||
typedef std::string (*exit_status_translator_func_t)(int, void*);
|
||||
typedef void (*exited_callback_func_t)(void*);
|
||||
@@ -54,15 +47,13 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
// exit_status_translator_func_t translator_func,
|
||||
exited_callback_func_t exited_cb = NULL, void* exited_cb_data = NULL
|
||||
)
|
||||
: object_mutex_(error_object_mutex_),
|
||||
running_(false), kill_signal_sent_(0), child_watch_handler_called_(false),
|
||||
: running_(false), kill_signal_sent_(0), child_watch_handler_called_(false),
|
||||
pid_(0), waitpid_status_(0),
|
||||
timer_(g_timer_new()),
|
||||
event_source_id_term(0), event_source_id_kill(0),
|
||||
fd_stdout_(0), fd_stderr_(0), channel_stdout_(0), channel_stderr_(0),
|
||||
channel_stdout_buffer_size_(100 * 1024), channel_stderr_buffer_size_(10 * 1024), // 100K and 10K
|
||||
event_source_id_stdout_(0), event_source_id_stderr_(0),
|
||||
stdout_make_str_as_available_(false), stderr_make_str_as_available_(true),
|
||||
translator_func_(0), translator_func_data_(0),
|
||||
exited_callback_(exited_cb), exited_callback_data_(exited_cb_data)
|
||||
{ }
|
||||
@@ -85,6 +76,9 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
|
||||
// Call before execute.
|
||||
// Note: The command and the arguments _must_ be shell-escaped.
|
||||
// Use g_shell_quote() or Glib::shell_quote(). Note that each argument
|
||||
// must be escaped separately.
|
||||
void set_command(const std::string& command_exec, const std::string& command_args)
|
||||
{
|
||||
command_exec_ = command_exec;
|
||||
@@ -116,9 +110,7 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
// Unset timeouts. This will stop the timeout counters.
|
||||
// This has an effect only if the command is running (after execute()).
|
||||
// do_lock is kind of private and indicates that mutex should be locked prior to
|
||||
// accessing the object members.
|
||||
void unset_stop_timeouts(bool do_lock = true);
|
||||
void unset_stop_timeouts();
|
||||
|
||||
|
||||
// If stopped_cleanup_needed() returned true, call this. The command
|
||||
@@ -128,10 +120,8 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
// Returns true if command has stopped.
|
||||
// Call repeatedly in a waiting function, after execute(). When returns true, call stopped_cleanup().
|
||||
// do_lock is private, set to false only if you already hold the object lock.
|
||||
bool stopped_cleanup_needed(bool do_lock = true)
|
||||
bool stopped_cleanup_needed()
|
||||
{
|
||||
ScopedLock locker(object_mutex_, do_lock);
|
||||
return (child_watch_handler_called_);
|
||||
}
|
||||
|
||||
@@ -141,7 +131,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
// stopped_cleanup_needed() instead.
|
||||
bool is_running() const
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
return running_;
|
||||
}
|
||||
|
||||
@@ -149,20 +138,19 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
// Call this before execution. There is a race-like condition - when the command
|
||||
// outputs something, the io channel reads it from fd to its buffer and the event
|
||||
// source callback is called. If the command dies, the io channel thread reads
|
||||
// source callback is called. If the command dies, the io channel callback reads
|
||||
// the remaining data to the channel buffer.
|
||||
// Since the event source callbacks (which read from the buffer and empty it)
|
||||
// happen rather sporadically in another thread, the buffer may not get read and
|
||||
// happen rather sporadically (from the glib loop), the buffer may not get read and
|
||||
// emptied at all (before the command exits). This is why it's necessary to have
|
||||
// a buffer size which potentially can hold _all_ the command output.
|
||||
// A way to fight this is to increase event source thread priority (which may not help).
|
||||
// Another way is to delay the command exit so that the event source thread
|
||||
// A way to fight this is to increase event source priority (which may not help).
|
||||
// Another way is to delay the command exit so that the event source callback
|
||||
// catches on and reads the buffer.
|
||||
|
||||
// Use 0 to ignore the parameter. Call before execute().
|
||||
void set_buffer_sizes(int stdout_buffer_size = 0, int stderr_buffer_size = 0)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
if (stdout_buffer_size)
|
||||
channel_stdout_buffer_size_ = stdout_buffer_size; // 100K by default
|
||||
if (stderr_buffer_size)
|
||||
@@ -170,29 +158,12 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
}
|
||||
|
||||
|
||||
// Set the flags for child stdout and stderr. If stdout_str_as_available is true,
|
||||
// then get_stdout_str() will return the stdout string as it becomes available,
|
||||
// while false will make it available only after the command exits. Note that
|
||||
// if the command outputs a lot of data in a very short period of time and
|
||||
// then exits, false is much better choice because it's much faster.
|
||||
// If you want to monitor the data as it becomes available and clean it to
|
||||
// save some memory, use true.
|
||||
// Call before execute().
|
||||
void set_str_available(bool stdout_str_as_available = false, bool stderr_str_as_available = true)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
stdout_make_str_as_available_ = stdout_str_as_available;
|
||||
stderr_make_str_as_available_ = stderr_str_as_available;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If stdout_make_str_as_available_ is false, call this after stopped_cleanup(),
|
||||
// before next execute(). If it's true, you may call this before the command has
|
||||
// stopped, but it will decrease performance significantly.
|
||||
std::string get_stdout_str(bool clear_existing = false)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
// debug_out_dump("app", str_stdout_);
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stdout_;
|
||||
@@ -206,7 +177,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
// See notes on get_stdout_str().
|
||||
std::string get_stderr_str(bool clear_existing = false)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stderr_;
|
||||
str_stderr_.clear();
|
||||
@@ -219,62 +189,28 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
// Return execution time, in seconds. Call after execute().
|
||||
double get_execution_time()
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
gulong microsec = 0;
|
||||
return g_timer_elapsed(timer_, µsec);
|
||||
}
|
||||
|
||||
|
||||
// don't return sigc::connection - it's better for thread-safety this way.
|
||||
// this will disconnect earlier slots. Call before execute().
|
||||
void set_exit_status_translator(exit_status_translator_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
translator_func_ = func;
|
||||
translator_func_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: The callback will be called in non-main thread! (the call is enclosed
|
||||
// in lock/unlock).
|
||||
// Don't use this unless absolutely necessary, use stopped_cleanup_needed()
|
||||
// polling instead.
|
||||
// You can use stopped_cleanup_needed() polling instead.
|
||||
void set_exited_callback(exited_callback_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
exited_callback_ = func;
|
||||
exited_callback_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// use lock() / unlock() if using members of this class outside of it.
|
||||
|
||||
void lock()
|
||||
{
|
||||
errors_lock(); // defer to parent's mutex - we use it for the whole object.
|
||||
}
|
||||
|
||||
|
||||
void unlock()
|
||||
{
|
||||
errors_unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// protect all member variable access by this mutex, as well as
|
||||
// serialize event callback execution (in respect of main thread too).
|
||||
// it's possible to implement mutexes for each member individually, but
|
||||
// it's impractical.
|
||||
// mutable allows the definition of const member functions - they only
|
||||
// read the data, but do it in a lock-protected manner.
|
||||
// mutable Glib::Mutex object_mutex; // aka access serializer mutex
|
||||
// use ErrorHolder's mutex
|
||||
|
||||
|
||||
|
||||
|
||||
// these are sorta-private
|
||||
|
||||
// for passing to callback
|
||||
@@ -288,20 +224,15 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
static void on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data);
|
||||
|
||||
static gboolean on_channel_io_buffered(GIOChannel* source,
|
||||
GIOCondition cond, Cmdex* self, channel_t type);
|
||||
|
||||
static gboolean on_channel_io_as_available(GIOChannel* source,
|
||||
static gboolean on_channel_io(GIOChannel* source,
|
||||
GIOCondition cond, Cmdex* self, channel_t type);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// The object MUST be locked by the caller.
|
||||
void cleanup_members()
|
||||
{
|
||||
// ScopedLock locker(object_mutex_);
|
||||
kill_signal_sent_ = 0;
|
||||
child_watch_handler_called_ = false;
|
||||
pid_ = 0;
|
||||
@@ -324,8 +255,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
}
|
||||
|
||||
|
||||
mutable ErrorLockPolicy::Mutex& object_mutex_; // reference to parent's member
|
||||
|
||||
|
||||
// default command and its args. std::strings, not ustrings.
|
||||
std::string command_exec_; // binary name. NOT affected by cleanup().
|
||||
@@ -358,9 +287,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
int event_source_id_stdout_;
|
||||
int event_source_id_stderr_;
|
||||
|
||||
int stdout_make_str_as_available_; // NOT affected by cleanup().
|
||||
int stderr_make_str_as_available_; // NOT affected by cleanup().
|
||||
|
||||
std::string str_stdout_; // NOT affected by cleanup().
|
||||
std::string str_stderr_; // NOT affected by cleanup().
|
||||
|
||||
@@ -372,7 +298,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
void* translator_func_data_;
|
||||
|
||||
// "command exited" signal callback.
|
||||
// NOTE: This will be called in separate thread!
|
||||
exited_callback_func_t exited_callback_; // NOT affected by cleanup().
|
||||
void* exited_callback_data_;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -87,8 +87,10 @@ bool CmdexSync::execute()
|
||||
}
|
||||
|
||||
|
||||
// without this, no event sources will be processed and the program will
|
||||
// Without this, no event sources will be processed and the program will
|
||||
// hang waiting for the child to exit (the watch handler won't be called).
|
||||
// Note: If you have an idle callback, g_main_context_pending() will
|
||||
// always return true (until the idle callback returns false and unregisters itself).
|
||||
while(g_main_context_pending(NULL)) {
|
||||
g_main_context_iteration(NULL, false);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -179,13 +179,6 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
cmdex_.set_buffer_sizes(stdout_buffer_size, stderr_buffer_size);
|
||||
}
|
||||
|
||||
// Call before execute().
|
||||
// See Cmdex for details.
|
||||
void set_str_available(bool stdout_str_as_available = false, bool stderr_str_as_available = true)
|
||||
{
|
||||
cmdex_.set_str_available(stdout_str_as_available, stderr_str_as_available);
|
||||
}
|
||||
|
||||
std::string get_stdout_str(bool clear_existing = false)
|
||||
{
|
||||
return cmdex_.get_stdout_str(clear_existing);
|
||||
@@ -209,6 +202,7 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
return error_msg_;
|
||||
}
|
||||
|
||||
/// Set a message to display when running. %s in \c msg will be replaced by the command.
|
||||
void set_running_msg(const std::string& msg)
|
||||
{
|
||||
running_msg_ = msg;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "executor_factory.h"
|
||||
#include "smartctl_executor_gui.h"
|
||||
#include "tw_cli_executor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
ExecutorFactory::ExecutorFactory(bool use_gui, Gtk::Window* parent)
|
||||
: use_gui_(use_gui), parent_(parent)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
hz::intrusive_ptr<CmdexSync> ExecutorFactory::create_executor(ExecutorFactory::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case ExecutorSmartctl:
|
||||
{
|
||||
if (use_gui_) {
|
||||
SmartctlExecutorGuiRefPtr ex = SmartctlExecutorGuiRefPtr(new SmartctlExecutorGui());
|
||||
ex->create_running_dialog(parent_); // dialog parent
|
||||
return ex;
|
||||
}
|
||||
return SmartctlExecutorRefPtr(new SmartctlExecutor());
|
||||
}
|
||||
case ExecutorTwCli:
|
||||
{
|
||||
if (use_gui_) {
|
||||
TwCliExecutorGuiRefPtr ex = TwCliExecutorGuiRefPtr(new TwCliExecutorGui());
|
||||
ex->create_running_dialog(parent_); // dialog parent
|
||||
return ex;
|
||||
}
|
||||
return TwCliExecutorRefPtr(new TwCliExecutor());
|
||||
}
|
||||
}
|
||||
|
||||
DBG_ASSERT(0);
|
||||
return hz::intrusive_ptr<CmdexSync>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXECUTOR_FACTORY_H
|
||||
#define EXECUTOR_FACTORY_H
|
||||
|
||||
#include "cmdex_sync.h"
|
||||
#include "hz/intrusive_ptr.h"
|
||||
|
||||
|
||||
// Forward declaration
|
||||
namespace Gtk {
|
||||
class Window;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// This class allows you to create new executors for different commands,
|
||||
/// without carrying the GUI/CLI stuff manually.
|
||||
class ExecutorFactory : public hz::intrusive_ptr_referenced {
|
||||
public:
|
||||
|
||||
/// Executor type for create_executor()
|
||||
enum Type {
|
||||
ExecutorSmartctl,
|
||||
ExecutorTwCli
|
||||
};
|
||||
|
||||
|
||||
/// Constructor. If \c use_gui is true, specify \c parent for the GUI dialogs.
|
||||
ExecutorFactory(bool use_gui, Gtk::Window* parent = 0);
|
||||
|
||||
|
||||
/// Create a new executor instance according to \c type and the constructor parameters.
|
||||
hz::intrusive_ptr<CmdexSync> create_executor(Type type);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool use_gui_; ///< Whether to construct GUI executors or not.
|
||||
Gtk::Window* parent_; ///< Parent window for dialogs
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef hz::intrusive_ptr<ExecutorFactory> ExecutorFactoryRefPtr;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,16 +1,21 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <gtkmm/messagedialog.h>
|
||||
#include <gtkmm/dialog.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/entry.h>
|
||||
#include <gtkmm/stock.h>
|
||||
#include <gtkmm/box.h>
|
||||
|
||||
#include "app_pango_utils.h" // app_pango_strip_markup()
|
||||
#include "gui_utils.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
inline void show_dialog(const std::string& message, const std::string& sec_message,
|
||||
Gtk::Window* parent, Gtk::MessageType type, bool sec_msg_markup)
|
||||
@@ -75,5 +80,92 @@ void gui_show_info_dialog(const std::string& message, const std::string& sec_mes
|
||||
|
||||
|
||||
|
||||
// Returns false if Cancel was clicked. Puts the user-entered string into result otherwise.
|
||||
bool gui_show_text_entry_dialog(const std::string& title, const std::string& message,
|
||||
std::string& result, const std::string& default_str, Gtk::Window* parent)
|
||||
{
|
||||
return gui_show_text_entry_dialog(title, message, "", result, default_str, parent, false);
|
||||
}
|
||||
|
||||
|
||||
bool gui_show_text_entry_dialog(const std::string& title, const std::string& message, const std::string& sec_message,
|
||||
std::string& result, const std::string& default_str, Gtk::Window* parent, bool sec_msg_markup)
|
||||
{
|
||||
int response = 0;
|
||||
std::string input_str;
|
||||
|
||||
{ // the dialog hides at the end of scope
|
||||
Gtk::Dialog dialog(title, true); // modal
|
||||
|
||||
dialog.set_resizable(false);
|
||||
dialog.set_skip_taskbar_hint(true);
|
||||
dialog.set_border_width(5);
|
||||
|
||||
if (parent) {
|
||||
dialog.set_transient_for(*parent);
|
||||
dialog.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
|
||||
} else {
|
||||
dialog.set_position(Gtk::WIN_POS_MOUSE);
|
||||
}
|
||||
|
||||
|
||||
Gtk::Label main_label;
|
||||
main_label.set_markup("<big><b>" + Glib::Markup::escape_text(message)
|
||||
+ (sec_message.empty() ? "\n" : "") + "</b></big>");
|
||||
main_label.set_line_wrap(true);
|
||||
main_label.set_selectable(true);
|
||||
main_label.set_alignment(0.0, 0.0);
|
||||
|
||||
Gtk::Label sec_label;
|
||||
if (sec_msg_markup) {
|
||||
sec_label.set_markup(sec_message);
|
||||
} else {
|
||||
sec_label.set_text(sec_message);
|
||||
}
|
||||
sec_label.set_line_wrap(true);
|
||||
sec_label.set_selectable(true);
|
||||
sec_label.set_alignment(0.0, 0.0);
|
||||
|
||||
Gtk::Entry input_entry;
|
||||
input_entry.set_activates_default(true);
|
||||
|
||||
|
||||
Gtk::VBox vbox;
|
||||
vbox.set_spacing(12);
|
||||
vbox.pack_start(main_label, false, false, 0);
|
||||
vbox.pack_start(sec_label, true, true, 0);
|
||||
vbox.pack_start(input_entry, true, true, 0);
|
||||
vbox.show_all();
|
||||
|
||||
dialog.get_action_area()->set_border_width(5);
|
||||
dialog.get_action_area()->set_spacing(6);
|
||||
|
||||
dialog.get_vbox()->set_spacing(14); // as in MessageDialog
|
||||
dialog.get_vbox()->pack_start(vbox, false, false, 0);
|
||||
|
||||
|
||||
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
||||
|
||||
Gtk::Button ok_button(Gtk::Stock::OK);
|
||||
ok_button.set_flags(ok_button.get_flags() | Gtk::CAN_DEFAULT);
|
||||
ok_button.show_all();
|
||||
dialog.add_action_widget(ok_button, Gtk::RESPONSE_OK);
|
||||
ok_button.grab_default(); // make it the default widget
|
||||
|
||||
response = dialog.run(); // blocks until the dialog is closed
|
||||
|
||||
input_str = input_entry.get_text();
|
||||
}
|
||||
|
||||
if (response == Gtk::RESPONSE_OK) {
|
||||
result = input_str;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+11
-1
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
// These functions won't return until the dialogs are closed.
|
||||
|
||||
// Message must not contain any markup.
|
||||
|
||||
void gui_show_error_dialog(const std::string& message, Gtk::Window* parent = 0);
|
||||
|
||||
void gui_show_error_dialog(const std::string& message, const std::string& sec_message,
|
||||
@@ -32,6 +34,14 @@ void gui_show_info_dialog(const std::string& message, const std::string& sec_mes
|
||||
Gtk::Window* parent = 0, bool sec_msg_markup = false);
|
||||
|
||||
|
||||
// Returns false if Cancel was clicked. Puts the user-entered string into result otherwise.
|
||||
bool gui_show_text_entry_dialog(const std::string& title, const std::string& message,
|
||||
std::string& result, const std::string& default_str, Gtk::Window* parent = 0);
|
||||
|
||||
bool gui_show_text_entry_dialog(const std::string& title, const std::string& message, const std::string& sec_message,
|
||||
std::string& result, const std::string& default_str, Gtk::Window* parent = 0, bool sec_msg_markup = false);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+10
-8
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -21,7 +21,7 @@ int64_t SelfTest::get_remaining_seconds() const
|
||||
if (total <= 0)
|
||||
return -1; // unknown
|
||||
|
||||
double gran = (total / 9.); // seconds per 10%
|
||||
double gran = (double(total) / 9.); // seconds per 10%
|
||||
// since remaining_percent_ may be manually set to 100, we limit from the above.
|
||||
double rem_seconds_at_last_change = std::min(double(total), gran * remaining_percent_ / 10.);
|
||||
double rem = rem_seconds_at_last_change - timer_.elapsed();
|
||||
@@ -103,7 +103,7 @@ std::string SelfTest::start(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
return "Invalid test specified";
|
||||
|
||||
std::string output;
|
||||
std::string error_msg = drive_->execute_smartctl("-t " + test_param, smartctl_ex, output); // --test=
|
||||
std::string error_msg = drive_->execute_device_smartctl("-t " + test_param, smartctl_ex, output); // --test=
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -163,7 +163,7 @@ std::string SelfTest::force_stop(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
|
||||
// To abort non-captive short, long and conveyance tests, use "--abort".
|
||||
std::string output;
|
||||
std::string error_msg = drive_->execute_smartctl("-X", smartctl_ex, output); // --abort
|
||||
std::string error_msg = drive_->execute_device_smartctl("-X", smartctl_ex, output); // --abort
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -202,8 +202,8 @@ std::string SelfTest::update(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
return "Invalid drive given.";
|
||||
|
||||
std::string output;
|
||||
// std::string error_msg = drive_->execute_smartctl("-l selftest", smartctl_ex, output); // --log=
|
||||
std::string error_msg = drive_->execute_smartctl("-c", smartctl_ex, output); // --capabilities
|
||||
// std::string error_msg = drive_->execute_device_smartctl("-l selftest", smartctl_ex, output); // --log=
|
||||
std::string error_msg = drive_->execute_device_smartctl("-c", smartctl_ex, output); // --capabilities
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -251,7 +251,8 @@ std::string SelfTest::update(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
poll_in_seconds_ = 30; // just a guess
|
||||
|
||||
} else {
|
||||
double gran = (total / 9.); // seconds per 10%. use double, because e.g. 60sec test gives silly values with int.
|
||||
// seconds per 10%. use double, because e.g. 60sec test gives silly values with int.
|
||||
double gran = (double(total) / 9.);
|
||||
|
||||
// Add 1/10 for disk load delays, etc... . Limit to 15sec, in case of very quick tests.
|
||||
poll_in_seconds_ = std::max(int64_t(15), int64_t(gran / 3. + (gran / 10.)));
|
||||
@@ -262,7 +263,8 @@ std::string SelfTest::update(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
poll_in_seconds_ = std::max(int64_t(1*60), int64_t(gran / 10.)); // that's 2 min for 180min extended test
|
||||
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "total: " << total << ", gran: " << gran
|
||||
<< ", poll_in: " << poll_in_seconds_ << ", remaining: " << get_remaining_seconds() << ".\n");
|
||||
<< ", poll in: " << poll_in_seconds_ << ", remaining secs: " << get_remaining_seconds()
|
||||
<< ", remaining %: " << int(remaining_percent_) << ", last seen %: " << int(last_seen_percent_) << ".\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#define SELFTEST_H
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <glibmm/timer.h>
|
||||
|
||||
#include "hz/cstdint.h"
|
||||
#include "hz/intrusive_ptr.h"
|
||||
|
||||
#include "storage_device.h"
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <glibmm.h> // Glib::shell_quote()
|
||||
|
||||
#include "smartctl_executor.h"
|
||||
|
||||
#include "hz/fs_path.h"
|
||||
#include "hz/win32_tools.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// returns an empty string if not found.
|
||||
std::string get_smartctl_binary()
|
||||
{
|
||||
std::string smartctl_binary;
|
||||
rconfig::get_data("system/smartctl_binary", smartctl_binary);
|
||||
|
||||
#ifdef _WIN32
|
||||
// look in smartmontools installation directory.
|
||||
do {
|
||||
bool use_smt = false;
|
||||
rconfig::get_data("system/win32_search_smartctl_in_smartmontools", use_smt);
|
||||
if (!use_smt)
|
||||
break;
|
||||
|
||||
std::string smt_regpath, smt_regkey, smt_smartctl;
|
||||
rconfig::get_data("system/win32_smartmontools_regpath", smt_regpath);
|
||||
rconfig::get_data("system/win32_smartmontools_regkey", smt_regkey);
|
||||
rconfig::get_data("system/win32_smartmontools_smartctl_binary", smt_smartctl);
|
||||
|
||||
if (smt_regpath.empty() || smt_regkey.empty() || smt_smartctl.empty())
|
||||
break;
|
||||
|
||||
std::string smt_inst_dir;
|
||||
hz::win32_get_registry_value_string(HKEY_LOCAL_MACHINE, smt_regpath, smt_regkey, smt_inst_dir);
|
||||
|
||||
if (smt_inst_dir.empty()) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Smartmontools installation not found in \"HKLM\\"
|
||||
<< smt_regpath << "\\" << smt_regkey << "\".\n");
|
||||
break;
|
||||
}
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Smartmontools installation found at \"" << smt_inst_dir
|
||||
<< "\", using \"" << smt_smartctl << "\".\n");
|
||||
|
||||
hz::FsPath p(smt_inst_dir);
|
||||
p.append(smt_smartctl);
|
||||
|
||||
if (!p.exists() || !p.is_file())
|
||||
break;
|
||||
|
||||
smartctl_binary = p.str();
|
||||
|
||||
} while (false);
|
||||
|
||||
#endif
|
||||
|
||||
return smartctl_binary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string execute_smartctl(const std::string& device, const std::string& device_opts,
|
||||
const std::string& command_options,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& smartctl_output)
|
||||
{
|
||||
#ifndef _WIN32 // win32 doesn't have slashes in devices names
|
||||
{
|
||||
std::string::size_type pos = device.rfind('/'); // find basename
|
||||
if (pos == std::string::npos) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Invalid device name \"" << device << "\".\n");
|
||||
return "Invalid device name specified.";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!smartctl_ex) // if it doesn't exist, create a default one
|
||||
smartctl_ex = new SmartctlExecutor(); // will be auto-deleted
|
||||
|
||||
std::string smartctl_binary = get_smartctl_binary();
|
||||
|
||||
if (smartctl_binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl binary is not set in config.\n");
|
||||
return "Smartctl binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string smartctl_def_options;
|
||||
rconfig::get_data("system/smartctl_options", smartctl_def_options);
|
||||
|
||||
if (!smartctl_def_options.empty())
|
||||
smartctl_def_options += " ";
|
||||
|
||||
|
||||
std::string device_specific_options = device_opts;
|
||||
if (!device_specific_options.empty())
|
||||
device_specific_options += " ";
|
||||
|
||||
|
||||
smartctl_ex->set_command(Glib::shell_quote(smartctl_binary),
|
||||
smartctl_def_options + device_specific_options + command_options
|
||||
+ " " + Glib::shell_quote(device));
|
||||
|
||||
if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n");
|
||||
|
||||
smartctl_output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str()));
|
||||
|
||||
// check if it's a device permission error.
|
||||
// Smartctl open device: /dev/sdb failed: Permission denied
|
||||
if (app_pcre_match("/Smartctl open device.+Permission denied/mi", smartctl_output)) {
|
||||
return "Permission denied while opening device.";
|
||||
}
|
||||
|
||||
// smartctl_output = smartctl_ex->get_stdout_str();
|
||||
return smartctl_ex->get_error_msg();
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
smartctl_output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str()));
|
||||
if (smartctl_output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl returned an empty output.\n");
|
||||
return "Smartctl returned an empty output.";
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -132,7 +132,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
if ( !((exit_code & exit_cant_parse) || (exit_code & exit_open_failed)) )
|
||||
return;
|
||||
|
||||
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
|
||||
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
|
||||
} else if (error_type == "giochannel" || error_type == "custom") {
|
||||
return;
|
||||
}
|
||||
@@ -140,9 +140,6 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
this->set_error_msg(e->get_message());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -150,6 +147,17 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
|
||||
typedef SmartctlExecutorGeneric<CmdexSync> SmartctlExecutor;
|
||||
|
||||
typedef hz::intrusive_ptr<SmartctlExecutor> SmartctlExecutorRefPtr;
|
||||
|
||||
|
||||
|
||||
// returns an empty string if not found.
|
||||
std::string get_smartctl_binary();
|
||||
|
||||
|
||||
std::string execute_smartctl(const std::string& device, const std::string& device_opts,
|
||||
const std::string& command_options,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& smartctl_output);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_whatever.txt
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Glib::thread_init();
|
||||
// Glib::thread_init();
|
||||
Gtk::Main m(argc, argv);
|
||||
|
||||
// NOTE: Don't use long options (e.g. --info). Use short ones (e.g. -i),
|
||||
|
||||
+320
-144
@@ -1,11 +1,13 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdint.h> // uint64_t
|
||||
#include <clocale> // localeconv
|
||||
|
||||
#include "hz/locale_tools.h" // ScopedCLocale, locale_c_get().
|
||||
#include "hz/cstdint.h" // uint64_t
|
||||
#include "hz/string_algo.h" // string_*
|
||||
#include "hz/string_num.h" // string_is_numeric, number_to_string
|
||||
#include "hz/format_unit.h" // format_size
|
||||
@@ -17,6 +19,7 @@
|
||||
#include "storage_property_colors.h"
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -147,23 +150,34 @@ bool SmartctlParser::parse_full(const std::string& full)
|
||||
|
||||
// version info
|
||||
|
||||
std::string version = parse_version(s);
|
||||
if (version.empty()) {
|
||||
std::string version, version_full;
|
||||
if (!parse_version(s, version, version_full)) {
|
||||
set_error_msg("Cannot extract smartctl version information.");
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot extract version information. Returning.\n");
|
||||
return false;
|
||||
|
||||
} else {
|
||||
StorageProperty p;
|
||||
p.set_name("Smartctl version", "smartctl_version");
|
||||
p.reported_value = version;
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
p.section = StorageProperty::section_info; // add to info section
|
||||
add_property(p);
|
||||
{
|
||||
StorageProperty p;
|
||||
p.set_name("Smartctl version", "smartctl_version", "Smartctl Version");
|
||||
p.reported_value = version;
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
p.section = StorageProperty::section_info; // add to info section
|
||||
add_property(p);
|
||||
}
|
||||
{
|
||||
StorageProperty p;
|
||||
p.set_name("Smartctl version", "smartctl_version_full", "Smartctl Version");
|
||||
p.reported_value = version_full;
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
p.section = StorageProperty::section_info; // add to info section
|
||||
add_property(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_version(version)) {
|
||||
if (!check_version(version, version_full)) {
|
||||
set_error_msg("Incompatible smartctl version.");
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Incompatible smartctl version. Returning.\n");
|
||||
return false;
|
||||
@@ -197,35 +211,38 @@ bool SmartctlParser::parse_full(const std::string& full)
|
||||
section_start_pos = section_end_pos;
|
||||
}
|
||||
|
||||
return status;
|
||||
if (!status) {
|
||||
set_error_msg("No ATA sections could be parsed.");
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "No ATA sections could be parsed. Returning.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Supply output of "smartctl --version" here.
|
||||
// returns empty string on failure. Non-unix newlines in s are ok.
|
||||
std::string SmartctlParser::parse_version(const std::string& s)
|
||||
// returns false on failure. Non-unix newlines in s are ok.
|
||||
bool SmartctlParser::parse_version(const std::string& s, std::string& version, std::string& version_full)
|
||||
{
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
// e.g. "smartctl version 5.37" or "smartctl 5.39"
|
||||
pcrecpp::RE re("^smartctl (?:version )?([0-9][^ \\t\\n\\r]+)", re_options);
|
||||
std::string version;
|
||||
|
||||
if (!re.PartialMatch(s, &version)) {
|
||||
// "smartctl 5.39 2009-06-03 20:10" (cvs versions)
|
||||
// "smartctl 5.39 2009-08-08 r2873" (svn versions)
|
||||
if (!app_pcre_match("/^smartctl (?:version )?(([0-9][^ \\t\\n\\r]+)(?: [0-9 r:-]+)?)/mi", s, &version_full, &version)) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "No smartctl version information found in supplied string.\n");
|
||||
return std::string();
|
||||
return false;
|
||||
}
|
||||
hz::string_trim(version_full);
|
||||
|
||||
return version;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// check that the version of smartctl output can be parsed with this parser.
|
||||
bool SmartctlParser::check_version(const std::string& version_str)
|
||||
bool SmartctlParser::check_version(const std::string& version_str, const std::string& version_full_str)
|
||||
{
|
||||
// tested with 5.1-xx versions (1 - 18), and 5.[20 - 38].
|
||||
// note: 5.1-11 (maybe others too) with scsi disk gives non-parsable output (why?).
|
||||
@@ -249,10 +266,40 @@ bool SmartctlParser::check_version(const std::string& version_str)
|
||||
// Note: this property is present since 5.33.
|
||||
std::string SmartctlParser::parse_byte_size(const std::string& str, uint64_t& bytes, bool extended)
|
||||
{
|
||||
// e.g. "500,107,862,016" bytes or "80'060'424'192 bytes" or "80 026 361 856 bytes"
|
||||
// (locale-dependent?). added '.'-separated too, just in case.
|
||||
std::string s = hz::string_replace_copy(hz::string_replace_copy(hz::string_trim_copy(str), ",", ""), "'", "");
|
||||
s = hz::string_replace_copy(hz::string_replace_copy(hz::string_replace_copy(s, " bytes", ""), " ", ""), ".", "");
|
||||
// E.g. "500,107,862,016" bytes or "80'060'424'192 bytes" or "80 026 361 856 bytes".
|
||||
// French locale inserts 0xA0 as a separator (non-breaking space, _not_ a valid utf8 char).
|
||||
// Added '.'-separated too, just in case.
|
||||
// Smartctl uses system locale's thousands_sep explicitly.
|
||||
|
||||
// When launching smartctl, we use LANG=C for it, but it works only on POSIX.
|
||||
// Also, loading smartctl output files from different locales doesn't really work.
|
||||
|
||||
// debug_out_dump("app", "Size reported as: " << str << "\n");
|
||||
|
||||
std::vector<std::string> to_replace;
|
||||
to_replace.push_back(" ");
|
||||
to_replace.push_back("'");
|
||||
to_replace.push_back(",");
|
||||
to_replace.push_back(".");
|
||||
to_replace.push_back(std::string(1, 0xa0));
|
||||
|
||||
#ifdef _WIN32
|
||||
// if current locale is C, then probably we didn't change it at application
|
||||
// startup, so set it now (temporarily). Otherwise, just use the current locale's
|
||||
// thousands separator.
|
||||
{
|
||||
std::string old_locale = hz::locale_c_get();
|
||||
hz::ScopedCLocale loc("", old_locale == "C"); // set system locale if the current one is C
|
||||
|
||||
struct lconv* lc = std::localeconv();
|
||||
if (lc && lc->thousands_sep && *(lc->thousands_sep)) {
|
||||
to_replace.push_back(lc->thousands_sep);
|
||||
}
|
||||
} // the locale is restored here
|
||||
#endif
|
||||
|
||||
to_replace.push_back("bytes");
|
||||
std::string s = hz::string_replace_array_copy(hz::string_trim_copy(str), to_replace, "");
|
||||
|
||||
uint64_t v = 0;
|
||||
if (hz::string_is_numeric(s, v, false)) {
|
||||
@@ -308,16 +355,13 @@ bool SmartctlParser::parse_section(const std::string& header, const std::string&
|
||||
// Parse the info section (without "===" header)
|
||||
bool SmartctlParser::parse_section_info(const std::string& body)
|
||||
{
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
this->set_data_section_info(body);
|
||||
|
||||
StorageProperty::section_t section = StorageProperty::section_info;
|
||||
|
||||
// split by lines.
|
||||
// e.g. Device Model: ST3500630AS
|
||||
pcrecpp::RE re("^([^:\\n]+):[ \\t]*(.*)$", re_options);
|
||||
pcrecpp::RE re = app_pcre_re("/^([^\\n]+): [ \\t]*(.*)$/miU"); // ungreedy
|
||||
|
||||
std::string name, value;
|
||||
pcrecpp::StringPiece input(body); // position tracker
|
||||
@@ -357,11 +401,38 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
|
||||
}
|
||||
|
||||
|
||||
if (app_pcre_match("/Model Family/mi", p.reported_name)
|
||||
|| app_pcre_match("/Device Model/mi", p.reported_name)
|
||||
|| app_pcre_match("/Serial Number/mi", p.reported_name)
|
||||
|| app_pcre_match("/Firmware Version/mi", p.reported_name)
|
||||
) {
|
||||
if (app_pcre_match("/Model Family/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "model_family", "Model Family");
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/Device Model/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "device_model", "Device Model");
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/Serial Number/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "serial_number", "Serial Number");
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/Firmware Version/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "firmware_version", "Firmware Version");
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/Sector Sizes/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "sector_sizes", "Sector Sizes");
|
||||
p.value_type = StorageProperty::value_type_string; // prints 2 values (phys/logical, if they're different)
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/Sector Size/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "sector_size", "Sector Size");
|
||||
p.value_type = StorageProperty::value_type_string; // prints a single value (if it's not 512)
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/LU WWN Device Id/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "wwn_id", "World Wide Name");
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
@@ -376,6 +447,7 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
|
||||
p.value_string = p.reported_value;
|
||||
|
||||
} else if (app_pcre_match("/User Capacity/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "capacity", "Capacity");
|
||||
p.value_type = StorageProperty::value_type_integer;
|
||||
uint64_t v = 0;
|
||||
if ((p.readable_value = parse_byte_size(p.reported_value, v, true)).empty()) {
|
||||
@@ -392,7 +464,7 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
|
||||
p.value_integer = v;
|
||||
|
||||
} else if (app_pcre_match("/Device is/mi", p.reported_name)) {
|
||||
p.set_name(p.reported_name, "in_smartctl_db", "Is in smartctl database");
|
||||
p.set_name(p.reported_name, "in_smartctl_db", "In Smartctl Database");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = (!app_pcre_match("/Not in /mi", p.reported_value));
|
||||
|
||||
@@ -401,37 +473,40 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
|
||||
// Don't put complete messages here - they change across smartctl versions.
|
||||
|
||||
if (app_pcre_match("/Available - device has/mi", p.reported_value)) {
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART supported");
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART Supported");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = true;
|
||||
|
||||
} else if (app_pcre_match("/Enabled/mi", p.reported_value)) {
|
||||
p.set_name(p.reported_name, "smart_enabled", "SMART enabled");
|
||||
p.set_name(p.reported_name, "smart_enabled", "SMART Enabled");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = true;
|
||||
|
||||
} else if (app_pcre_match("/Disabled/mi", p.reported_value)) {
|
||||
p.set_name(p.reported_name, "smart_enabled", "SMART enabled");
|
||||
p.set_name(p.reported_name, "smart_enabled", "SMART Enabled");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = false;
|
||||
|
||||
} else if (app_pcre_match("/Unavailable/mi", p.reported_value)) {
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART supported");
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART Supported");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = false;
|
||||
|
||||
// this should be last - when ambiguous state is detected, usually smartctl
|
||||
// retries with other methods and prints one of the above.
|
||||
} else if (app_pcre_match("/Ambiguous/mi", p.reported_value)) {
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART supported");
|
||||
p.set_name(p.reported_name, "smart_supported", "SMART Supported");
|
||||
p.value_type = StorageProperty::value_type_bool;
|
||||
p.value_bool = true; // let's be optimistic - just hope that it doesn't hurt.
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Unknown attribute \"" << p.reported_name << "\"\n");
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Unknown property \"" << p.reported_name << "\"\n");
|
||||
// this is not an error, just unknown attribute. treat it as string.
|
||||
// Don't highlight it with warning, it may just be a new smartctl feature.
|
||||
p.value_type = StorageProperty::value_type_string;
|
||||
p.value_string = p.reported_value;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -464,7 +539,7 @@ bool SmartctlParser::parse_section_data(const std::string& body)
|
||||
// merge "error log" parts. each part begins with a double-space or "Error nn".
|
||||
for (unsigned int i = 0; i < split_subsections.size(); ++i) {
|
||||
std::string sub = hz::string_trim_copy(split_subsections[i], "\t\n\r"); // don't trim space
|
||||
if (pcrecpp::RE("^ ").PartialMatch(sub) || pcrecpp::RE("^Error [0-9]+").PartialMatch(sub)) {
|
||||
if (app_pcre_re("^ ").PartialMatch(sub) || app_pcre_re("^Error [0-9]+").PartialMatch(sub)) {
|
||||
if (!subsections.empty()) {
|
||||
subsections.back() += "\n\n" + sub; // append to previous part
|
||||
} else {
|
||||
@@ -525,20 +600,14 @@ bool SmartctlParser::parse_section_data_subsection_health(const std::string& sub
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_health;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
|
||||
pcrecpp::RE re("^([^:\\n]+):[ \\t]*(.*)$", re_options);
|
||||
|
||||
std::string name, value;
|
||||
if (re.PartialMatch(sub, &name, &value)) {
|
||||
if (app_pcre_match("/^([^:\\n]+):[ \\t]*(.*)$/mi", sub, &name, &value)) {
|
||||
hz::string_trim(name);
|
||||
hz::string_trim(value);
|
||||
|
||||
// only one attribute in this section
|
||||
if (app_pcre_match("/SMART overall-health self-assessment/mi", name)) {
|
||||
pt.set_name(name, "overall_health", "Overall health self-assessment test");
|
||||
pt.set_name(name, "overall_health", "Overall Health Self-Assessment Test");
|
||||
pt.reported_value = value;
|
||||
pt.value_type = StorageProperty::value_type_string;
|
||||
pt.value_string = pt.reported_value;
|
||||
@@ -563,16 +632,12 @@ bool SmartctlParser::parse_section_data_subsection_capabilities(const std::strin
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_capabilities;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
|
||||
std::string sub = sub_initial;
|
||||
|
||||
// Fix some bugs in smartctl output (pre-5.39-final versions):
|
||||
// There is a stale newline in "is in a Vendor Specific state\n.\n" and
|
||||
// "is in a Reserved state\n.\n".
|
||||
// pcrecpp::RE("\\n\\.$", re_options).GlobalReplace(".", &sub);
|
||||
// app_pcre_replace("/\\n\\.$/mi", ".", &sub);
|
||||
app_pcre_replace("/(is in a Vendor Specific state)\\n\\.$/mi", "\\1.", sub);
|
||||
app_pcre_replace("/(is in a Reserved state)\\n\\.$/mi", "\\1.", sub);
|
||||
|
||||
@@ -608,8 +673,7 @@ bool SmartctlParser::parse_section_data_subsection_capabilities(const std::strin
|
||||
|
||||
|
||||
// parse each block
|
||||
pcrecpp::RE re("([^:]*):\\s*\\(([^)]+)\\)\\s*(.*)",
|
||||
pcrecpp::RE_Options().set_multiline(true).set_dotall(true));
|
||||
pcrecpp::RE re = app_pcre_re("/([^:]*):\\s*\\(([^)]+)\\)\\s*(.*)/ms");
|
||||
|
||||
bool cap_found = false; // found at least one capability
|
||||
|
||||
@@ -676,7 +740,7 @@ bool SmartctlParser::parse_section_data_subsection_capabilities(const std::strin
|
||||
p.value_type = StorageProperty::value_type_capability;
|
||||
|
||||
p.value_capability.reported_flag_value = numvalue_orig;
|
||||
p.value_capability.flag_value = numvalue; // full flag value
|
||||
p.value_capability.flag_value = static_cast<int16_t>(numvalue); // full flag value
|
||||
p.value_capability.reported_strvalue = strvalue_orig;
|
||||
|
||||
// split capability lines into a vector. every flag sentence ends with "."
|
||||
@@ -708,9 +772,6 @@ bool SmartctlParser::parse_section_data_subsection_capabilities(const std::strin
|
||||
// Check the capabilities for internal properties we can use.
|
||||
bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& cap)
|
||||
{
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
// Some special capabilities we're interested in.
|
||||
|
||||
// Note: Smartctl gradually changed spelling Off-line to Offline in some messages.
|
||||
@@ -721,29 +782,36 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
|
||||
|
||||
// "was never started", "was completed without error", "is in progress",
|
||||
// "was suspended by an interrupting command from host", etc...
|
||||
pcrecpp::RE re_offline_status("^(Off-?line data collection) activity (?:is|was) (.*)$", re_options);
|
||||
pcrecpp::RE re_offline_status = app_pcre_re("/^(Off-?line data collection) activity (?:is|was) (.*)$/mi");
|
||||
// "Enabled", "Disabled". May not show up on older smartctl (< 5.1.10), so no way of knowing there.
|
||||
pcrecpp::RE re_offline_enabled("^(Auto Off-?line Data Collection):[ \\t]*(.*)$", re_options);
|
||||
pcrecpp::RE re_offline_immediate("^(SMART execute Off-?line immediate)$", re_options);
|
||||
pcrecpp::RE re_offline_enabled = app_pcre_re("/^(Auto Off-?line Data Collection):[ \\t]*(.*)$/mi");
|
||||
pcrecpp::RE re_offline_immediate = app_pcre_re("/^(SMART execute Off-?line immediate)$/mi");
|
||||
// "No Auto Offline data collection support.", "Auto Offline data collection on/off support.".
|
||||
pcrecpp::RE re_offline_auto("^(No |)(Auto Off-?line data collection (?:on\\/off )?support)$", re_options);
|
||||
pcrecpp::RE re_offline_auto = app_pcre_re("/^(No |)(Auto Off-?line data collection (?:on\\/off )?support)$/mi");
|
||||
// Same as above (smartctl <= 5.1-18). "No Automatic timer ON/OFF support."
|
||||
pcrecpp::RE re_offline_auto2("^(No |)(Automatic timer ON\\/OFF support)$", re_options);
|
||||
pcrecpp::RE re_offline_suspend("^(?:Suspend|Abort) (Off-?line collection upon new command)$", re_options);
|
||||
pcrecpp::RE re_offline_surface("^(No |)(Off-?line surface scan supported)$", re_options);
|
||||
pcrecpp::RE re_offline_time("^(Total time to complete Off-?line data collection)", re_options); // match on name!
|
||||
pcrecpp::RE re_offline_auto2 = app_pcre_re("/^(No |)(Automatic timer ON\\/OFF support)$/mi");
|
||||
pcrecpp::RE re_offline_suspend = app_pcre_re("/^(?:Suspend|Abort) (Off-?line collection upon new command)$/mi");
|
||||
pcrecpp::RE re_offline_surface = app_pcre_re("/^(No |)(Off-?line surface scan supported)$/mi");
|
||||
|
||||
pcrecpp::RE re_selftest_status("^Self-test execution status", re_options); // match on name
|
||||
pcrecpp::RE re_selftest_support("^(No |)(Self-test supported)$", re_options);
|
||||
pcrecpp::RE re_conv_selftest_support("^(No |)(Conveyance Self-test supported)$", re_options);
|
||||
pcrecpp::RE re_selective_selftest_support("^(No |)(Selective Self-test supported)$", re_options);
|
||||
pcrecpp::RE re_selftest_short_time("^(Short self-test routine recommended polling time)", re_options); // match on name!
|
||||
pcrecpp::RE re_selftest_long_time("^(Extended self-test routine recommended polling time)", re_options); // match on name!
|
||||
pcrecpp::RE re_conv_selftest_time("^(Conveyance self-test routine recommended polling time)", re_options); // match on name!
|
||||
pcrecpp::RE re_selftest_support = app_pcre_re("/^(No |)(Self-test supported)$/mi");
|
||||
pcrecpp::RE re_conv_selftest_support = app_pcre_re("/^(No |)(Conveyance Self-test supported)$/mi");
|
||||
pcrecpp::RE re_selective_selftest_support = app_pcre_re("/^(No |)(Selective Self-test supported)$/mi");
|
||||
|
||||
pcrecpp::RE re_sct_status("^(SCT Status supported)$", re_options);
|
||||
pcrecpp::RE re_sct_control("^(SCT Feature Control supported)$", re_options); // means can change logging interval
|
||||
pcrecpp::RE re_sct_data("^(SCT Data Table supported)$", re_options);
|
||||
pcrecpp::RE re_sct_status = app_pcre_re("/^(SCT Status supported)$/mi");
|
||||
pcrecpp::RE re_sct_control = app_pcre_re("/^(SCT Feature Control supported)$/mi"); // means can change logging interval
|
||||
pcrecpp::RE re_sct_data = app_pcre_re("/^(SCT Data Table supported)$/mi");
|
||||
|
||||
// these are matched on name
|
||||
pcrecpp::RE re_offline_status_group = app_pcre_re("/^(Off-?line data collection status)/mi");
|
||||
pcrecpp::RE re_offline_time = app_pcre_re("/^(Total time to complete Off-?line data collection)/mi");
|
||||
pcrecpp::RE re_offline_cap_group = app_pcre_re("/^(Off-?line data collection capabilities)/mi");
|
||||
pcrecpp::RE re_smart_cap_group = app_pcre_re("/^(SMART capabilities)/mi");
|
||||
pcrecpp::RE re_error_log_cap_group = app_pcre_re("/^(Error logging capability)/mi");
|
||||
pcrecpp::RE re_sct_cap_group = app_pcre_re("/^(SCT capabilities)/mi");
|
||||
pcrecpp::RE re_selftest_status = app_pcre_re("/^Self-test execution status/mi");
|
||||
pcrecpp::RE re_selftest_short_time = app_pcre_re("/^(Short self-test routine recommended polling time)/mi");
|
||||
pcrecpp::RE re_selftest_long_time = app_pcre_re("/^(Extended self-test routine recommended polling time)/mi");
|
||||
pcrecpp::RE re_conv_selftest_time = app_pcre_re("/^(Conveyance self-test routine recommended polling time)/mi");
|
||||
|
||||
if (cap.section != StorageProperty::section_data || cap.subsection != StorageProperty::subsection_capabilities) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Non-capability property passed.\n");
|
||||
@@ -751,9 +819,30 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
|
||||
}
|
||||
|
||||
|
||||
// Name the capability groups for easy matching when setting descriptions
|
||||
if (cap.value_type == StorageProperty::value_type_capability) {
|
||||
if (re_offline_status_group.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "offline_status_group";
|
||||
|
||||
} else if (re_offline_cap_group.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "offline_cap_group";
|
||||
|
||||
} else if (re_smart_cap_group.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "smart_cap_group";
|
||||
|
||||
} else if (re_error_log_cap_group.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "error_log_cap_group";
|
||||
|
||||
} else if (re_sct_cap_group.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "sct_cap_group";
|
||||
|
||||
} else if (re_selftest_status.PartialMatch(cap.reported_name)) {
|
||||
cap.generic_name = "last_selftest_cap_group";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// match on name:
|
||||
// Last self-test status
|
||||
if (re_selftest_status.PartialMatch(cap.reported_name)) {
|
||||
// The last self-test status. break up into pieces.
|
||||
|
||||
@@ -852,6 +941,7 @@ bool SmartctlParser::parse_section_data_internal_capabilities(StorageProperty& c
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Extract subcapabilities from capability vectors and assign to "internal" section.
|
||||
if (cap.value_type == StorageProperty::value_type_capability) {
|
||||
|
||||
@@ -955,32 +1045,53 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_attributes;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(sub, '\n', lines, true);
|
||||
|
||||
// Format notes:
|
||||
// * Before 5.1-14, no UPDATED column was present.
|
||||
// * Before 5.1-14, no UPDATED column was present in "old" format.
|
||||
// * Most, but not all attribute names are with underscores. However, I encountered one
|
||||
// named "Head flying hours". So, parse until we encounter the next column.
|
||||
// * One WD drive had non-integer flags, something like "PO--C-", with several
|
||||
// lines of their descriptions after the attributes block (each line started with spaces and |).
|
||||
// named "Head flying hours" and there are slashes sometimes as well.
|
||||
// So, parse until we encounter the next column.
|
||||
// * "Old" format: One WD drive had non-integer flags, something like "PO--C-", with several
|
||||
// lines of their descriptions after the attributes block (each line started with spaces and |)
|
||||
// (seems to be a CVS version from 2006).
|
||||
// * SSD drives may show "---" in value/worst/threshold fields.
|
||||
|
||||
// "old" format (used in -a):
|
||||
// "ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE"
|
||||
// " 1 Raw_Read_Error_Rate 0x000f 115 099 006 Pre-fail Always - 90981479"
|
||||
// " 12 Power_Cycle_Count 0x0000 --- --- --- Old_age Offline - 167"
|
||||
|
||||
// "brief" format (used in -x):
|
||||
// "ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE"
|
||||
// " 1 Raw_Read_Error_Rate POSR-- 118 099 006 - 174772734"
|
||||
|
||||
enum {
|
||||
FormatStyleOld,
|
||||
FormatStyleNoUpdated, // old format without UPDATED column
|
||||
FormatStyleBrief
|
||||
};
|
||||
|
||||
bool attr_found = false; // at least one attribute was found
|
||||
bool attr_format_with_updated = false; // UPDATED column present
|
||||
int attr_format_style = FormatStyleOld;
|
||||
|
||||
pcrecpp::RE re_up("[ \\t]*([0-9]+) ([^\\t\\n]+)[ \\t]+((?:0x[a-fA-F0-9]+)|(?:[A-Z-]{2,}))[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+"
|
||||
"([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*", re_options);
|
||||
std::string space_re = "[ \\t]+";
|
||||
|
||||
pcrecpp::RE re_noup("[ \\t]*([0-9]+) ([^\\t\\n]+)[ \\t]+((?:0x[a-fA-F0-9]+)|(?:[A-Z-]{2,}))[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+([0-9]+)[ \\t]+"
|
||||
"([^ \\t\\n]+)[ \\t]+([^ \\t\\n]+)[ \\t]+(.+)[ \\t]*", re_options);
|
||||
std::string flag_re = "((?:0x[a-fA-F0-9]+)|(?:[A-Z+-]{2,}))";
|
||||
std::string base_re = "[ \\t]*([0-9]+) ([^\\t\\n]+)" + space_re + flag_re + space_re // name / flag
|
||||
+ "([0-9-]+)" + space_re + "([0-9-]+)" + space_re + "([0-9-]+)" + space_re; // value / worst / threshold
|
||||
std::string type_re = "([^ \\t\\n]+)" + space_re;
|
||||
std::string updated_re = "([^ \\t\\n]+)" + space_re;
|
||||
std::string failed_re = "([^ \\t\\n]+)" + space_re;
|
||||
std::string raw_re = "(.+)[ \\t]*";
|
||||
|
||||
pcrecpp::RE re_flag_descr("^[\\t ]+\\|", re_options);
|
||||
pcrecpp::RE re_old_up = app_pcre_re("/" + base_re + type_re + updated_re + failed_re + raw_re + "/mi");
|
||||
pcrecpp::RE re_old_noup = app_pcre_re("/" + base_re + type_re + failed_re + raw_re + "/mi");
|
||||
pcrecpp::RE re_brief = app_pcre_re("/" + base_re + failed_re + raw_re + "/mi");
|
||||
|
||||
pcrecpp::RE re_flag_descr = app_pcre_re("/^[\\t ]+\\|/mi");
|
||||
|
||||
|
||||
for(unsigned int i = 0; i < lines.size(); ++i) {
|
||||
@@ -991,7 +1102,12 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
continue;
|
||||
|
||||
if (app_pcre_match("/ATTRIBUTE_NAME/mi", line)) {
|
||||
attr_format_with_updated = (app_pcre_match("/UPDATED/mi", line));
|
||||
// detect format type
|
||||
if (!app_pcre_match("/WHEN_FAILED/mi", line)) {
|
||||
attr_format_style = FormatStyleBrief;
|
||||
} else if (!app_pcre_match("/UPDATED/mi", line)) {
|
||||
attr_format_style = FormatStyleNoUpdated;
|
||||
}
|
||||
continue; // we don't need this line
|
||||
}
|
||||
|
||||
@@ -1000,7 +1116,7 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
}
|
||||
|
||||
if (app_pcre_match("/Data Structure revision number/mi", line)) {
|
||||
pcrecpp::RE re("^([^:\\n]+):[ \\t]*(.*)$", re_options);
|
||||
pcrecpp::RE re = app_pcre_re("/^([^:\\n]+):[ \\t]*(.*)$/mi");
|
||||
std::string name, value;
|
||||
if (re.PartialMatch(line, &name, &value)) {
|
||||
hz::string_trim(name);
|
||||
@@ -1009,7 +1125,7 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
hz::string_is_numeric(value, value_num, false);
|
||||
|
||||
StorageProperty p(pt);
|
||||
p.set_name(name);
|
||||
p.set_name(name, "data_structure_version");
|
||||
p.reported_value = value;
|
||||
p.value_type = StorageProperty::value_type_integer;
|
||||
p.value_integer = value_num;
|
||||
@@ -1026,15 +1142,22 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
|
||||
bool matched = true;
|
||||
|
||||
if (attr_format_with_updated) {
|
||||
if (!re_up.FullMatch(line, &id, &name, &flag, &value, &worst, &threshold, &attr_type,
|
||||
if (attr_format_style == FormatStyleOld) {
|
||||
if (!re_old_up.FullMatch(line, &id, &name, &flag, &value, &worst, &threshold, &attr_type,
|
||||
&update_type, &when_failed, &raw_value)) {
|
||||
matched = false;
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse attribute line.\n");
|
||||
}
|
||||
|
||||
} else { // no UPDATED column
|
||||
if (!re_noup.FullMatch(line, &id, &name, &flag, &value, &worst, &threshold, &attr_type,
|
||||
} else if (attr_format_style == FormatStyleNoUpdated) {
|
||||
if (!re_old_noup.FullMatch(line, &id, &name, &flag, &value, &worst, &threshold, &attr_type,
|
||||
&when_failed, &raw_value)) {
|
||||
matched = false;
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse attribute line.\n");
|
||||
}
|
||||
|
||||
} else if (attr_format_style == FormatStyleBrief) {
|
||||
if (!re_brief.FullMatch(line, &id, &name, &flag, &value, &worst, &threshold,
|
||||
&when_failed, &raw_value)) {
|
||||
matched = false;
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse attribute line.\n");
|
||||
@@ -1052,23 +1175,49 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
|
||||
StorageAttribute a;
|
||||
hz::string_is_numeric(hz::string_trim_copy(id), a.id, true, 10);
|
||||
a.flag = hz::string_trim_copy(flag);
|
||||
hz::string_is_numeric(hz::string_trim_copy(value), a.value, true, 10);
|
||||
hz::string_is_numeric(hz::string_trim_copy(worst), a.worst, true, 10);
|
||||
hz::string_is_numeric(hz::string_trim_copy(threshold), a.threshold, true, 10);
|
||||
uint8_t norm_value = 0, worst_value = 0, threshold_value = 0;
|
||||
|
||||
a.attr_type = (attr_type == "Pre-fail" ? StorageAttribute::attr_type_prefail
|
||||
: (attr_type == "Old_age" ? StorageAttribute::attr_type_oldage : StorageAttribute::attr_type_unknown));
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(value), norm_value, true, 10)) {
|
||||
a.value = norm_value;
|
||||
}
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(worst), worst_value, true, 10)) {
|
||||
a.worst = worst_value;
|
||||
}
|
||||
if (hz::string_is_numeric(hz::string_trim_copy(threshold), threshold_value, true, 10)) {
|
||||
a.threshold = threshold_value;
|
||||
}
|
||||
|
||||
a.update_type = (update_type == "Always" ? StorageAttribute::update_type_always
|
||||
: (update_type == "Offline" ? StorageAttribute::update_type_offline : StorageAttribute::update_type_unknown));
|
||||
if (attr_format_style == FormatStyleBrief) {
|
||||
a.attr_type = app_pcre_match("/P/", a.flag) ? StorageAttribute::attr_type_prefail : StorageAttribute::attr_type_oldage;
|
||||
} else {
|
||||
if (attr_type == "Pre-fail") {
|
||||
a.attr_type = StorageAttribute::attr_type_prefail;
|
||||
} else if (attr_type == "Old_age") {
|
||||
a.attr_type = StorageAttribute::attr_type_oldage;
|
||||
} else {
|
||||
a.attr_type = StorageAttribute::attr_type_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_format_style == FormatStyleBrief) {
|
||||
a.update_type = app_pcre_match("/O/", a.flag) ? StorageAttribute::update_type_always : StorageAttribute::update_type_offline;
|
||||
} else {
|
||||
if (update_type == "Always") {
|
||||
a.update_type = StorageAttribute::update_type_always;
|
||||
} else if (update_type == "Offline") {
|
||||
a.update_type = StorageAttribute::update_type_offline;
|
||||
} else {
|
||||
a.update_type = StorageAttribute::update_type_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
a.when_failed = StorageAttribute::fail_time_unknown;
|
||||
hz::string_trim(when_failed);
|
||||
if (when_failed == "-") {
|
||||
a.when_failed = StorageAttribute::fail_time_none;
|
||||
} else if (when_failed == "In_the_past") {
|
||||
} else if (when_failed == "In_the_past" || when_failed == "Past") { // the second one if from brief format
|
||||
a.when_failed = StorageAttribute::fail_time_past;
|
||||
} else if (when_failed == "FAILING_NOW") {
|
||||
} else if (when_failed == "FAILING_NOW" || when_failed == "NOW") { // the second one if from brief format
|
||||
a.when_failed = StorageAttribute::fail_time_now;
|
||||
}
|
||||
|
||||
@@ -1104,10 +1253,6 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_error_log;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
|
||||
// Note: The format of this section was changed somewhere between 5.0-x and 5.30.
|
||||
// The old format is doesn't really give any useful info, and whatever's left is somewhat
|
||||
// parsable by this parser. Can't really improve that.
|
||||
@@ -1115,9 +1260,9 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
|
||||
bool data_found = false;
|
||||
|
||||
// error log version
|
||||
// Error log version
|
||||
{
|
||||
pcrecpp::RE re("^(SMART Error Log Version):[ \\t]*(.*)$", re_options);
|
||||
pcrecpp::RE re = app_pcre_re("/^(SMART Error Log Version):[ \\t]*(.*)$/mi");
|
||||
|
||||
std::string name, value;
|
||||
if (re.PartialMatch(sub, &name, &value)) {
|
||||
@@ -1138,11 +1283,24 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
// error log count
|
||||
// Error log support
|
||||
{
|
||||
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Error Logging)$/mi");
|
||||
|
||||
if (re.PartialMatch(sub)) {
|
||||
StorageProperty p(pt);
|
||||
p.set_name("error_log_unsupported");
|
||||
p.readable_name = "Warning";
|
||||
p.readable_value = "Device does not support error logging";
|
||||
add_property(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Error log enty count
|
||||
{
|
||||
// note: these represent the same information
|
||||
pcrecpp::RE re1("^ATA Error Count:[ \\t]*([0-9]+)", re_options);
|
||||
pcrecpp::RE re2("^No Errors Logged$", re_options);
|
||||
pcrecpp::RE re1 = app_pcre_re("/^ATA Error Count:[ \\t]*([0-9]+)/mi");
|
||||
pcrecpp::RE re2 = app_pcre_re("/^No Errors Logged$/mi");
|
||||
|
||||
std::string value;
|
||||
if (re1.PartialMatch(sub, &value) || re2.PartialMatch(sub)) {
|
||||
@@ -1167,11 +1325,14 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
// individual errors
|
||||
{
|
||||
// split by blocks
|
||||
pcrecpp::RE re_block("^((Error[ \\t]*([0-9]+))[ \\t]*occurred at disk power-on lifetime:[ \\t]*([0-9]+) hours.*(?:\\n(?: |\\n ).*)*)", re_options);
|
||||
pcrecpp::RE re_block = app_pcre_re("/^((Error[ \\t]*([0-9]+))[ \\t]*occurred at disk power-on lifetime:[ \\t]*([0-9]+) hours.*(?:\\n(?: |\\n ).*)*)/mi");
|
||||
|
||||
// for "in an unknown state" - remove first two words.
|
||||
pcrecpp::RE re_state("occurred, the device was[ \\t]*(?: in)?(?: an?)?[ \\t]+([^.\\n]*)\\.?", re_options);
|
||||
pcrecpp::RE re_type("[ \\t]+Error:[ \\t]*([^ \\t\\n]+)[ \\t]*(.*)$", re_options);
|
||||
// " When the command that caused the error occurred, the device was active or idle."
|
||||
// Note: For "in an unknown state" - remove first two words.
|
||||
pcrecpp::RE re_state = app_pcre_re("/occurred, the device was[ \\t]*(?: in)?(?: an?)?[ \\t]+([^.\\n]*)\\.?/mi");
|
||||
// " 84 51 2c 71 cd 3f e6 Error: ICRC, ABRT 44 sectors at LBA = 0x063fcd71 = 104844657"
|
||||
// " 40 51 00 f5 41 61 e0 Error: UNC at LBA = 0x006141f5 = 6373877"
|
||||
pcrecpp::RE re_type = app_pcre_re("/[ \\t]+Error:[ \\t]*([ ,a-z]+)[ \\t]+((?:[0-9]+|at )[ \\t]*.*)$/mi");
|
||||
|
||||
std::string block, name, value_num, value_time;
|
||||
pcrecpp::StringPiece input(sub); // position tracker
|
||||
@@ -1182,9 +1343,9 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
hz::string_trim(value_time);
|
||||
// debug_out_dump("app", "\nBLOCK -------------------------------\n" << block);
|
||||
|
||||
std::string state, etype, emore;
|
||||
std::string state, etypes_str, emore;
|
||||
re_state.PartialMatch(block, &state);
|
||||
re_type.PartialMatch(block, &etype, &emore);
|
||||
re_type.PartialMatch(block, &etypes_str, &emore);
|
||||
|
||||
StorageProperty p(pt);
|
||||
p.set_name(hz::string_trim_copy(name)); // "Error 6"
|
||||
@@ -1194,8 +1355,14 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
|
||||
hz::string_is_numeric(value_num, p.value_error_block.error_num, false);
|
||||
hz::string_is_numeric(value_time, p.value_error_block.lifetime_hours, false);
|
||||
|
||||
std::vector<std::string> etypes;
|
||||
hz::string_split(etypes_str, ",", etypes, true);
|
||||
for (std::vector<std::string>::iterator iter = etypes.begin(); iter != etypes.end(); ++iter) {
|
||||
hz::string_trim(*iter);
|
||||
}
|
||||
|
||||
p.value_error_block.device_state = hz::string_trim_copy(state);
|
||||
p.value_error_block.reported_type = hz::string_trim_copy(etype);
|
||||
p.value_error_block.reported_types = etypes;
|
||||
p.value_error_block.type_more_info = hz::string_trim_copy(emore);
|
||||
|
||||
add_property(p);
|
||||
@@ -1234,9 +1401,6 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_selftest_log;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
// Self-test log contains:
|
||||
// * structure revision number
|
||||
// * a list of current / previous tests performed, with each having:
|
||||
@@ -1249,7 +1413,7 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
|
||||
bool data_found = false; // true if something was found.
|
||||
|
||||
// the whole subsection
|
||||
// The whole subsection
|
||||
{
|
||||
StorageProperty p(pt);
|
||||
p.set_name("SMART Self-test log", "selftest_log");
|
||||
@@ -1262,12 +1426,25 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
}
|
||||
|
||||
|
||||
// self-test log version
|
||||
// Self-test log support
|
||||
{
|
||||
pcrecpp::RE re = app_pcre_re("/^(Warning: device does not support Self Test Logging)$/mi");
|
||||
|
||||
if (re.PartialMatch(sub)) {
|
||||
StorageProperty p(pt);
|
||||
p.set_name("selftest_log_unsupported");
|
||||
p.readable_name = "Warning";
|
||||
p.readable_value = "Device does not support self-test logging";
|
||||
add_property(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Self-test log version
|
||||
{
|
||||
// newer smartctl (since smartctl 5.1-16)
|
||||
pcrecpp::RE re1("(SMART Self-test log structure[^\\n0-9]*)([^ \\n]+)[ \\t]*$", re_options);
|
||||
pcrecpp::RE re1 = app_pcre_re("/(SMART Self-test log structure[^\\n0-9]*)([^ \\n]+)[ \\t]*$/mi");
|
||||
// older smartctl
|
||||
pcrecpp::RE re2("(SMART Self-test log, version number[^\\n0-9]*)([^ \\n]+)[ \\t]*$", re_options);
|
||||
pcrecpp::RE re2 = app_pcre_re("/(SMART Self-test log, version number[^\\n0-9]*)([^ \\n]+)[ \\t]*$/mi");
|
||||
|
||||
std::string name, value;
|
||||
if (re1.PartialMatch(sub, &name, &value) || re2.PartialMatch(sub, &name, &value)) {
|
||||
@@ -1295,9 +1472,9 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
|
||||
// individual entries
|
||||
{
|
||||
// split by columns (minimum 2 spaces between them)
|
||||
// num, type, status, remaining, hours, lba
|
||||
pcrecpp::RE re("^(#[ \\t]*([0-9]+)[ \\t]*(\\S.*) [ \\t]*(\\S.*) [ \\t]*([0-9]+%) [ \\t]*([0-9]+) [ \\t]*(\\S.*))$", re_options);
|
||||
// split by columns.
|
||||
// num, type, status, remaining, hours, lba (optional).
|
||||
pcrecpp::RE re = app_pcre_re("/^(#[ \\t]*([0-9]+)[ \\t]+(\\S+(?: \\S+)*) [ \\t]*(\\S.*) [ \\t]*([0-9]+%) [ \\t]*([0-9]+)[ \\t]*((?: [ \\t]*\\S.*)?))$/mi");
|
||||
|
||||
std::string line, num, type, status_str, remaining, hours, lba;
|
||||
pcrecpp::StringPiece input(sub); // position tracker
|
||||
@@ -1316,6 +1493,9 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
|
||||
|
||||
p.value_selftest_entry.type = hz::string_trim_copy(type);
|
||||
p.value_selftest_entry.lba_of_first_error = hz::string_trim_copy(lba);
|
||||
// old smartctls didn't print anything for lba if none, but newer ones print "-". normalize.
|
||||
if (p.value_selftest_entry.lba_of_first_error == "")
|
||||
p.value_selftest_entry.lba_of_first_error = "-";
|
||||
|
||||
hz::string_trim(status_str);
|
||||
StorageSelftestEntry::status_t status = StorageSelftestEntry::status_unknown;
|
||||
@@ -1384,10 +1564,6 @@ bool SmartctlParser::parse_section_data_subsection_selective_selftest_log(const
|
||||
pt.section = StorageProperty::section_data;
|
||||
pt.subsection = StorageProperty::subsection_selective_selftest_log;
|
||||
|
||||
pcrecpp::RE_Options re_options;
|
||||
re_options.set_caseless(true).set_multiline(true);
|
||||
|
||||
|
||||
// Selective self-test log contains:
|
||||
// * 5 (maybe less/more?) test entries, each with
|
||||
// span / min_lba / max_lba / current_test_status.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -28,13 +28,12 @@ class SmartctlParser {
|
||||
bool parse_full(const std::string& s);
|
||||
|
||||
|
||||
// supply output of "smartctl --version" here.
|
||||
// returns empty string on failure.
|
||||
static std::string parse_version(const std::string& s);
|
||||
// supply any output of smartctl here.
|
||||
static bool parse_version(const std::string& s, std::string& version, std::string& version_full);
|
||||
|
||||
|
||||
// check that the version of smartctl output can be parsed with this parser.
|
||||
static bool check_version(const std::string& version_str);
|
||||
static bool check_version(const std::string& version_str, const std::string& version_full_str);
|
||||
|
||||
|
||||
// convert e.g. "1,000,204,886,016 bytes" to 1.00 TiB [931.51 GB, 1000204886016 bytes]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_whatever.txt
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#undef HZ_USE_LIBDEBUG
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_whatever.txt
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <glibmm.h>
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Glib::thread_init();
|
||||
// g_thread_init(NULL);
|
||||
|
||||
GPid pid;
|
||||
int fd_stdout = 0, fd_stderr = 0;
|
||||
@@ -44,7 +42,6 @@ int main(int argc, char** argv)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
GIOChannel* channel_stdout = g_io_channel_win32_new_fd(fd_stdout);
|
||||
GIOChannel* channel_stderr = g_io_channel_win32_new_fd(fd_stderr);
|
||||
@@ -54,24 +51,22 @@ int main(int argc, char** argv)
|
||||
#endif
|
||||
|
||||
// blocking writes if the pipe is full helps for small-pipe systems (see man 7 pipe).
|
||||
GIOFlags flags = GIOFlags(~G_IO_FLAG_NONBLOCK);
|
||||
int channel_flags = ~G_IO_FLAG_NONBLOCK;
|
||||
|
||||
if (channel_stdout) {
|
||||
g_io_channel_set_encoding(channel_stdout, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stdout, flags, 0);
|
||||
g_io_channel_set_flags(channel_stdout, GIOFlags(g_io_channel_get_flags(channel_stdout) & channel_flags), 0);
|
||||
g_io_channel_set_buffer_size(channel_stdout, 10000);
|
||||
}
|
||||
|
||||
if (channel_stderr) {
|
||||
g_io_channel_set_encoding(channel_stderr, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stderr, flags, 0);
|
||||
g_io_channel_set_flags(channel_stderr, GIOFlags(g_io_channel_get_flags(channel_stderr) & channel_flags), 0);
|
||||
g_io_channel_set_buffer_size(channel_stderr, 10000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
g_main_loop_run(g_main_loop_new(NULL, false));
|
||||
|
||||
|
||||
|
||||
+29
-572
@@ -1,597 +1,55 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "hz/hz_config.h" // CONFIG_*
|
||||
|
||||
#include <ios> // std::boolalpha
|
||||
// #include <glibmm/fileutils.h> // Dir
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets()
|
||||
#include <cerrno> // ENXIO
|
||||
|
||||
#if defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
#include <util.h> // getrawpartition()
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_KERNEL_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_dir.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "hz/string_sprintf.h"
|
||||
#include "hz/local_algo.h" // hz::shell_sort()
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
|
||||
#include "app_pcrecpp.h"
|
||||
#include "smartctl_executor.h"
|
||||
#include "storage_detector.h"
|
||||
|
||||
#include "storage_detector_linux.h"
|
||||
#include "storage_detector_win32.h"
|
||||
#include "storage_detector_other.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
// Note: Since 3ware RAID controllers need additional flags on most (all?) OSes,
|
||||
// and they may ignore the actual devices names, I have no idea how to support them.
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
|
||||
// Linux 2.6 with udev. Scan /dev/disk/by-id - the directory entries there
|
||||
// are symlinks to respective /dev devices. Some devices have multiple
|
||||
// links pointing to them, so unique filter is needed.
|
||||
/*
|
||||
Sample listing:
|
||||
------------------------------------------------------------
|
||||
# ls -1 /dev/disk/by-id
|
||||
ata-ST31000340AS_9QJ0FFG7
|
||||
ata-ST31000340AS_9QJ0FFG7-part1
|
||||
ata-ST31000340AS_9QJ0FFG7-part2
|
||||
ata-ST3500630AS_9QG0R38D
|
||||
ata-ST3500630AS_9QG0R38D-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part2
|
||||
scsi-SATA_ST3500630AS_9QG0R38D
|
||||
scsi-SATA_ST3500630AS_9QG0R38D-part1
|
||||
*/
|
||||
inline std::string detect_drives_linux_udev_byid(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through device scan directory /dev/disk/by-id...\n");
|
||||
|
||||
std::string dev_dir; // this defaults to "/dev/disk/by-id"
|
||||
if (!rconfig::get_data("system/linux_udev_byid_path", dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory path is not set.\n");
|
||||
return "Device scan directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.entry_list(all_devices, false)) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
blacklist.push_back("/-part[0-9]+$/");
|
||||
|
||||
// filter-out the ones with "partN" in them
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// those are usually relative links, so find out where they are pointing to.
|
||||
std::string link_dest;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
path.compress(); // compress in case there are ../-s.
|
||||
}
|
||||
|
||||
// skip number-ended devices, in case we couldn't filter out the scan directory correctly
|
||||
// (it's user-settable after all).
|
||||
// if (app_pcre_match("/[0-9]+$/", path.str()))
|
||||
// continue;
|
||||
|
||||
if (std::find(devices.begin(), devices.end(), path.str()) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path.str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Procfs files don't support SEEK_END or ftello() (I think). Anyway, they can't
|
||||
// be read through hz::File::get_contents, so use this function instead.
|
||||
inline bool read_proc_partitions_file(hz::File& file, std::vector<std::string>& lines)
|
||||
{
|
||||
if (!file.open("rb")) // closed automatically
|
||||
return false; // the error message is in File itself.
|
||||
|
||||
FILE* fp = file.get_handle();
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char line[256];
|
||||
while (std::fgets(line, sizeof(line), fp) != NULL) {
|
||||
if (*line != '\0')
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Linux (tested with 2.4 and 2.6) /proc/partitions. Parses the file, appends /dev to each entry.
|
||||
// Note that file format changed from 2.4 to 2.6 (some statistics fields moved to another file).
|
||||
// No /proc/partitions on at least freebsd, solaris and osx, afaik.
|
||||
/*
|
||||
Sample 1 (2.4, devfs, with statistics):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
||||
|
||||
3 0 60051600 ide/host0/bus0/target0/lun0/disc 72159 136746 1668720 467190 383039 658435 8342136 1659840 -429 17038808 22703194
|
||||
3 1 1638598 ide/host0/bus0/target0/lun0/part1 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 2 1028160 ide/host0/bus0/target0/lun0/part2 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3092512 ide/host0/bus0/target0/lun0/part3 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 4 1 ide/host0/bus0/target0/lun0/part4 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 5 514048 ide/host0/bus0/target0/lun0/part5 1458 7877 74680 9070 2140 18285 166272 42490 0 10100 52000
|
||||
------------------------------------------------------------
|
||||
Sample 2 (2.6):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
1 0 4096 ram0
|
||||
8 0 156290904 sda
|
||||
8 1 39070048 sda1
|
||||
8 2 7560 sda2
|
||||
8 3 1 sda3
|
||||
------------------------------------------------------------
|
||||
Sample 3 (2.6 on nokia n8xx, spaces may be missing):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
31 0 128 mtdblock0
|
||||
31 1 384 mtdblock1
|
||||
31 2 2048 mtdblock2
|
||||
31 3 2048 mtdblock3
|
||||
31 4 257536 mtdblock4
|
||||
254 0 3932160 mmcblk0
|
||||
254 1 3928064 mmcblk0p1
|
||||
254 8 1966080 mmcblk1
|
||||
254 9 2007032 mmcblk1p1
|
||||
*/
|
||||
inline std::string detect_drives_linux_proc_partitions(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /proc/partitions...\n");
|
||||
|
||||
std::string parts_file;
|
||||
if (!rconfig::get_data("system/linux_proc_partitions_path", parts_file) || parts_file.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file path is not set.\n");
|
||||
return "Partitions file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(parts_file);
|
||||
// std::string contents;
|
||||
std::vector<std::string> lines;
|
||||
// if (!f.get_contents(contents)) {
|
||||
if (!read_proc_partitions_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Partitions file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
// debug_out_dump("app", DBG_FUNC_MSG << "Dumping partitions file:\n" << contents << "\n");
|
||||
|
||||
// hz::string_split(contents, '\n', lines, true);
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
// fixme: not sure about how partitions are visible with twa0.
|
||||
blacklist.push_back("/d[a-z][0-9]+$/"); // sda1, hdb2 - partitions. twa0 and twe1 are drives, not partitions.
|
||||
blacklist.push_back("/ram[0-9]+$/"); // ramdisks?
|
||||
blacklist.push_back("/loop[0-9]*$/"); // not sure if loop devices go there, but anyway...
|
||||
blacklist.push_back("/part[0-9]+$/"); // devfs had them
|
||||
blacklist.push_back("/p[0-9]+$/"); // partitions are usually marked this way
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < lines.size(); ++i) {
|
||||
std::string line = hz::string_trim_copy(lines[i]);
|
||||
if (line.empty() || app_pcre_match("/^major/", line)) // file header
|
||||
continue;
|
||||
|
||||
std::string dev;
|
||||
if (!app_pcre_match("/^[ \\t]*[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+([^ \\t\\n]+)/", line, &dev) || dev.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse line \"" << line << "\".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, dev)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
std::string path = "/dev/" + dev;
|
||||
if (std::find(devices.begin(), devices.end(), path) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path);
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_WINDOWS
|
||||
|
||||
|
||||
// smartctl accepts various variants, but \\.\PhysicalDriveN
|
||||
// seems to be the most native and acceptable.
|
||||
|
||||
inline std::string detect_drives_win32(std::vector<std::string>& devices)
|
||||
{
|
||||
for (int drive_num = 0; ; ++drive_num) {
|
||||
// If the drive is openable, then it's there.
|
||||
// NOTE: Administrative privileges are required to open it.
|
||||
std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num);
|
||||
HANDLE h = CreateFile(name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
// The numbers seem to be continuous, so break on first invalid.
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
CloseHandle (h);
|
||||
|
||||
// smartctl uses /dev/pdN for \\.\PhysicalDrive N.
|
||||
devices.push_back(hz::string_sprintf("/dev/pd%d", drive_num));
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else // FreeBSD, Solaris, etc... .
|
||||
|
||||
|
||||
inline std::string detect_drives_dev(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /dev...\n");
|
||||
|
||||
std::string sdev_config_path;
|
||||
#ifdef CONFIG_KERNEL_SOLARIS
|
||||
sdev_config_path = "system/solaris_dev_path";
|
||||
#else // other unixes
|
||||
sdev_config_path = "system/unix_sdev_path";
|
||||
#endif
|
||||
|
||||
std::string dev_dir; // defaults to /dev for freebsd, /dev/rdsk for solaris.
|
||||
if (!rconfig::get_data(sdev_config_path, dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory path is not set.\n");
|
||||
return "Device directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.entry_list(all_devices, false, hz::DirSortNone())) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
// platform whitelist
|
||||
std::vector<std::string> whitelist;
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY
|
||||
// FreeBSD example device names:
|
||||
// * /dev/ad0 - ide disk 0. /dev/ad0a - non-slice dos partition 1.
|
||||
// * /dev/da1s1e - scsi disk 1 (second disk), slice 1 (aka dos partition 1),
|
||||
// bsd partition e (multiple bsd partitions may be inside one dos partition).
|
||||
// * /dev/acd0 - first cdrom. /dev/acd0c - ?.
|
||||
// Info: http://www.freebsd.org/doc/en/books/handbook/disks-naming.html
|
||||
|
||||
// Of two machines I had access to, freebsd 6.3 had only real devices,
|
||||
// while freebsd 4.10 had lots of dummy ones (ad1, ad2, ad3, da0, da1, da2, da3, sa0, ...).
|
||||
|
||||
whitelist.push_back("/^ad[0-9]+$/"); // adN without suffix - fbsd ide
|
||||
whitelist.push_back("/^da[0-9]+$/"); // daN without suffix - fbsd scsi, usb
|
||||
// whitelist.push_back("/ ^sa[0-9]+$/"); // saN without suffix - fbsd scsi tape
|
||||
// whitelist.push_back("/^ast[0-9]+$/"); // astN without suffix - fbsd ide tape
|
||||
whitelist.push_back("/^aacd[0-9]+$/"); // fbsd adaptec raid
|
||||
whitelist.push_back("/^mlxd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^mlyd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^amrd[0-9]+$/"); // fbsd AMI raid
|
||||
whitelist.push_back("/^idad[0-9]+$/"); // fbsd compaq raid
|
||||
whitelist.push_back("/^twed[0-9]+$/"); // fbsd 3ware raid
|
||||
// these are checked by smartctl, but they are not mentioned in freebsd docs:
|
||||
whitelist.push_back("/^tw[ae][0-9]+$/"); // fbsd 3ware raid
|
||||
// unused: acd - ide cdrom, cd - scsi cdrom, mcd - mitsumi cdrom, scd - sony cdrom,
|
||||
// fd - floppy, fla - diskonchip flash.
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_SOLARIS
|
||||
|
||||
// /dev/rdsk contains "raw" physical char devices, as opposed to
|
||||
// "filesystem" block devices in /dev/dsk. smartctl needs rdsk.
|
||||
|
||||
// x86:
|
||||
|
||||
// /dev/rdsk/c0t0d0p0:1
|
||||
// Where c0 is the controller number.
|
||||
// t0 is the target (SCSI ID number) (omit for ATAPI)
|
||||
// d0 is always 0 for SCSI, the drive # for ATAPI
|
||||
// p0 is the partition (p0 is the entire disk, or p1 - p4)
|
||||
// :1 is the logical drive (c - z or 1 - 24) (that is, logical partitions inside extended partition)
|
||||
|
||||
// /dev/rdsk/c0d0p2:1
|
||||
// where p2 means the extended partition (type 0x05) is partition 2 (out of 1-4) and
|
||||
// ":1" is the 2nd extended partition (:0 would be the first extended partition). -- not sure about this!
|
||||
|
||||
// p0 whole physical disk
|
||||
// p1 - p4 Four primary fdisk partitions
|
||||
// p5 - p30 26 logical drives in extended DOS partition (not implemented by Solaris)
|
||||
// s0 - s15 16 slices in the Solaris FDISK partition (SPARC has only 8)
|
||||
// On Solaris, by convention, s2 is the whole Solaris partition.
|
||||
|
||||
// SPARC: There are no *p* devices on sparc afaik, only slices. By convention,
|
||||
// s2 is used as a "whole" disk there (but not with EFI partitions!).
|
||||
// So, c0d0s2 is the whole disk there.
|
||||
// x86 has both c0d0s2 and c0d0p2, where s2 is a whole solaris partition.
|
||||
|
||||
// NOTE: It seems that smartctl searches for s0 (aka root partition) in the end. I'm not sure
|
||||
// what implications this has for x86, but we replicate this behaviour.
|
||||
|
||||
// Note: Cdroms are ATAPI, so they pose as SCSI, as opposed to IDE hds.
|
||||
|
||||
// TODO: No idea how to implement /dev/rmt (scsi tape devices),
|
||||
// I have no files in that directory.
|
||||
|
||||
whitelist.push_back("/^c[0-9]+(?:t[0-9]+)?d[0-9]+s0$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
|
||||
// OpenBSD / NetBSD have /dev/wdNc for IDE/ATA, /dev/sdNc for SCSI disk,
|
||||
// /dev/stNc for scsi tape. N is [0-9]+. "c" means "whole disk" (not sure about
|
||||
// different architectures though). There are no "sdN" devices, only "sdNP".
|
||||
// Another manual says that wd0d would be a whole disk, while wd0c is its
|
||||
// bsd part only (on x86) (only on netbsd?). Anyway, getrawpartition() gives
|
||||
// us the letter we need.
|
||||
// There is no additional level of names for BSD subpartitions (unlike freebsd).
|
||||
// cd0a is cdrom.
|
||||
// Dummy devices are present.
|
||||
|
||||
// Note: This detection may take a while (probably due to open() check).
|
||||
|
||||
char whole_part = 'a' + getrawpartition(); // from bsd's util.h
|
||||
|
||||
whitelist.push_back(hz::string_sprintf("/^wd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^sd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^st[0-9]+%c$/", whole_part));
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_DARWIN
|
||||
|
||||
// Darwin has /dev/disk0, /dev/disk0s1, etc...
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^disk[0-9]+$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_QNX
|
||||
|
||||
// QNX has /dev/hd0, /dev/hd0t78 (partition?).
|
||||
// Afaik, IDE and SCSI have the same prefix. fd for floppy, cd for cdrom.
|
||||
// Not sure about the tapes.
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^hd[0-9]+$/");
|
||||
|
||||
|
||||
#endif // unix platforms
|
||||
|
||||
|
||||
std::vector<std::string> matched_devices;
|
||||
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
bool matched = false;
|
||||
for (std::vector<std::string>::const_iterator iter = whitelist.begin(); iter != whitelist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// In case these are links, trace them to originals.
|
||||
// We don't replace /dev files with real devices - it leads to really bad paths (pci ids for solaris, etc...).
|
||||
std::string link_dest;
|
||||
hz::FsPath real_dev_path;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
real_dev_path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
real_dev_path.compress(); // compress in case there are ../-s.
|
||||
|
||||
// solaris has dangling links for non-existant devices, so filter them out.
|
||||
if (!real_dev_path.exists())
|
||||
continue;
|
||||
}
|
||||
|
||||
matched_devices.push_back(path.str());
|
||||
}
|
||||
|
||||
|
||||
// List ones who need dummy device filtering
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY \
|
||||
|| defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
// Since we may have encountered dummy devices, we should check
|
||||
// if they really exist. Unfortunately, this involves opening them, which
|
||||
// is not good with some media (e.g. it may hang on audio cd (freebsd, maybe others), etc...).
|
||||
// That's why we don't whitelist cd devices. Let's hope usb and others are
|
||||
// ok with this. Dummy devices give errno ENXIO (6, Device not configured) on *bsd.
|
||||
// In Linux ENXIO is (6, No such device or address).
|
||||
|
||||
// Don't do this on solaris - we can't distinguish between cdroms and hds there.
|
||||
|
||||
// If there are less than 4 devices, they are probably not dummy (newer freebsd).
|
||||
bool open_needed = (matched_devices.size() >= 4);
|
||||
if (open_needed) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", will try to filter non-existent ones out.\n");
|
||||
} else {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", no need for filtering them out.\n");
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < matched_devices.size(); ++i) {
|
||||
hz::File dev_file(matched_devices[i]);
|
||||
|
||||
// we check errno because OS may deny us for some other reason on valid devices.
|
||||
if (open_needed && !dev_file.open("rb") && dev_file.get_errno() == ENXIO) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" failed to open, ignoring.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (open_needed)
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" opened successfully, adding to device list.\n");
|
||||
|
||||
devices.push_back(dev_file.str());
|
||||
}
|
||||
|
||||
#else // not *BSD
|
||||
for (unsigned int i = 0; i < matched_devices.size(); ++i) {
|
||||
devices.push_back(matched_devices[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
hz::shell_sort(devices.begin(), devices.end());
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
#endif // platforms
|
||||
|
||||
|
||||
|
||||
} // anon. ns
|
||||
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
|
||||
std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Starting drive detection.\n");
|
||||
|
||||
std::vector<std::string> devices;
|
||||
std::vector<StorageDeviceRefPtr> all_detected;
|
||||
std::string error_msg;
|
||||
bool found = false;
|
||||
|
||||
// Try each one and move to next if it fails.
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_udev_byid(devices); // linux udev
|
||||
// we check for devices vector emptiness because it could be a dummy directory
|
||||
// with no files, so treat it as an error.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
error_msg = detect_drives_linux(all_detected, ex_factory); // linux /proc/partitions as fallback.
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_proc_partitions(devices); // linux /proc/partitions as fallback.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined CONFIG_KERNEL_WINDOWS
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_win32(devices); // win32
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
#elif defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
|
||||
error_msg = detect_drives_win32(all_detected, ex_factory); // win32
|
||||
|
||||
#else // freebsd, etc...
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_dev(devices); // bsd, etc... . scans /dev.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
error_msg = detect_drives_other(all_detected, ex_factory); // bsd, etc... . scans /dev.
|
||||
|
||||
#endif
|
||||
|
||||
if (!found) {
|
||||
if (all_detected.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot detect drives: None of the drive detection methods returned any drives.\n");
|
||||
return error_msg; // last error message should be ok.
|
||||
}
|
||||
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter = devices.begin(); iter != devices.end(); ++iter) {
|
||||
std::string dev = *iter;
|
||||
for (std::vector<StorageDeviceRefPtr>::iterator iter = all_detected.begin(); iter != all_detected.end(); ++iter) {
|
||||
StorageDeviceRefPtr drive = *iter;
|
||||
|
||||
// try to match against patterns
|
||||
// for (unsigned int i = 0; i < match_patterns_.size(); i++) {
|
||||
@@ -602,21 +60,20 @@ std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
|
||||
// matched, check the blacklist
|
||||
bool blacked = false;
|
||||
for (unsigned int j = 0; j < blacklist_patterns_.size(); j++) {
|
||||
if (app_pcre_match(blacklist_patterns_[j], dev)) { // matched the blacklist too
|
||||
if (app_pcre_match(blacklist_patterns_[j], drive->get_device())) { // matched the blacklist too
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StorageDeviceRefPtr drive(new StorageDevice(dev));
|
||||
debug_out_info("app", "Found device: \"" << drive->get_device() << "\".\n");
|
||||
debug_out_info("app", "Found device: " << drive->get_device_with_type() << ".\n");
|
||||
|
||||
if (!blacked) {
|
||||
drives.push_back(drive);
|
||||
// break; // no need to match other patters, go to next device
|
||||
|
||||
} else { // blacklisted
|
||||
debug_out_info("app", "Device \"" << drive->get_device() << "\" is blacklisted, ignoring.\n");
|
||||
debug_out_info("app", "Device " << drive->get_device_with_type() << " is blacklisted, ignoring.\n");
|
||||
// break; // go to next device
|
||||
}
|
||||
// }
|
||||
@@ -630,27 +87,26 @@ std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
|
||||
|
||||
|
||||
std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>& drives,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex, bool return_first_error)
|
||||
ExecutorFactoryRefPtr ex_factory, bool return_first_error)
|
||||
{
|
||||
fetch_data_errors_.clear();
|
||||
fetch_data_error_outputs_.clear();
|
||||
|
||||
|
||||
// If it doesn't exist, create a default one. Even though it will be auto-created later,
|
||||
// we need it here to get its errors afterwards.
|
||||
if (!smartctl_ex)
|
||||
smartctl_ex = new SmartctlExecutor(); // will be auto-deleted
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
for (unsigned int i = 0; i < drives.size(); ++i) {
|
||||
StorageDeviceRefPtr drive = drives[i];
|
||||
debug_out_info("app", "Retrieving basic information about the device...\n");
|
||||
|
||||
smartctl_ex->set_running_msg("Running %s on " + drive->get_device() + "...");
|
||||
smartctl_ex->set_running_msg("Running %s on " + drive->get_device_with_type() + "...");
|
||||
|
||||
// don't show any errors here - we don't want a screen flood.
|
||||
// no need for gui-based executors here, we already show the message in
|
||||
// iconview background (if called from main window)
|
||||
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
std::string error_msg;
|
||||
if (drive->get_info_output().empty()) { // if not fetched during detection
|
||||
error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
}
|
||||
|
||||
// normally we skip drives with errors - possibly scsi, etc...
|
||||
if (return_first_error && !error_msg.empty())
|
||||
@@ -665,9 +121,10 @@ std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>&
|
||||
fetch_data_error_outputs_.push_back(smartctl_ex->get_stdout_str());
|
||||
}
|
||||
|
||||
debug_out_dump("app", "Device information for " << drive->get_device() << ":\n"
|
||||
debug_out_dump("app", "Device information for " << drive->get_device()
|
||||
<< " (type: \"" << drive->get_type_argument() << "\"):\n"
|
||||
<< "\tModel: " << drive->get_model_name() << "\n"
|
||||
<< "\tType: " << StorageDevice::get_type_name(drive->get_type()) << "\n"
|
||||
<< "\tDetected type: " << StorageDevice::get_type_readable_name(drive->get_detected_type()) << "\n"
|
||||
<< "\tSMART status: " << StorageDevice::get_status_name(drive->get_smart_status()) << "\n"
|
||||
);
|
||||
|
||||
@@ -679,12 +136,12 @@ std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>&
|
||||
|
||||
|
||||
std::string StorageDetector::detect_and_fetch_basic_data(std::vector<StorageDeviceRefPtr>& put_drives_here,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::string error_msg = detect(put_drives_here);
|
||||
std::string error_msg = detect(put_drives_here, ex_factory);
|
||||
|
||||
if (error_msg.empty())
|
||||
fetch_basic_data(put_drives_here, smartctl_ex, false); // ignore its errors, there may be plenty of them.
|
||||
fetch_basic_data(put_drives_here, ex_factory, false); // ignore its errors, there may be plenty of them.
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "storage_device.h"
|
||||
#include "cmdex_sync.h"
|
||||
#include "executor_factory.h"
|
||||
|
||||
|
||||
|
||||
@@ -28,17 +29,18 @@ class StorageDetector {
|
||||
|
||||
|
||||
// detects a list of drives. returns detection error if error occurs.
|
||||
std::string detect(std::vector<StorageDeviceRefPtr>& put_drives_here);
|
||||
std::string detect(std::vector<StorageDeviceRefPtr>& put_drives_here,
|
||||
ExecutorFactoryRefPtr ex_factory);
|
||||
|
||||
|
||||
// fetch basic data of "drives" elements
|
||||
std::string fetch_basic_data(std::vector<StorageDeviceRefPtr>& drives,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = 0, bool return_first_error = false);
|
||||
ExecutorFactoryRefPtr ex_factory, bool return_first_error = false);
|
||||
|
||||
|
||||
// do both of the above, return detection error.
|
||||
std::string detect_and_fetch_basic_data(std::vector<StorageDeviceRefPtr>& put_drives_here,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
|
||||
ExecutorFactoryRefPtr ex_factory);
|
||||
|
||||
|
||||
// void add_match_patterns(std::vector<std::string>& patterns)
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_DETECTOR_HELPERS_H
|
||||
#define STORAGE_DETECTOR_HELPERS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "executor_factory.h"
|
||||
#include "storage_device.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Get number of ports using tw_cli. Return -1 on error.
|
||||
inline std::string tw_cli_get_drives(const std::string& dev, int scsi_host_no,
|
||||
std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory, bool use_tw_cli_dev)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string command_options = hz::string_sprintf("/c%d show all", scsi_host_no);
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), command_options);
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
pcrecpp::RE port_re = app_pcre_re("/^p([0-9])+[ \\t]+([^\\t\\n]+)/mi");
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string port_str, status;
|
||||
if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &port_str, &status)) {
|
||||
if (status != "NOT-PRESENT") {
|
||||
int port = -1;
|
||||
hz::string_is_numeric(port_str, port);
|
||||
if (port != -1) {
|
||||
if (use_tw_cli_dev) { // use "tw_cli/cx/py" device
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice("tw_cli/c"
|
||||
+ hz::number_to_string(scsi_host_no) + "/p" + hz::number_to_string(port))));
|
||||
} else {
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(dev, "3ware," + hz::number_to_string(port))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Return 3ware SCSI host numbers (same as /c switch to tw_cli)
|
||||
/// \return error string on error
|
||||
inline std::string tw_cli_get_controllers(ExecutorFactoryRefPtr ex_factory, std::vector<int>& controllers)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), "show");
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
pcrecpp::RE controller_re = app_pcre_re("/^c([0-9])+[ \\t]+/mi");
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string controller_str;
|
||||
if (controller_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &controller_str)) {
|
||||
int controller = -1;
|
||||
hz::string_is_numeric(controller_str, controller);
|
||||
if (controller != -1) {
|
||||
controllers.push_back(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,497 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "storage_detector_linux.h"
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets(), std::FILE
|
||||
#include <cerrno> // ENXIO
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_path_utils.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
// Linux 2.6 with udev. Scan /dev/disk/by-id - the directory entries there
|
||||
// are symlinks to respective /dev devices. Some devices have multiple
|
||||
// links pointing to them, so unique filter is needed.
|
||||
/*
|
||||
Sample listing:
|
||||
------------------------------------------------------------
|
||||
# ls -1 /dev/disk/by-id
|
||||
ata-ST31000340AS_9QJ0FFG7
|
||||
ata-ST31000340AS_9QJ0FFG7-part1
|
||||
ata-ST31000340AS_9QJ0FFG7-part2
|
||||
ata-ST3500630AS_9QG0R38D
|
||||
ata-ST3500630AS_9QG0R38D-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part2
|
||||
scsi-SATA_ST3500630AS_9QG0R38D
|
||||
scsi-SATA_ST3500630AS_9QG0R38D-part1
|
||||
*/
|
||||
/*
|
||||
// We don't use udev anymore - not all distros have it, and e.g. Ubuntu
|
||||
// has it all wrong (two symlinks (sda, sdb) pointing both to sdb).
|
||||
inline std::string detect_drives_linux_udev_byid(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through device scan directory /dev/disk/by-id...\n");
|
||||
|
||||
std::string dev_dir; // this defaults to "/dev/disk/by-id"
|
||||
if (!rconfig::get_data("system/linux_udev_byid_path", dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory path is not set.\n");
|
||||
return "Device scan directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.list(all_devices, false)) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
blacklist.push_back("/-part[0-9]+$/");
|
||||
|
||||
// filter-out the ones with "partN" in them
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// those are usually relative links, so find out where they are pointing to.
|
||||
std::string link_dest;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
path.compress(); // compress in case there are ../-s.
|
||||
}
|
||||
|
||||
// skip number-ended devices, in case we couldn't filter out the scan directory correctly
|
||||
// (it's user-settable after all).
|
||||
// if (app_pcre_match("/[0-9]+$/", path.str()))
|
||||
// continue;
|
||||
|
||||
if (std::find(devices.begin(), devices.end(), path.str()) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path.str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Procfs files don't support SEEK_END or ftello() (I think). Anyway, they can't
|
||||
// be read through hz::File::get_contents, so use this function instead.
|
||||
inline bool read_proc_file(hz::File& file, std::vector<std::string>& lines)
|
||||
{
|
||||
if (!file.open("rb")) // closed automatically
|
||||
return false; // the error message is in File itself.
|
||||
|
||||
std::FILE* fp = file.get_handle();
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char line[256];
|
||||
while (std::fgets(line, static_cast<int>(sizeof(line)), fp) != NULL) {
|
||||
if (*line != '\0')
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_partitions_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_partitions_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file path is not set.\n");
|
||||
return "Partitions file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Partitions file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_devices_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_devices_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Devices file path is not set.\n");
|
||||
return "Devices file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Devices file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Devices file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_scsi_scsi_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_scsi_scsi_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "SCSI file path is not set.\n");
|
||||
return "SCSI file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "SCSI file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "SCSI file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Get number of ports by sequentially running smartctl on each port, until
|
||||
/// one of the gives an error. Return -1 on error.
|
||||
inline std::string smartctl_get_drives(const std::string& dev, const std::string& type,
|
||||
int from, int to, std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
for (int i = from; i <= to; ++i) {
|
||||
std::string type_arg = hz::string_sprintf(type.c_str(), i);
|
||||
StorageDeviceRefPtr drive(new StorageDevice(dev, type_arg));
|
||||
|
||||
// std::string error_msg = execute_smartctl(dev, "-d " + type_arg, "-i", smartctl_ex, output);
|
||||
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
std::string output = drive->get_info_output();
|
||||
|
||||
// if we've reached smartctl port limit (older versions may have smaller limits), abort.
|
||||
if (app_pcre_match("/VALID ARGUMENTS ARE/mi", output)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_info("app", "Smartctl returned with an error: " << error_msg);
|
||||
} else {
|
||||
drives.push_back(drive);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Linux (tested with 2.4 and 2.6) /proc/partitions. Parses the file, appends /dev to each entry.
|
||||
// Note that file format changed from 2.4 to 2.6 (some statistics fields moved to another file).
|
||||
// No /proc/partitions on freebsd, solaris or osx, afaik.
|
||||
/*
|
||||
Sample 1 (2.4, devfs, with statistics):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
||||
|
||||
3 0 60051600 ide/host0/bus0/target0/lun0/disc 72159 136746 1668720 467190 383039 658435 8342136 1659840 -429 17038808 22703194
|
||||
3 1 1638598 ide/host0/bus0/target0/lun0/part1 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 2 1028160 ide/host0/bus0/target0/lun0/part2 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3092512 ide/host0/bus0/target0/lun0/part3 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 4 1 ide/host0/bus0/target0/lun0/part4 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 5 514048 ide/host0/bus0/target0/lun0/part5 1458 7877 74680 9070 2140 18285 166272 42490 0 10100 52000
|
||||
------------------------------------------------------------
|
||||
Sample 2 (2.6):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
1 0 4096 ram0
|
||||
8 0 156290904 sda
|
||||
8 1 39070048 sda1
|
||||
8 2 7560 sda2
|
||||
8 3 1 sda3
|
||||
------------------------------------------------------------
|
||||
Sample 3 (2.6 on nokia n8xx, spaces may be missing):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
31 0 128 mtdblock0
|
||||
31 1 384 mtdblock1
|
||||
31 2 2048 mtdblock2
|
||||
31 3 2048 mtdblock3
|
||||
31 4 257536 mtdblock4
|
||||
254 0 3932160 mmcblk0
|
||||
254 1 3928064 mmcblk0p1
|
||||
254 8 1966080 mmcblk1
|
||||
254 9 2007032 mmcblk1p1
|
||||
*/
|
||||
inline std::string detect_drives_linux_proc_partitions(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /proc/partitions...\n");
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::string error_msg = read_proc_partitions_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
// fixme: not sure about how partitions are visible with twa0.
|
||||
blacklist.push_back("/d[a-z][0-9]+$/"); // sda1, hdb2 - partitions. twa0 and twe1 are drives, not partitions.
|
||||
blacklist.push_back("/ram[0-9]+$/"); // ramdisks?
|
||||
blacklist.push_back("/loop[0-9]*$/"); // not sure if loop devices go there, but anyway...
|
||||
blacklist.push_back("/part[0-9]+$/"); // devfs had them
|
||||
blacklist.push_back("/p[0-9]+$/"); // partitions are usually marked this way
|
||||
blacklist.push_back("/md[0-9]*$/"); // linux software raid
|
||||
blacklist.push_back("/dm-[0-9]*$/"); // linux device mapper
|
||||
|
||||
std::vector<std::string> devices;
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string line = hz::string_trim_copy(lines[i]);
|
||||
if (line.empty() || app_pcre_match("/^major/", line)) // file header
|
||||
continue;
|
||||
|
||||
std::string dev;
|
||||
if (!app_pcre_match("/^[ \\t]*[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+([^ \\t\\n]+)/", line, &dev) || dev.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse line \"" << line << "\".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, dev)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
std::string path = "/dev/" + dev; // let's just hope the it's /dev.
|
||||
if (std::find(devices.begin(), devices.end(), path) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path);
|
||||
}
|
||||
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
StorageDeviceRefPtr drive(new StorageDevice(devices.at(i)));
|
||||
drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
|
||||
// 3ware controllers also export themselves as sd*. Smartctl detects that,
|
||||
// so we can avoid adding them. Older smartctl (5.38) prints "AMCC", newer one
|
||||
// prints "AMCC/3ware controller". It's better to search it this way.
|
||||
if (!app_pcre_match("/try adding '-d 3ware,N'/im", drive->get_info_output())) {
|
||||
drives.push_back(drive);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Detect drives behind 3ware RAID controller.
|
||||
|
||||
3ware Linux:
|
||||
Call as: smartctl -i -d 3ware,[0-127] /dev/twa[0-15] (or twe[0-15])
|
||||
Use twe* for [678]xxx series, and twa* for 9xxx series.
|
||||
Note: twe* devices are limited to [0-15] ports (not sure about this).
|
||||
Note: /dev/tw* devices may not exist, they are created by smartctl on the first run.
|
||||
Note: for twe*, /dev/sda may also exist (to be used with -d 3ware,N), we should
|
||||
somehow detect and ignore them.
|
||||
Note: when specifying non-existent port, either a "Device Read Identity Failed"
|
||||
error, or a "blank" info may be returned.
|
||||
Detection:
|
||||
Grep /proc/devices for "twa" or "twe" (e.g. "251 twa"). Use this for /dev/tw* part.
|
||||
Grep /proc/scsi/scsi for AMCC or 3ware (LSI too?), use number of matched lines N
|
||||
for /dev/tw*[0, N-1].
|
||||
For detecting the number of ports, use "tw_cli /cK show all", K being the controller
|
||||
scsi number, which is displayed as scsiK in the scsi file.
|
||||
If there's no tw_cli, we'll have to scan all the ports (up to supported maximum).
|
||||
This is too slow however, so scan only 24.
|
||||
|
||||
Implementation notes: it seems that twe uses "3ware" and twa uses "AMCC".
|
||||
We can't handle a situation with both twa and twe present, since we don't know
|
||||
how they will be ordered for tw_cli.
|
||||
*/
|
||||
inline std::string detect_drives_linux_3ware(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::string error_msg = read_proc_devices_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
bool twa_found = false;
|
||||
bool twe_found = false;
|
||||
|
||||
// Check /proc/devices for twa or twe
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string dev;
|
||||
if (app_pcre_match("/^[ \\t]*[0-9]+[ \\t]+(tw[ae])/", hz::string_trim_copy(lines[i]), &dev)) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Found " << dev << " entry in devices file.\n");
|
||||
if (dev == "twa") {
|
||||
twa_found = true;
|
||||
} else if (dev == "twe") {
|
||||
twe_found = true;
|
||||
} else {
|
||||
DBG_ASSERT(0); // error in regexp?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!twa_found && !twe_found) {
|
||||
return std::string(); // no controllers
|
||||
}
|
||||
|
||||
lines.clear();
|
||||
error_msg = read_proc_scsi_scsi_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
int num_controllers = 0;
|
||||
int last_scsi_host = 0;
|
||||
|
||||
pcrecpp::RE host_re = app_pcre_re("^Host: scsi([0-9]+)");
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
// The format of this file is scsi host number on one line, vendor on another.
|
||||
// debug_out_error("app", "SCSI Line: " << hz::string_trim_copy(lines[i]) << "\n");
|
||||
std::string scsi_host_str;
|
||||
if (host_re.PartialMatch(hz::string_trim_copy(lines[i]), &scsi_host_str)) {
|
||||
// debug_out_dump("app", "SCSI Host " << scsi_host_str << " found.\n");
|
||||
hz::string_is_numeric(scsi_host_str, last_scsi_host);
|
||||
}
|
||||
if (!app_pcre_match("/Vendor: (AMCC)|(3ware) /i", hz::string_trim_copy(lines[i]))) {
|
||||
continue; // not a supported controller
|
||||
}
|
||||
|
||||
debug_out_dump("app", "Found AMCC/3ware controller in SCSI file, SCSI host " << last_scsi_host << ".\n");
|
||||
|
||||
// We can't handle both twa and twe in one system, so assume twa by default.
|
||||
// We can't map twaX to scsiY, so lets assume the relative order is the same.
|
||||
std::string dev = std::string("/dev/") + (twa_found ? "twa" : "twe") + hz::number_to_string(num_controllers);
|
||||
|
||||
error_msg = tw_cli_get_drives(dev, last_scsi_host, drives, ex_factory, false);
|
||||
if (!error_msg.empty()) { // no tw_cli
|
||||
int max_ports = rconfig::get_data<int32_t>("system/linux_max_scan_ports");
|
||||
max_ports = std::max(max_ports, 23); // 128 smartctl calls are too much (it's too slow). Settle for 24.
|
||||
error_msg = smartctl_get_drives(dev, "3ware,%d", 0, max_ports, drives, ex_factory);
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Couldn't get number of ports on a 3ware controller.\n");
|
||||
}
|
||||
|
||||
++num_controllers;
|
||||
}
|
||||
|
||||
if (num_controllers == 0) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "3ware entry found in devices file, but SCSI file contains no known entries.\n");
|
||||
}
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
} // anon ns
|
||||
|
||||
|
||||
|
||||
|
||||
std::string detect_drives_linux(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<std::string> error_msgs;
|
||||
std::string error_msg;
|
||||
|
||||
// Disable by-id detection - it's unreliable on broken systems.
|
||||
// For example, on Ubuntu 8.04, /dev/disk/by-id contains two device
|
||||
// links for two drives, but both point to the same sdb (instead of
|
||||
// sda and sdb). Plus, there are no "*-partN" files (not that we need them).
|
||||
// error_msg = detect_drives_linux_udev_byid(devices); // linux udev
|
||||
|
||||
error_msg = detect_drives_linux_proc_partitions(drives, ex_factory);
|
||||
if (!error_msg.empty()) {
|
||||
error_msgs.push_back(error_msg);
|
||||
}
|
||||
|
||||
error_msg = detect_drives_linux_3ware(drives, ex_factory);
|
||||
if (!error_msg.empty()) {
|
||||
error_msgs.push_back(error_msg);
|
||||
}
|
||||
|
||||
return hz::string_join(error_msgs, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CONFIG_KERNEL_LINUX
|
||||
@@ -0,0 +1,30 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_DETECTOR_LINUX_H
|
||||
#define STORAGE_DETECTOR_LINUX_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hz/hz_config.h" // CONFIG_*
|
||||
#include "executor_factory.h"
|
||||
#include "storage_device.h"
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
|
||||
|
||||
/// Detect drives in linux
|
||||
std::string detect_drives_linux(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,270 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "storage_detector_win32.h"
|
||||
|
||||
#if !defined CONFIG_KERNEL_LINUX && !defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
#include <util.h> // getrawpartition()
|
||||
#endif
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/local_algo.h" // hz::shell_sort()
|
||||
#include "hz/fs_path_utils.h"
|
||||
#include "hz/fs_path.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "hz/fs_dir.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
std::string detect_drives_other(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /dev...\n");
|
||||
|
||||
std::vector<std::string> devices;
|
||||
|
||||
std::string sdev_config_path;
|
||||
#if defined CONFIG_KERNEL_SOLARIS
|
||||
sdev_config_path = "system/solaris_dev_path";
|
||||
#else // other unixes
|
||||
sdev_config_path = "system/unix_sdev_path";
|
||||
#endif
|
||||
|
||||
std::string dev_dir; // defaults to /dev for freebsd, /dev/rdsk for solaris.
|
||||
if (!rconfig::get_data(sdev_config_path, dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory path is not set.\n");
|
||||
return "Device directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.list(all_devices, false, hz::DirSortNone())) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
// platform whitelist
|
||||
std::vector<std::string> whitelist;
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY
|
||||
// FreeBSD example device names:
|
||||
// * /dev/ad0 - ide disk 0. /dev/ad0a - non-slice dos partition 1.
|
||||
// * /dev/da1s1e - scsi disk 1 (second disk), slice 1 (aka dos partition 1),
|
||||
// bsd partition e (multiple bsd partitions may be inside one dos partition).
|
||||
// * /dev/acd0 - first cdrom. /dev/acd0c - ?.
|
||||
// Info: http://www.freebsd.org/doc/en/books/handbook/disks-naming.html
|
||||
|
||||
// Of two machines I had access to, freebsd 6.3 had only real devices,
|
||||
// while freebsd 4.10 had lots of dummy ones (ad1, ad2, ad3, da0, da1, da2, da3, sa0, ...).
|
||||
|
||||
whitelist.push_back("/^ad[0-9]+$/"); // adN without suffix - fbsd ide
|
||||
whitelist.push_back("/^da[0-9]+$/"); // daN without suffix - fbsd scsi, usb
|
||||
// whitelist.push_back("/ ^sa[0-9]+$/"); // saN without suffix - fbsd scsi tape
|
||||
// whitelist.push_back("/^ast[0-9]+$/"); // astN without suffix - fbsd ide tape
|
||||
whitelist.push_back("/^aacd[0-9]+$/"); // fbsd adaptec raid
|
||||
whitelist.push_back("/^mlxd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^mlyd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^amrd[0-9]+$/"); // fbsd AMI raid
|
||||
whitelist.push_back("/^idad[0-9]+$/"); // fbsd compaq raid
|
||||
whitelist.push_back("/^twed[0-9]+$/"); // fbsd 3ware raid
|
||||
// these are checked by smartctl, but they are not mentioned in freebsd docs:
|
||||
whitelist.push_back("/^tw[ae][0-9]+$/"); // fbsd 3ware raid
|
||||
// unused: acd - ide cdrom, cd - scsi cdrom, mcd - mitsumi cdrom, scd - sony cdrom,
|
||||
// fd - floppy, fla - diskonchip flash.
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_SOLARIS
|
||||
|
||||
// /dev/rdsk contains "raw" physical char devices, as opposed to
|
||||
// "filesystem" block devices in /dev/dsk. smartctl needs rdsk.
|
||||
|
||||
// x86:
|
||||
|
||||
// /dev/rdsk/c0t0d0p0:1
|
||||
// Where c0 is the controller number.
|
||||
// t0 is the target (SCSI ID number) (omit for ATAPI)
|
||||
// d0 is always 0 for SCSI, the drive # for ATAPI
|
||||
// p0 is the partition (p0 is the entire disk, or p1 - p4)
|
||||
// :1 is the logical drive (c - z or 1 - 24) (that is, logical partitions inside extended partition)
|
||||
|
||||
// /dev/rdsk/c0d0p2:1
|
||||
// where p2 means the extended partition (type 0x05) is partition 2 (out of 1-4) and
|
||||
// ":1" is the 2nd extended partition (:0 would be the first extended partition). -- not sure about this!
|
||||
|
||||
// p0 whole physical disk
|
||||
// p1 - p4 Four primary fdisk partitions
|
||||
// p5 - p30 26 logical drives in extended DOS partition (not implemented by Solaris)
|
||||
// s0 - s15 16 slices in the Solaris FDISK partition (SPARC has only 8)
|
||||
// On Solaris, by convention, s2 is the whole Solaris partition.
|
||||
|
||||
// SPARC: There are no *p* devices on sparc afaik, only slices. By convention,
|
||||
// s2 is used as a "whole" disk there (but not with EFI partitions!).
|
||||
// So, c0d0s2 is the whole disk there.
|
||||
// x86 has both c0d0s2 and c0d0p2, where s2 is a whole solaris partition.
|
||||
|
||||
// NOTE: It seems that smartctl searches for s0 (aka root partition) in the end. I'm not sure
|
||||
// what implications this has for x86, but we replicate this behaviour.
|
||||
|
||||
// Note: Cdroms are ATAPI, so they pose as SCSI, as opposed to IDE hds.
|
||||
|
||||
// TODO: No idea how to implement /dev/rmt (scsi tape devices),
|
||||
// I have no files in that directory.
|
||||
|
||||
whitelist.push_back("/^c[0-9]+(?:t[0-9]+)?d[0-9]+s0$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
|
||||
// OpenBSD / NetBSD have /dev/wdNc for IDE/ATA, /dev/sdNc for SCSI disk,
|
||||
// /dev/stNc for scsi tape. N is [0-9]+. "c" means "whole disk" (not sure about
|
||||
// different architectures though). There are no "sdN" devices, only "sdNP".
|
||||
// Another manual says that wd0d would be a whole disk, while wd0c is its
|
||||
// bsd part only (on x86) (only on netbsd?). Anyway, getrawpartition() gives
|
||||
// us the letter we need.
|
||||
// There is no additional level of names for BSD subpartitions (unlike freebsd).
|
||||
// cd0a is cdrom.
|
||||
// Dummy devices are present.
|
||||
|
||||
// Note: This detection may take a while (probably due to open() check).
|
||||
|
||||
char whole_part = 'a' + getrawpartition(); // from bsd's util.h
|
||||
|
||||
whitelist.push_back(hz::string_sprintf("/^wd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^sd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^st[0-9]+%c$/", whole_part));
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_DARWIN
|
||||
|
||||
// Darwin has /dev/disk0, /dev/disk0s1, etc...
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^disk[0-9]+$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_QNX
|
||||
|
||||
// QNX has /dev/hd0, /dev/hd0t78 (partition?).
|
||||
// Afaik, IDE and SCSI have the same prefix. fd for floppy, cd for cdrom.
|
||||
// Not sure about the tapes.
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^hd[0-9]+$/");
|
||||
|
||||
|
||||
#endif // unix platforms
|
||||
|
||||
|
||||
std::vector<std::string> matched_devices;
|
||||
|
||||
for (std::size_t i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
bool matched = false;
|
||||
for (std::vector<std::string>::const_iterator iter = whitelist.begin(); iter != whitelist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// In case these are links, trace them to originals.
|
||||
// We don't replace /dev files with real devices - it leads to really bad paths (pci ids for solaris, etc...).
|
||||
std::string link_dest;
|
||||
hz::FsPath real_dev_path;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
real_dev_path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
real_dev_path.compress(); // compress in case there are ../-s.
|
||||
|
||||
// solaris has dangling links for non-existant devices, so filter them out.
|
||||
if (!real_dev_path.exists())
|
||||
continue;
|
||||
}
|
||||
|
||||
matched_devices.push_back(path.str());
|
||||
}
|
||||
|
||||
|
||||
// List ones who need dummy device filtering
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY \
|
||||
|| defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
// Since we may have encountered dummy devices, we should check
|
||||
// if they really exist. Unfortunately, this involves opening them, which
|
||||
// is not good with some media (e.g. it may hang on audio cd (freebsd, maybe others), etc...).
|
||||
// That's why we don't whitelist cd devices. Let's hope usb and others are
|
||||
// ok with this. Dummy devices give errno ENXIO (6, Device not configured) on *bsd.
|
||||
// In Linux ENXIO is (6, No such device or address).
|
||||
|
||||
// Don't do this on solaris - we can't distinguish between cdroms and hds there.
|
||||
|
||||
// If there are less than 4 devices, they are probably not dummy (newer freebsd).
|
||||
bool open_needed = (matched_devices.size() >= 4);
|
||||
if (open_needed) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", will try to filter non-existent ones out.\n");
|
||||
} else {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", no need for filtering them out.\n");
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < matched_devices.size(); ++i) {
|
||||
hz::File dev_file(matched_devices[i]);
|
||||
|
||||
// we check errno because OS may deny us for some other reason on valid devices.
|
||||
if (open_needed && !dev_file.open("rb") && dev_file.get_errno() == ENXIO) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" failed to open, ignoring.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (open_needed)
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" opened successfully, adding to device list.\n");
|
||||
|
||||
devices.push_back(dev_file.str());
|
||||
}
|
||||
|
||||
#else // not *BSD
|
||||
for (std::size_t i = 0; i < matched_devices.size(); ++i) {
|
||||
devices.push_back(matched_devices[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
hz::shell_sort(devices.begin(), devices.end());
|
||||
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(devices.at(i))));
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !defined CONFIG_KERNEL_LINUX && !defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
@@ -0,0 +1,28 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_DETECTOR_OTHER_H
|
||||
#define STORAGE_DETECTOR_OTHER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hz/hz_config.h" // CONFIG_*
|
||||
#include "executor_factory.h"
|
||||
#include "storage_device.h"
|
||||
|
||||
|
||||
#if !defined CONFIG_KERNEL_LINUX && !defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
|
||||
|
||||
// FreeBSD, Solaris, etc... .
|
||||
std::string detect_drives_other(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_whatever.txt
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_unlicense.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
@@ -24,13 +24,15 @@ int main()
|
||||
// sd.add_match_patterns(match_patterns);
|
||||
sd.add_blacklist_patterns(blacklist_patterns);
|
||||
|
||||
std::string error_msg = sd.detect_and_fetch_basic_data(drives);
|
||||
ExecutorFactoryRefPtr ex_factory(new ExecutorFactory(false));
|
||||
std::string error_msg = sd.detect_and_fetch_basic_data(drives, ex_factory);
|
||||
if (!error_msg.empty()) {
|
||||
std::cerr << error_msg << "\n";
|
||||
|
||||
} else {
|
||||
for (unsigned int i = 0; i < drives.size(); ++i) {
|
||||
std::cerr << drives[i]->get_device() << " (" << StorageDevice::get_type_name(drives[i]->get_type()) << ")\n";
|
||||
std::cerr << drives[i]->get_device_with_type() <<
|
||||
" (" << StorageDevice::get_type_readable_name(drives[i]->get_detected_type()) << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "storage_detector_win32.h"
|
||||
|
||||
#if defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
|
||||
#include <windows.h> // CreateFileA(), CloseHandle(), etc...
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "hz/win32_tools.h"
|
||||
#include "hz/string_sprintf.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
/*
|
||||
3ware Windows (XP so far, maybe the same under the others):
|
||||
For 3ware 9xxx only.
|
||||
Call as: smartctl -i sd[a-z],N
|
||||
N is port, a-z is logical drive (unit) provided by controller.
|
||||
N is limited to [0, 31] in the code.
|
||||
The sd[a-z] device actually exists as \\.\PhysicalDrive[0-N].
|
||||
No idea how to check if it's 3ware.
|
||||
Call as: smarctl -i tw_cli/cx/py
|
||||
This runs tw_cli tool and parses the output; controller x, port y.
|
||||
tw_cli may be needed for older controllers / drivers.
|
||||
In tw_cli mode only limited information-gathering is supported.
|
||||
tw_cli (part of 3DM2) is automatically added to system PATH,
|
||||
no need to look for it.
|
||||
3DM2 install can be detected by checking:
|
||||
HKEY_USERS\.DEFAULT\Software\3ware\3DM2, InstallPath
|
||||
Another option for detection (whether it's 3ware) would be getting
|
||||
\\.\PhysicalDrive0 properties, like smartctl does.
|
||||
Newer (added after 5.39.1) smartctl supports --scan-open, which will give us:
|
||||
/dev/sda,0 -d ata (opened)
|
||||
/dev/sda,1 -d ata (opened)
|
||||
-d 3ware is not needed under Windows. We should treat sda as pd0
|
||||
and remove pd0 from PhysicalDrive-detected list.
|
||||
Running smartctl on sda gives almost the same result as on sda,0.
|
||||
|
||||
|
||||
Intel Matrix RAID (since smartmontools SVN version on 2011-02-04):
|
||||
Call as: "/dev/csmi[0-9],N" where N is the port behind the logical
|
||||
scsi controller "\\.\Scsi[0-9]:".
|
||||
The prefix "/dev/" is optional.
|
||||
This is detected (with /dev/ prefix) by --scan-open.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
smartctl --scan-open output for win32 (3ware):
|
||||
/dev/sda,0 -d ata (opened)
|
||||
/dev/sda,1 -d ata (opened)
|
||||
|
||||
smartctl --scan-open output for linux:
|
||||
/dev/sda -d sat # /dev/sda [SAT], ATA device
|
||||
/dev/sdb -d sat # /dev/sdb [SAT], ATA device
|
||||
/dev/sdc -d sat # /dev/sdc [SAT], ATA device
|
||||
*/
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
/// Run "smartctl --scan-open" and pick the devices which have
|
||||
/// a port parameter. We don't pick the others because the may
|
||||
/// conflict with pd* devices, and we like pd* better than sd*.
|
||||
std::string get_scan_open_multiport_devices(std::vector<StorageDeviceRefPtr>& drives,
|
||||
ExecutorFactoryRefPtr ex_factory, std::vector<int>& equivalent_pds)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
std::string smartctl_binary = get_smartctl_binary();
|
||||
|
||||
if (smartctl_binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl binary is not set in config.\n");
|
||||
return "Smartctl binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string smartctl_def_options;
|
||||
rconfig::get_data("system/smartctl_options", smartctl_def_options);
|
||||
|
||||
if (!smartctl_def_options.empty())
|
||||
smartctl_def_options += " ";
|
||||
|
||||
smartctl_ex->set_command(Glib::shell_quote(smartctl_binary),
|
||||
smartctl_def_options + "--scan-open");
|
||||
|
||||
if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n");
|
||||
return smartctl_ex->get_error_msg();
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl returned an empty output.\n");
|
||||
return "Smartctl returned an empty output.";
|
||||
}
|
||||
|
||||
// if we've reached smartctl port limit (older versions may have smaller limits), abort.
|
||||
if (app_pcre_match("/UNRECOGNIZED OPTION/mi", output)) {
|
||||
return "Smartctl doesn't support --scan-open switch.";
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
// /dev/sda,0 -d ata (opened)
|
||||
// /dev/sda,1 -d ata (opened)
|
||||
// /dev/sda -d sat # /dev/sda [SAT], ATA device
|
||||
// /dev/sde,2 -d ata [ATA] (opened)
|
||||
|
||||
// we only pick the ones with ports
|
||||
pcrecpp::RE port_re = app_pcre_re("/^(/dev/[a-z0-9]+),([0-9]+)[ \\t]+-d[ \\t]+([^ \\t\\n]+)/i");
|
||||
pcrecpp::RE dev_re = app_pcre_re("/^/dev/sd([a-z])$/");
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string dev, port_str, type;
|
||||
if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &dev, &port_str, &type)) {
|
||||
std::string letter;
|
||||
if (dev_re.PartialMatch(dev, &letter)) {
|
||||
// don't use pd* devices equivalent to these sd* devices.
|
||||
equivalent_pds.push_back(letter.at(0) - 'a');
|
||||
}
|
||||
|
||||
std::string full_dev = dev + "," + port_str;
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(full_dev, type)));
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// smartctl accepts various variants, the most straight being pdN,
|
||||
// (or /dev/pdN, /dev/ being optional) where N comes from
|
||||
// "\\.\PhysicalDriveN" (winnt only).
|
||||
// http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
|
||||
|
||||
std::string detect_drives_win32(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<int> used_pds;
|
||||
std::string error_msg = get_scan_open_multiport_devices(drives, ex_factory, used_pds);
|
||||
bool multiport_found = !drives.empty();
|
||||
|
||||
for (int drive_num = 0; ; ++drive_num) {
|
||||
std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num);
|
||||
|
||||
// If the drive is openable, then it's there.
|
||||
// NOTE: Administrative privileges are required to open it.
|
||||
// Yes, CreateFile() is open, not create. Yes, it's silly (ah, win32...).
|
||||
// We don't use any long/unopenable files here, so use the ANSI version.
|
||||
HANDLE h = CreateFileA(name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
// The numbers seem to be consecutive, so break on first invalid.
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
if (std::find(used_pds.begin(), used_pds.end(), drive_num) == used_pds.end()) {
|
||||
std::string dev = hz::string_sprintf("pd%d", drive_num);
|
||||
drives.push_back(new StorageDevice(dev));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If smartctl --scan-open returns no "sd*,port"-style devices,
|
||||
// check if 3dm2 is installed and execute "tw_cli show" to get
|
||||
// the controllers, then use the tw_cli variant of smartctl.
|
||||
|
||||
if (!multiport_found) {
|
||||
std::string inst_path;
|
||||
hz::win32_get_registry_value_string(HKEY_USERS, ".DEFAULT\\Software\\3ware\\3DM2", "InstallPath", inst_path);
|
||||
|
||||
if (!inst_path.empty()) {
|
||||
std::vector<int> controllers;
|
||||
error_msg = tw_cli_get_controllers(ex_factory, controllers);
|
||||
// ignore the error message above, it's of no use.
|
||||
for (std::size_t i = 0; i < controllers.size(); ++i) {
|
||||
// don't specify device, it's ignored in tw_cli mode
|
||||
tw_cli_get_drives("", controllers.at(i), drives, ex_factory, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user