Compare commits

..
6 Commits
Author SHA1 Message Date
Alexander Shaduri d007261077 Blacklisted linux device mapper devices (annoying in LVM setups).
Added beesu support and generally improved gsmartcontrol-root script (this is
needed for Fedora 14 which doesn't have any old supported su mechanisms).
2010-12-26 19:58:47 +00:00
Alexander Shaduri f72c332264 Preparing 0.8.5.1. 2010-12-26 19:56:11 +00:00
Alexander Shaduri 2ca8174054 Importing 0.8.5. 2010-12-26 19:50:52 +00:00
Alexander Shaduri 10e4496bb7 Importing 0.8.4. 2010-12-26 19:46:54 +00:00
Alexander Shaduri 880d876ccf Importing 0.8.4-pre-2009-03-21. 2010-12-26 19:44:01 +00:00
Alexander Shaduri 2ffec89ed8 Importing 0.8.3 2010-12-26 19:40:08 +00:00
234 changed files with 7132 additions and 2474 deletions
+25
View File
@@ -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.
+3 -2
View File
@@ -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 Whatever License. See LICENSE_whatever.txt for
details.
Portions of this software are copyright Google Inc. See LICENSE_pcrecpp.txt
+4
View File
@@ -17,6 +17,10 @@ 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.
+12 -8
View File
@@ -16,6 +16,7 @@ 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 \
@@ -26,6 +27,13 @@ dist_doc_DATA = AUTHORS.txt ChangeLog NEWS README.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 \
@@ -61,7 +69,8 @@ src-rpm: dist
# NSIS installer support.
# Requires wine, installed NSIS, gtkmm dlls, pcre dlls, smartctl.exe, smartctl_console.exe.
# 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.
@@ -86,17 +95,12 @@ win-dist-prepare: all win-dist-clean
unix2dos nsis-dist/*.nsi nsis-dist/doc/*.txt
cp "@WIN32_ENV@"/libatkmm-*.dll "@WIN32_ENV@"/libcairomm-*.dll "@WIN32_ENV@"/libgdkmm-*.dll nsis-dist/
cp "@WIN32_ENV@"/libgiomm-*.dll "@WIN32_ENV@"/libglibmm-*.dll "@WIN32_ENV@"/libgtkmm-*.dll nsis-dist/
cp "@WIN32_ENV@"/libpangomm-*.dll "@WIN32_ENV@"/libsigc-*.dll "@WIN32_ENV@"/pcre3.dll nsis-dist/
cp "@WIN32_ENV@"/mingwm10.dll "@WIN32_ENV@"/smartctl.exe "@WIN32_ENV@"/smartctl_console.exe nsis-dist/
cp "@WINDOWS_BINDIR@"/smartctl-nc.exe nsis-dist/
cp "@WINDOWS_BINDIR@"/smartctl.exe nsis-dist/
cp src/gsmartcontrol.exe nsis-dist/
$(STRIP) nsis-dist/*.exe
mv nsis-dist/mingwm10.dll nsis-dist/mingwm10.dll_
$(STRIP) --strip-debug --strip-unneeded nsis-dist/*.dll
mv nsis-dist/mingwm10.dll_ nsis-dist/mingwm10.dll
nsis-dist: nsis-dist-nocleanup nsis-cleanup
+48 -2
View File
@@ -1,10 +1,56 @@
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
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).
@@ -14,7 +60,7 @@ Version 0.8.2, released on 2008-12-10
No more unnecessary parsing.
No segfault on exit under Windows and Solaris.
A friendlier message is displayed if smartctl was not found.
No hilighted labels when switching tabs in Information window.
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
+88 -44
View File
@@ -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: Only ATA drives (both PATA and SATA) and various USB to ATA bridges are
supported for now.
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.
@@ -101,15 +103,15 @@ You need to have the following software installed:
* libglademm, version 2.4 or higher - see http://www.gtkmm.org .
Note: libglademm is not needed when using GTK 2.12 and Gtkmm 2.12.
Note that GTK+ 2.12 and Gtkmm 2.12 are HIGHLY recommended. While earlier
versions may work, they may produce suboptimal results and buggy behaviour.
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.
Libglademm is not needed when using GTK / Gtkmm 2.12.
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:
openSUSE, SLES, SLED:
gcc-c++, pcre-devel, gtkmm2-devel, (possibly) libglademm-devel.
Fedora, CentOS, RHEL:
@@ -126,6 +128,10 @@ 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.
The following operating systems are supported:
@@ -137,15 +143,14 @@ The following operating systems are supported:
* OpenBSD - Tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5.
* Windows (XP or higher) - Tested with Windows XP and Vista. Windows 2000 does
not work for some unknown reason. The Windows port uses pd0, pd1, etc... for
physical drives 0, 1, etc... .
* Windows (2000 SP4 or newer) - Tested with Windows 2000 SP4, XP SP2 and Vista
SP1. 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.
@@ -158,15 +163,19 @@ to work without any issues.
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
@@ -174,15 +183,49 @@ 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. Useful with --no-scan to list
certain drives only.
-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.
@@ -227,9 +270,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.
@@ -237,12 +281,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) and various USB to ATA bridges 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
@@ -251,19 +295,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...
@@ -283,14 +322,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.0).
* 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.
@@ -300,6 +342,8 @@ dialog):
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".
@@ -322,7 +366,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.
+44 -15
View File
@@ -19,14 +19,6 @@ A treeview (also iconview, combobox) from glade comes
with existing model, which should be unset.
--------------------------------------------------------
portability:
win32 32-bit: int: 4, long: 4, pointer: 4.
win32 64-bit: int: 4, long: 8, pointer: 8.
sparc: same as win32 (what about OS?).
--------------------------------------------------------
@@ -34,11 +26,17 @@ sparc: same as win32 (what about OS?).
TODO:
Support Areca controller.
When adding device, have an option to specify "-d" type and other parameters.
This is needed to support multi-disk devices.
Patch pangomm for Pango::strip_markup().
+Make a test case of IconView positioning bug, file a bug report.
Patch gtkmm, glibmm, pangomm for static win32 builds.
No Gtk::AboutDialog::set_logo(NULL);
libdebug:
@@ -46,11 +44,43 @@ libdebug:
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.
OpenSuse Build Service:
fails with error when tarball already contains the debian directory.
'-l sataphy' -> SATA Phy event counters: Non-SMART feature, useful to detect SATA cabling problems.
'-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 scttemp' -> SCT Temperature history table. See below.
'-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.
Careful with GPL (xerror...) stuff until the jmicron situation clears up.
Add detection for Interix (i586-pc-interix3), maybe with debian?
Re-check long double printing - win32 libc doesn't support it, a cast
to double is needed.
The underlying problem is that in msvc, long double is the same size
as double, so printf() has mingw-incompatible presentation of long double.
Support USB flash disks in CVS smartctl versions:
Try smartctl -i /dev/sdc;
If it returns "Smartctl: please specify device type with the -d option.",
try "-d scsi", which should at least give us the name.
Maybe make it easier to specify "-d" (with a dropdown?)
Not sure, "-l aaa /tmp" doesn't list all types.
@@ -87,7 +117,6 @@ OpenSuse Build Service:
+ * 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
@@ -97,7 +126,7 @@ OpenSuse Build Service:
+ 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.
+19 -8
View File
@@ -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
])
+18 -8
View File
@@ -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
View File
@@ -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
])
+21 -12
View File
@@ -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 -1
View 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
############################################################################
+19 -3
View 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()
@@ -91,7 +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.])
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
@@ -123,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])
+54 -22
View 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
############################################################################
@@ -50,20 +50,18 @@ 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.
# -mconsole - opposite of -mwindows, default.
# -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";
@@ -81,7 +79,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 \
@@ -119,13 +126,6 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
# gcc, mingw
if test "x$app_cv_compiler_debug_options" = "xgnu"; then
if test "x$app_cv_target_os_env" = "xmingw" || test "x$app_cv_target_os_env" = "xcygwin"; then
# Enable console window for debug builds
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -mconsole"
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -mconsole"
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mconsole"
fi
# We could put libstdc++ debug options here, but it generates binary-incompatible
# C++ code, which leads to runtime errors with e.g. libsigc++.
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g3 -O0";
@@ -175,11 +175,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";
@@ -222,6 +222,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
+11 -6
View File
@@ -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
])
+12 -6
View File
@@ -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
])
+63 -13
View 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
############################################################################
@@ -59,12 +59,24 @@ 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... .
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 +136,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 +172,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 +184,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 +249,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 +312,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 +351,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 +364,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}])
])
+56 -19
View File
@@ -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
;;
+45 -3
View 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
############################################################################
@@ -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
+32 -21
View File
@@ -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
])
+83 -27
View File
@@ -1,5 +1,5 @@
AC_INIT([GSmartControl], 0.8.2, [], [gsmartcontrol])
AC_INIT([GSmartControl],[0.8.5],[],[gsmartcontrol])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_HEADERS([config.h])
@@ -36,6 +36,9 @@ 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
# -------------------------------------------------------------------------------------
@@ -52,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.
@@ -60,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([])
@@ -104,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__
@@ -124,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])
@@ -158,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.
@@ -228,36 +253,66 @@ 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],
AC_ARG_WITH([nsis], [AS_HELP_STRING([--with-nsis=<location>|auto],
[specify makensis.exe location to support making NSIS packages]
[ (default: ~/".wine/drive_c/Program Files/NSIS/makensis.exe")])],
[ (default: "C:\Program Files\NSIS\makensis.exe" for windows, ]
["~/.wine/drive_c/Program Files/NSIS/makensis.exe" for others)])],
[with_nsis=${withval}], [with_nsis=auto])
AC_ARG_ENABLE([nsis-wine], [AS_HELP_STRING([--enable-nsis-wine],
[use wine to run makensis.exe when making NSIS packages (default: yes)])],
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([win32-env], [AS_HELP_STRING([--with-win32-env],
[specify location of win32 dlls when making win32 packages (default: /target/bin)])],
[with_win32_env=${withval}], [win_win32_env=auto])
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])
if test "x$with_nsis" = "xauto" || test "x$with_nsis" = "x"; then
with_nsis="~/\".wine/drive_c/Program Files/NSIS/makensis.exe\""
if test "x$app_cv_build_os_kernel" = "xwindows"; then
with_nsis="~/\".wine/drive_c/Program Files/NSIS/makensis.exe\"";
else
with_nsis="\"C:\\Program Files\\NSIS\\makensis.exe\"";
fi
fi
if test "x$with_win32_env" = "xauto" || test "x$with_win32_env" = "x"; then
with_win32_env="/target/bin"
if test "x$with_nsis_wine" = "xauto"; then
if test "x$app_cv_build_os_kernel" = "xwindows"; 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
WIN32_ENV="$with_win32_env";
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";
AC_SUBST(NSIS_EXEC)
AC_SUBST(WIN32_ENV)
AC_SUBST(WINDOWS_BINDIR)
# -------------------------------------------------------------------------------------
@@ -365,7 +420,8 @@ 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" \
+17
View File
@@ -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
View File
@@ -0,0 +1,22 @@
#!/bin/bash
############################################################################
# Copyright:
# (C) 2008 - 2009 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
# License: See LICENSE_whatever.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
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
############################################################################
# Copyright:
# (C) 2008 - 2009 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
# License: See LICENSE_whatever.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"
+15 -2
View File
@@ -1,10 +1,23 @@
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."; \
+35 -20
View File
@@ -1,11 +1,12 @@
#!/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
############################################################################
# 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"
@@ -44,8 +45,8 @@ fi
# 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";
gnome_sus="gnomesu gksu kdesu beesu xdg-su sux";
kde_sus="kdesu gnomesu gksu beesu xdg-su sux";
other_sus="$gnome_sus";
@@ -60,18 +61,20 @@ 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 [ "$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 or sux first.";
exit 1;
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
@@ -82,7 +85,10 @@ fi
# 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).
export PATH="/usr/sbin:/usr/local/sbin:$PATH"
# 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;
@@ -90,20 +96,29 @@ export PATH="/usr/sbin:/usr/local/sbin:$PATH"
# Examples:
# gnomesu -c 'gsmartcontrol --no-scan'
# kdesu -c 'gsmartcontrol --no-scan'
# beesu -P '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 $@'"
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 $@'"
full_cmd="$found_su '$EXEC_BIN $@'";
elif [ "$found_su" = "beesu" ]; then
full_cmd="$found_su -P '$EXEC_BIN $@'";
else # gnomesu, kdesu, xdg-su
full_cmd="$found_su -c '$EXEC_BIN $@'"
full_cmd="$found_su -c '$EXEC_BIN $@'";
fi
#echo $full_cmd
eval $full_cmd
+74
View File
@@ -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.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 95 KiB

+7 -6
View File
@@ -17,12 +17,13 @@ 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.
64-bit Windows. The binary was statically compiled against Gtkmm
(http://www.gtkmm.org/) and related libraries, and PCRE (http://www.pcre.org/).
* Gtkmm (http://www.gtkmm.org/) dlls.
* Smartctl binaries (from smartmontools 5.39-0-20090826-r2878,
http://smartmontools.sf.net/) - smartctl-nc.exe (compiled without console
output), smartctl.exe (compiled with console output).
* PCRE (http://www.pcre.org/) dll.
* Smartctl binaries - smartctl.exe (compiled without console output),
smartctl_console.exe (compiled with console output), version 5.38.
http://smartmontools.sf.net/ .
The combined distribution is multi-licensed under GNU GPL versions 2 and 3.
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
+5 -5
View File
@@ -177,7 +177,7 @@ FunctionEnd
; ----------------- INSTALLATINO TYPES
; ----------------- INSTALLATION TYPES
; InstType "Recommended"
InstType "Full"
@@ -199,9 +199,9 @@ SectionIn 1
File gsmartcontrol.exe
File gsmartcontrol.ico
File icon_*.png
File *.dll
; File *.dll
File smartctl-nc.exe
File smartctl.exe
File smartctl_console.exe
File /r doc
@@ -271,9 +271,9 @@ Section Uninstall
Delete "$INSTDIR\gsmartcontrol.exe"
Delete "$INSTDIR\gsmartcontrol.ico"
Delete "$INSTDIR\icon_*.png"
Delete "$INSTDIR\*.dll"
; Delete "$INSTDIR\*.dll"
Delete "$INSTDIR\smartctl-nc.exe"
Delete "$INSTDIR\smartctl.exe"
Delete "$INSTDIR\smartctl_console.exe"
RMDir /r "$INSTDIR\doc"
+2 -3
View File
@@ -1,7 +1,6 @@
noinst_DATA = changelog.in compat control copyright docs menu postinst \
postrm rules
noinst_DATA = changelog.in compat control copyright menu postinst postrm rules
# include the generated file too
EXTRA_DIST=changelog.in changelog compat control copyright docs menu postinst \
EXTRA_DIST=changelog.in changelog compat control copyright menu postinst \
postrm rules
-5
View File
@@ -1,5 +0,0 @@
gsmartcontrol (0.8.2+nmu1) unstable; urgency=low
* Permanently Initial Release.
-- Alexander Shaduri <ashaduriREMOVETHIS@gmail.com> Sat, 15 Nov 2008 00:12:04 +0400
+4 -5
View File
@@ -15,8 +15,7 @@ Architecture: any
Depends: ${shlibs:Depends}, smartmontools
Description: Hard disk drive health inspection tool
GSmartControl is a graphical user interface for smartctl (from smartmontools
package, see http://smartmontools.sourceforge.net), 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.
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.
+2 -2
View File
@@ -5,7 +5,7 @@ It was downloaded from <http://gsmartcontrol.berlios.de/>
Copyright:
Copyright (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
Copyright (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License:
@@ -27,6 +27,6 @@ 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 Alexander Shaduri <ashaduri 'at' gmail.com> and
The Debian packaging is (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com> and
is licensed under the GPLv2 and GPLv3, see above.
-12
View File
@@ -1,12 +0,0 @@
AUTHORS.txt
LICENSE_boost_1_0.txt
LICENSE_bsd-ucb.txt
LICENSE_gpl2.txt
LICENSE_gpl3.txt
LICENSE_gsmartcontrol.txt
LICENSE_hz.txt
LICENSE_pcrecpp.txt
LICENSE_whatever.txt
LICENSE_zlib.txt
NEWS
README.txt
+9 -5
View File
@@ -25,8 +25,12 @@ endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
./configure --enable-optimize-options=auto --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"
./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
@@ -42,7 +46,7 @@ build-stamp: config.status
clean:
dh_testdir
dh_testroot
rm -f build-stamp
rm -f build-stamp
# Add here commands to clean up after the build process.
-$(MAKE) clean
@@ -72,7 +76,7 @@ binary-arch: build install
# dh_installexamples
# dh_install
dh_installmenu
# dh_installdebconf
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
@@ -81,7 +85,7 @@ binary-arch: build install
# dh_installinit
# dh_installcron
# dh_installinfo
# dh_installman
dh_installman
dh_link
dh_strip
dh_compress
@@ -95,4 +99,4 @@ binary-arch: build install
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install
.PHONY: build clean binary-indep binary-arch binary install
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/bash
############################################################################
# Copyright:
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
# License: See LICENSE_zlib.txt file
############################################################################
+48 -31
View File
@@ -15,14 +15,14 @@
<projectname>gsmartcontrol</projectname>
<projectdirectory>.</projectdirectory>
<absoluteprojectpath>false</absoluteprojectpath>
<description/>
<defaultencoding/>
<description></description>
<defaultencoding></defaultencoding>
<versioncontrol/>
</general>
<kdevautoproject>
<general>
<activetarget>src/gsmartcontrol</activetarget>
<useconfiguration>debuggy</useconfiguration>
<useconfiguration>suncc</useconfiguration>
</general>
<run>
<mainprogram>/10/devel/projects/gsmartcontrol/current/gsmartcontrol/debuggy</mainprogram>
@@ -76,21 +76,21 @@
<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>
<f77compiler>kdevg77options</f77compiler>
<cflags/>
<cxxflags/>
<cflags></cflags>
<cxxflags></cxxflags>
<envvars/>
<topsourcedir/>
<cppflags/>
<ldflags/>
<ccompilerbinary/>
<cxxcompilerbinary/>
<f77compilerbinary/>
<f77flags/>
<topsourcedir></topsourcedir>
<cppflags></cppflags>
<ldflags></ldflags>
<ccompilerbinary>gcc-4.4</ccompilerbinary>
<cxxcompilerbinary>g++-4.4</cxxcompilerbinary>
<f77compilerbinary></f77compilerbinary>
<f77flags></f77flags>
</debuggy>
<icc>
<envvars/>
@@ -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-optimize-options --enable-tests --target=i386-mingw32msvc --host=i386-mingw32msvc --build=i686-linux PKG_CONFIG_PATH=/target/lib/pkgconfig PKG_CONFIG_LIBDIR=/target/lib PATH=&quot;/opt/cross-tools/bin:/target/bin:$PATH&quot;</configargs>
<configargs>--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=&quot;&quot; PATH=&quot;/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH&quot;</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=&quot;/opt/sun/target64/lib64/pkgconfig:/usr/lib64/pkgconfig&quot; PKG_CONFIG_LIBDIR=&quot;&quot;</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>
@@ -164,7 +164,7 @@
</portland>
<win32-debug>
<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=&quot;/opt/cross-tools/bin:/target/bin:$PATH&quot;</configargs>
<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=&quot;&quot; PATH=&quot;/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH&quot;</configargs>
<builddir>win32-debug</builddir>
<topsourcedir/>
<cppflags/>
@@ -172,13 +172,30 @@
<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/>
<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=&quot;&quot; PATH=&quot;/cross/w64/gcc-bin:/cross/w64/target/bin:$PATH&quot;</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>
</configurations>
<make>
<envvars>
@@ -254,11 +271,11 @@
</kdevdoctreeview>
<kdevdebugger>
<general>
<dbgshell/>
<gdbpath/>
<configGdbScript/>
<runShellScript/>
<runGdbScript/>
<dbgshell></dbgshell>
<gdbpath></gdbpath>
<configGdbScript></configGdbScript>
<runShellScript></runShellScript>
<runGdbScript></runGdbScript>
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>false</floatingtoolbar>
+16 -4
View File
@@ -1,5 +1,5 @@
Name: gsmartcontrol
Version: @VERSION@
Version: @VERSION@
Release: 1as
License: GPLv2, GPLv3
Url: http://gsmartcontrol.berlios.de
@@ -38,8 +38,13 @@ Group: Hardware/Other
Requires: smartmontools, pcre, gtkmm2 >= 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
%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
@@ -60,7 +65,8 @@ BuildRequires: gcc-c++, pcre-devel, gtkmm24-devel >= 2.6.0, libglademm24-devel >
%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
@@ -84,8 +90,11 @@ SMART data to determine its health, as well as run various tests on it.
%setup -q
%if 0%{?mandriva_version} <= 2006
%configure
%else
%configure --enable-optimize-options=auto
%endif
%build
# Set up for parallel builds
@@ -101,6 +110,9 @@ make -j$numprocs
%install
# %makeinstall
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="" \
@@ -122,6 +134,7 @@ rm -rf %buildroot
# %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/*
%doc %{_datadir}/doc/gsmartcontrol
%doc %{_mandir}/man1/*
%{_datadir}/gsmartcontrol
# %{_datadir}/gsmartcontrol/*
@@ -141,4 +154,3 @@ rm -rf %buildroot
* Mon Sep 15 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
- Initial .spec file.
+9 -4
View File
@@ -4,7 +4,7 @@ METASOURCES = AUTO
SUBDIRS = libdebug hz rmn rconfig pcrecpp applib res
if TARGET_OS_KERNEL_WINDOWS
if TARGET_OS_KERNEL_FAMILY_WINDOWS
WINRES_OBJ = gsc_winres_win32.o
endif
@@ -19,6 +19,11 @@ mostlyclean-local:
noinst_DATA = gsc_winres.rc.in
# if TARGET_OS_KERNEL_FAMILY_WINDOWS
# WIN_MAIN_SRC = win_main.cpp
# endif
bin_PROGRAMS = gsmartcontrol
gsmartcontrol_LDADD = $(top_builddir)/src/applib/libapplib.a \
@@ -28,7 +33,7 @@ gsmartcontrol_LDADD = $(top_builddir)/src/applib/libapplib.a \
noinst_HEADERS = global_macros.h gsc_about_dialog.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_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
+3 -2
View File
@@ -2,8 +2,9 @@ AM_CPPFLAGS = $(all_includes)
METASOURCES = AUTO
noinst_LIBRARIES = libapplib.a
libapplib_a_SOURCES = app_gtkmm_utils.cpp app_pango_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
cmdex_sync.cpp cmdex_sync_gui.cpp gui_utils.cpp selftest.cpp smartctl_executor.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_pango_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 \
+2 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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
+6 -6
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -10,7 +10,7 @@
#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
@@ -54,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 {
@@ -107,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 {
@@ -160,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
@@ -177,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 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+10 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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));
}
+24 -19
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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)
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.txt
***************************************************************************/
+3 -3
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.txt
***************************************************************************/
@@ -9,7 +9,7 @@
// A simple empty window definition
#if defined ENABLE_LIBGLADE
#if defined ENABLE_LIBGLADE && ENABLE_LIBGLADE
extern const unsigned char app_ui_res_test_window_ui[] = {
@@ -341,7 +341,7 @@ extern const unsigned int app_ui_res_test_window_ui_size = 319;
#elif defined ENABLE_GTKBUILDER
#elif defined ENABLE_GTKBUILDER && ENABLE_GTKBUILDER
extern const unsigned char app_ui_res_test_window_ui[] = {
+88 -250
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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,38 +97,36 @@ 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;
}
}
// Set the locale for a child to Classic - otherwise it may mangle the output.
// 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.
#ifndef _WIN32
// 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);
#endif
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;
gchar** elem = argvp.get();
while (*elem) {
debug_out_dump("app", *elem << "\n");
++elem;
@@ -156,53 +136,59 @@ bool Cmdex::execute()
// 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)) {
/*
#if defined APP_CMDEX_USE_SYNC && APP_CMDEX_USE_SYNC
push_error(Error<void>("gspawn", ErrorLevel::error, spawn_error->message), false);
g_error_free(spawn_error);
g_free(curr_dir);
g_strfreev(argvp);
#ifndef _WIN32
if (old_lang_set)
g_setenv("LANG", old_lang.c_str(), true);
#endif
return false;
}
g_free(curr_dir);
g_strfreev(argvp);
#ifndef _WIN32
if (old_lang_set)
g_setenv("LANG", old_lang.c_str(), true);
#endif
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
@@ -213,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;
}
@@ -272,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;
@@ -298,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);
@@ -315,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)
@@ -340,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
@@ -385,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_) {
@@ -427,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;
}
@@ -441,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;
@@ -463,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) {
@@ -476,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);
@@ -497,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.
+19 -97
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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)
{ }
@@ -119,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
@@ -131,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_);
}
@@ -144,7 +131,6 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
// stopped_cleanup_needed() instead.
bool is_running() const
{
ScopedLock locker(object_mutex_);
return running_;
}
@@ -152,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)
@@ -173,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_;
@@ -209,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();
@@ -222,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_, &microsec);
}
// 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
@@ -291,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;
@@ -327,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().
@@ -361,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().
@@ -375,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_;
+4 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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 -8
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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);
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+4 -3
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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();
@@ -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.)));
+2 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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"
+64
View File
@@ -0,0 +1,64 @@
/**************************************************************************
Copyright:
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include "smartctl_executor.h"
#include "hz/fs_path.h"
#include "hz/win32_tools.h"
#include "rconfig/rconfig_mini.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;
}
+4 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -152,6 +152,9 @@ typedef SmartctlExecutorGeneric<CmdexSync> SmartctlExecutor;
// returns an empty string if not found.
std::string get_smartctl_binary();
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+2 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.txt
***************************************************************************/
@@ -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),
+94 -101
View File
@@ -1,12 +1,12 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include <stdint.h> // uint64_t
#include <clocale> // setlocale, localeconv
#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
@@ -148,23 +148,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");
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");
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;
@@ -198,35 +209,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?).
@@ -258,7 +272,7 @@ std::string SmartctlParser::parse_byte_size(const std::string& str, uint64_t& by
// 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");
// debug_out_dump("app", "Size reported as: " << str << "\n");
std::vector<std::string> to_replace;
to_replace.push_back(" ");
@@ -344,16 +358,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
@@ -468,6 +479,9 @@ bool SmartctlParser::parse_section_info_property(StorageProperty& p)
} else {
debug_out_warn("app", DBG_FUNC_MSG << "Unknown attribute \"" << 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;
@@ -500,7 +514,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 {
@@ -561,14 +575,8 @@ 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);
@@ -599,16 +607,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);
@@ -644,8 +648,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
@@ -712,7 +715,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 "."
@@ -744,9 +747,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.
@@ -757,29 +757,29 @@ 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_offline_time = app_pcre_re("/^(Total time to complete Off-?line data collection)/mi"); // match on name!
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_status = app_pcre_re("/^Self-test execution status/mi"); // 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_selftest_short_time = app_pcre_re("/^(Short self-test routine recommended polling time)/mi"); // match on name!
pcrecpp::RE re_selftest_long_time = app_pcre_re("/^(Extended self-test routine recommended polling time)/mi"); // match on name!
pcrecpp::RE re_conv_selftest_time = app_pcre_re("/^(Conveyance self-test routine recommended polling time)/mi"); // match on name!
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");
if (cap.section != StorageProperty::section_data || cap.subsection != StorageProperty::subsection_capabilities) {
debug_out_error("app", DBG_FUNC_MSG << "Non-capability property passed.\n");
@@ -991,10 +991,6 @@ 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);
@@ -1010,13 +1006,13 @@ bool SmartctlParser::parse_section_data_subsection_attributes(const std::string&
bool attr_found = false; // at least one attribute was found
bool attr_format_with_updated = false; // UPDATED column present
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);
pcrecpp::RE re_up = app_pcre_re("/[ \\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]*/mi");
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);
pcrecpp::RE re_noup = app_pcre_re("/[ \\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]*/mi");
pcrecpp::RE re_flag_descr("^[\\t ]+\\|", re_options);
pcrecpp::RE re_flag_descr = app_pcre_re("/^[\\t ]+\\|/mi");
for(unsigned int i = 0; i < lines.size(); ++i) {
@@ -1036,7 +1032,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);
@@ -1140,10 +1136,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.
@@ -1153,7 +1145,7 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
// 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)) {
@@ -1177,8 +1169,8 @@ bool SmartctlParser::parse_section_data_subsection_error_log(const std::string&
// error log 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)) {
@@ -1203,11 +1195,13 @@ 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"
pcrecpp::RE re_type = app_pcre_re("/[ \\t]+Error:[ \\t]*([ ,a-z]+)[ \\t]+[0-9]+[ \\t]*(.*)$/mi");
std::string block, name, value_num, value_time;
pcrecpp::StringPiece input(sub); // position tracker
@@ -1218,9 +1212,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"
@@ -1230,8 +1224,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);
@@ -1270,9 +1270,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:
@@ -1301,9 +1298,9 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
// 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)) {
@@ -1333,7 +1330,7 @@ bool SmartctlParser::parse_section_data_subsection_selftest_log(const std::strin
{
// split by columns.
// num, type, status, remaining, hours, lba (optional).
pcrecpp::RE re("^(#[ \\t]*([0-9]+)[ \\t]+(\\S+(?: \\S+)*) [ \\t]*(\\S.*) [ \\t]*([0-9]+%) [ \\t]*([0-9]+)[ \\t]*((?: [ \\t]*\\S.*)?))$", re_options);
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
@@ -1423,10 +1420,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.
+4 -5
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.txt
***************************************************************************/
+5 -10
View File
@@ -1,19 +1,17 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.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));
+22 -20
View File
@@ -1,23 +1,22 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 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 <cstdio> // std::fgets(), std::FILE
#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>
#if defined CONFIG_KERNEL_FAMILY_WINDOWS
#include <windows.h> // CreateFileA(), CloseHandle(), etc...
#endif
#include "hz/debug.h"
@@ -73,7 +72,7 @@ namespace {
hz::Dir dir(dev_dir);
std::vector<std::string> all_devices;
if (!dir.entry_list(all_devices, false)) { // this outputs to debug too.
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");
@@ -133,12 +132,12 @@ namespace {
if (!file.open("rb")) // closed automatically
return false; // the error message is in File itself.
FILE* fp = file.get_handle();
std::FILE* fp = file.get_handle();
if (!fp)
return false;
char line[256];
while (std::fgets(line, sizeof(line), fp) != NULL) {
while (std::fgets(line, static_cast<int>(sizeof(line)), fp) != NULL) {
if (*line != '\0')
lines.push_back(line);
}
@@ -201,9 +200,9 @@ namespace {
}
hz::File file(parts_file);
// std::string contents;
// std::string contents;
std::vector<std::string> lines;
// if (!f.get_contents(contents)) {
// 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()) {
@@ -214,9 +213,9 @@ namespace {
return error_msg;
}
// debug_out_dump("app", DBG_FUNC_MSG << "Dumping partitions file:\n" << contents << "\n");
// debug_out_dump("app", DBG_FUNC_MSG << "Dumping partitions file:\n" << contents << "\n");
// hz::string_split(contents, '\n', lines, true);
// hz::string_split(contents, '\n', lines, true);
std::vector<std::string> blacklist;
// fixme: not sure about how partitions are visible with twa0.
@@ -225,6 +224,8 @@ namespace {
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
for (unsigned int i = 0; i < lines.size(); ++i) {
@@ -249,7 +250,7 @@ namespace {
if (blacked)
continue;
std::string path = "/dev/" + dev;
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);
}
@@ -259,11 +260,11 @@ namespace {
#elif defined CONFIG_KERNEL_WINDOWS
#elif defined CONFIG_KERNEL_FAMILY_WINDOWS
// smartctl accepts various variants, the most straight being pdN,
// (or /dev/pdN, /dev being optional) where N comes from
// (or /dev/pdN, /dev/ being optional) where N comes from
// "\\.\PhysicalDriveN" (winnt only).
inline std::string detect_drives_win32(std::vector<std::string>& devices)
@@ -274,7 +275,8 @@ namespace {
// 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...).
HANDLE h = CreateFile(name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
// 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.
@@ -300,7 +302,7 @@ namespace {
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /dev...\n");
std::string sdev_config_path;
#ifdef CONFIG_KERNEL_SOLARIS
#if defined CONFIG_KERNEL_SOLARIS
sdev_config_path = "system/solaris_dev_path";
#else // other unixes
sdev_config_path = "system/unix_sdev_path";
@@ -315,7 +317,7 @@ namespace {
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.
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");
@@ -570,7 +572,7 @@ std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
}
}
#elif defined CONFIG_KERNEL_WINDOWS
#elif defined CONFIG_KERNEL_FAMILY_WINDOWS
if (!found) {
error_msg = detect_drives_win32(devices); // win32
@@ -674,7 +676,7 @@ std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>&
debug_out_dump("app", "Device information for " << drive->get_device() << ":\n"
<< "\tModel: " << drive->get_model_name() << "\n"
<< "\tType: " << StorageDevice::get_type_name(drive->get_type()) << "\n"
<< "\tType: " << StorageDevice::get_type_readable_name(drive->get_type()) << "\n"
<< "\tSMART status: " << StorageDevice::get_status_name(drive->get_smart_status()) << "\n"
);
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+3 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_whatever.txt
***************************************************************************/
@@ -30,7 +30,8 @@ int main()
} 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() <<
" (" << StorageDevice::get_type_readable_name(drives[i]->get_type()) << ")\n";
}
}
+79 -22
View File
@@ -1,13 +1,13 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include <glibmm.h> // Glib::shell_quote()
#include "rconfig/rconfig_mini.h"
#include "hz/string_algo.h" // string_trim_copy
#include "hz/string_algo.h" // string_trim_copy, string_any_to_unix_copy
#include "hz/fs_path.h" // FsPath
#include "hz/fs_path_utils.h" // hz::filename_make_safe
#include "hz/format_unit.h" // hz::format_date
@@ -16,6 +16,7 @@
#include "storage_device.h"
#include "smartctl_parser.h"
#include "storage_settings.h"
#include "smartctl_executor.h"
@@ -31,7 +32,21 @@ std::string StorageDevice::fetch_basic_data_and_parse(hz::intrusive_ptr<CmdexSyn
std::string output;
// We don't use "--all" - it may cause really screwed up the output (tests, etc...).
// This looks just like "--info" only on non-smart devices.
std::string error_msg = execute_smartctl("-i -H -c", smartctl_ex, output); // --info --health --capabilities
// --info --health --capabilities
std::string error_msg = execute_smartctl("-i -H -c", smartctl_ex, output, true); // set type to invalid if needed
// Smartctl 5.39 cvs/svn version defaults to usb type on at least linux and windows.
// This means that the old SCSI identify command isn't executed by default,
// and there is no information about the device manufacturer/etc... in the output.
// We detect this and set the device type to scsi to at least have _some_ info.
if (get_type() == type_invalid) {
debug_out_info("app", "The device seems to be of different type than auto-detected, trying again with scsi.\n");
this->set_type(type_scsi);
return this->fetch_basic_data_and_parse(smartctl_ex); // try again with scsi
}
// Since the type error leads to "command line didn't parse" error here,
// we do this after the scsi stuff.
if (!error_msg.empty())
return error_msg;
@@ -54,8 +69,8 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
return "Cannot read information from an empty string.";
}
std::string version = SmartctlParser::parse_version(this->info_output_);
if (version.empty()) // is this smartctl data at all?
std::string version, version_full;
if (!SmartctlParser::parse_version(this->info_output_, version, version_full)) // is this smartctl data at all?
return "Cannot get smartctl version information.";
// detect type. note: we can't distinguish between sata and scsi (on linux, for -d ata switch).
@@ -116,7 +131,9 @@ std::string StorageDevice::parse_basic_data(bool do_set_properties, bool emit_si
}
// try to parse the properties. ignore its errors - we already got what we came for.
// Try to parse the properties. ignore its errors - we already got what we came for.
// Note that this may try to parse data the second time (it may already have
// been parsed by parse_data() which failed at it).
if (do_set_properties) {
SmartctlParser ps;
if (ps.parse_full(this->info_output_)) { // try to parse it
@@ -141,13 +158,28 @@ std::string StorageDevice::fetch_data_and_parse(hz::intrusive_ptr<CmdexSync> sma
this->clear_fetched(); // clear everything fetched before, including outputs
std::string output;
// std::string error_msg = execute_smartctl("-a", smartctl_ex, output); // --all
std::string error_msg;
// instead of -a, we use all the individual options -a encompasses, so that
// an addition to default -a output won't affect us.
// IDE equivalent of -a:
std::string error_msg = execute_smartctl("-H -i -c -A -l error -l selftest -l selective", smartctl_ex, output);
// SCSI equivalent of -a:
// std::string error_msg = execute_smartctl("-H -i -A -l error -l selftest", smartctl_ex, output);
if (this->get_type() == type_scsi) {
// This doesn't do much yet, but just in case...
// SCSI equivalent of -a:
error_msg = execute_smartctl("-H -i -A -l error -l selftest", smartctl_ex, output);
} else {
// ATA equivalent of -a:
error_msg = execute_smartctl("-H -i -c -A -l error -l selftest -l selective",
smartctl_ex, output, true); // set type to invalid if needed
}
// See notes above (in fetch_basic_data_and_parse()).
if (get_type() == type_invalid) {
debug_out_info("app", "The device seems to be of different type than auto-detected, trying again with scsi.\n");
this->set_type(type_scsi);
return this->fetch_data_and_parse(smartctl_ex); // try again with scsi
}
// Since the type error leads to "command line didn't parse" error here,
// we do this after the scsi stuff.
if (!error_msg.empty())
return error_msg;
@@ -407,14 +439,27 @@ std::string StorageDevice::get_device_options() const
return std::string();
}
return app_get_device_option(get_device());
std::string config_options = app_get_device_option(get_device());
// If we have some special type, specify it on the command line (like "-d scsi").
// Note that the latter "-d" option overrides the former, so we're ok with multiple ones.
std::string type_arg = get_type_arg_name(this->get_type());
if (!type_arg.empty()) {
if (!config_options.empty()) {
config_options += " ";
}
config_options += "-d " + type_arg;
}
return config_options;
}
// Returns error message on error, empty string on success
std::string StorageDevice::execute_smartctl(const std::string& command_options,
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& output) const
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& smartctl_output, bool check_type)
{
// don't forbid running on currently tested drive - we need to call this from the test code.
@@ -438,16 +483,16 @@ std::string StorageDevice::execute_smartctl(const std::string& command_options,
if (!smartctl_ex) // if it doesn't exist, create a default one
smartctl_ex = new SmartctlExecutor(); // will be auto-deleted
std::string smartctl_binary, smartctl_def_options;
rconfig::get_data("system/smartctl_binary", smartctl_binary);
rconfig::get_data("system/smartctl_options", smartctl_def_options);
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 += " ";
@@ -460,20 +505,32 @@ std::string StorageDevice::execute_smartctl(const std::string& command_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_error("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n");
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n");
std::string output = 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_ex->get_stdout_str())) {
if (app_pcre_match("/Smartctl open device.+Permission denied/mi", output)) {
return "Permission denied while opening device.";
}
// Smartctl 5.39 cvs/svn version defaults to usb type on at least linux and windows.
// This means that the old SCSI identify command isn't executed by default,
// and there is no information about the device manufacturer/etc... in the output.
// We detect this and set the device type to scsi to at least have _some_ info.
if (check_type && this->get_type() == type_unknown
&& app_pcre_match("/specify device type with the -d option/mi", output)) {
this->set_type(type_invalid);
}
return smartctl_ex->get_error_msg();
}
output = smartctl_ex->get_stdout_str();
if (output.empty()) {
// 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.";
}
+26 -15
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -30,27 +30,38 @@ class StorageDevice : public hz::intrusive_ptr_referenced {
// to display the correct icon
enum type_t {
type_unknown, // unknown. will be autodetected by smartctl
type_cddvd // unsupported by smartctl
// type_pata, // old pata
// we can't differentiate between these.
// type_ata, // libata
// type_scsi, // scsi
type_invalid, // this is set by smartctl executor if it detects invalid type (but not if it's scsi).
type_cddvd, // unsupported by smartctl, only basic info is given.
type_scsi // this is used to force "-d scsi" to execute IDENTIFY command.
};
static std::string get_type_name(type_t type)
// this gives a string which can be displayed in outputs
static std::string get_type_readable_name(type_t type)
{
switch (type) {
case type_unknown: return "unknown";
case type_cddvd: return "cd_dvd";
// case type_pata: return "old_pata";
// case type_ata: return "libata";
// case type_scsi: return "scsi";
case type_invalid: return "invalid";
case type_cddvd: return "cd/dvd";
case type_scsi: return "scsi";
}
return "[internal_error]";
}
// this gives a string which, if not empty, can be given as a parameter of "-d".
static std::string get_type_arg_name(type_t type)
{
switch (type) {
case type_unknown: return "";
case type_invalid: return "";
case type_cddvd: return "";
case type_scsi: return "scsi";
}
return "";
}
enum status_t { // statuses of various states
status_enabled, // smart, aodc
status_disabled, // smart, aodc
@@ -147,7 +158,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced {
}
// calls "smartctl --info" (info sectio), then parse_basic_data()
// calls "smartctl --info" (info section), then parse_basic_data()
// called during drive detection.
// note: this will clear the non-basic properties!
std::string fetch_basic_data_and_parse(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
@@ -344,12 +355,12 @@ class StorageDevice : public hz::intrusive_ptr_referenced {
std::string get_save_filename() const;
std::string get_device_options() const; // get smartctl options for this device from config.
std::string get_device_options() const; // get smartctl options for this device from config and type info.
// execute smartctl on this device. nothing is modified in this class.
std::string execute_smartctl(const std::string& command_options,
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& output) const;
hz::intrusive_ptr<CmdexSync> smartctl_ex, std::string& output, bool check_type = false);
// emitted whenever new information is available
+15 -7
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -10,6 +10,7 @@
#include "hz/string_num.h" // number_to_string
#include "hz/stream_cast.h" // stream_cast<>
#include "hz/format_unit.h" // format_time_length
#include "hz/string_algo.h" // string_join
#include "storage_property.h"
@@ -38,7 +39,7 @@ std::ostream& operator<< (std::ostream& os, const StorageAttribute& p)
std::string StorageErrorBlock::get_readable_error_type(const std::string& type)
std::string StorageErrorBlock::get_readable_error_types(const std::vector<std::string>& types)
{
std::map<std::string, std::string> m;
@@ -57,18 +58,25 @@ std::string StorageErrorBlock::get_readable_error_type(const std::string& type)
m["UNC"] = "Uncorrectable error in data";
m["WP"] = "Media is write protected";
if (m.find(type) != m.end())
return m[type];
std::vector<std::string> sv;
for (std::vector<std::string>::const_iterator iter = types.begin(); iter != types.end(); ++iter) {
if (m.find(*iter) != m.end()) {
sv.push_back(m[*iter]);
} else {
sv.push_back("[unknown type" + (iter->empty() ? "" : (": " + (*iter))) + "]");
}
}
return "[unknown type]";
return hz::string_join(sv, ", ");
}
std::ostream& operator<< (std::ostream& os, const StorageErrorBlock& b)
{
os << "Error number: " << b.error_num << ", "
<< b.reported_type << " [" << StorageErrorBlock::get_readable_error_type(b.reported_type) << "]";
os << "Error number " << b.error_num << ": "
<< hz::string_join(b.reported_types, ", ")
<< " [" << StorageErrorBlock::get_readable_error_types(b.reported_types) << "]";
return os;
}
+7 -5
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -8,10 +8,11 @@
#define STORAGE_PROPERTY_H
#include <string>
#include <stdint.h>
#include <vector>
#include <iosfwd>
#include "hz/cstdint.h"
@@ -96,7 +97,8 @@ class StorageAttribute {
StorageAttribute() : id(-1), value(0), worst(0), threshold(0),
attr_type(attr_type_unknown), update_type(update_type_unknown)
attr_type(attr_type_unknown), update_type(update_type_unknown),
when_failed(fail_time_unknown), raw_value_int(0)
{ }
@@ -126,12 +128,12 @@ class StorageErrorBlock {
StorageErrorBlock() : error_num(0), lifetime_hours(0)
{ }
static std::string get_readable_error_type(const std::string& type);
static std::string get_readable_error_types(const std::vector<std::string>& types);
uint32_t error_num; // error number
uint32_t lifetime_hours; // when it occurred
std::string device_state; // "active or idle", standby, etc...
std::string reported_type; // e.g. "UNC".
std::vector<std::string> reported_types; // e.g. array of reported strings, e.g. "UNC".
std::string type_more_info; // more info on error type (e.g. "at LBA = 0x0253eac0 = 39054016")
};
+4 -4
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -12,7 +12,7 @@
// colors for tree rows
inline bool app_property_get_row_hilight_colors(StorageProperty::warning_t warning, std::string& fg, std::string& bg)
inline bool app_property_get_row_highlight_colors(StorageProperty::warning_t warning, std::string& fg, std::string& bg)
{
// Note: we're setting both fg and bg, to avoid theme conflicts.
if (warning == StorageProperty::warning_notice) {
@@ -34,7 +34,7 @@ inline bool app_property_get_row_hilight_colors(StorageProperty::warning_t warni
// colors for labels
inline bool app_property_get_label_hilight_color(StorageProperty::warning_t warning, std::string& fg)
inline bool app_property_get_label_highlight_color(StorageProperty::warning_t warning, std::string& fg)
{
if (warning == StorageProperty::warning_notice) {
fg = "#770000"; // very dark red
@@ -56,7 +56,7 @@ inline bool app_property_get_label_hilight_color(StorageProperty::warning_t warn
inline std::string storage_property_get_warning_reason(const StorageProperty& p)
{
std::string fg, start, stop;
if (app_property_get_label_hilight_color(p.warning, fg)) {
if (app_property_get_label_highlight_color(p.warning, fg)) {
start = "<span color=\"" + fg + "\">";
stop = "</span>";
}
+21 -3
View File
@@ -1,9 +1,11 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include <vector>
#include "hz/string_algo.h" // string_replace_copy
#include "applib/app_pcrecpp.h"
@@ -59,7 +61,23 @@ namespace {
} else {
bool known_by_smartctl = !app_pcre_match("/Unknown_Attribute/i", p.reported_name);
bool smartctl_is_same = app_pcre_match("/^" + app_pcre_escape(smartctl_name) + "$/i", attr_name);
// check if smartctl_name is approximately the same as our description.
std::string regex = app_pcre_escape(smartctl_name);
std::string match = attr_name;
std::vector<std::string> searches, replacements;
searches.push_back("-");
replacements.push_back(" ");
searches.push_back("/");
replacements.push_back(" ");
searches.push_back("Ct");
replacements.push_back("Count");
hz::string_replace_array(regex, searches, replacements);
hz::string_replace_array(match, searches, replacements);
bool smartctl_is_same = app_pcre_match("/^" + regex + "$/i", match);
p.readable_name = attr_name;
@@ -127,7 +145,7 @@ bool storage_property_autoset_description(StorageProperty& p)
// Read Channel Margin
|| auto_set_attr(p, 6, "Read Channel Margin", "Margin of a channel while reading data. The function of this attribute is not specified.")
// Seek Error Rate
|| auto_set_attr(p, 7, "Seek Error Rate", "Number of seek errors (Raw value). When a drive reads data, it positions heads in the needed place. If there is a failure in the mechanical positioning system, a seek error arises. More seek errors indicate worse condition of a disk surface and disk mechanical subsystem.")
|| auto_set_attr(p, 7, "Seek Error Rate", "Frequency of errors appearance while positioning. When a drive reads data, it positions heads in the needed place. If there is a failure in the mechanical positioning system, a seek error arises. More seek errors indicate worse condition of a disk surface and disk mechanical subsystem. The exact meaning of the Raw value is manufacturer-dependent.")
// Seek Time Performance
|| auto_set_attr(p, 8, "Seek Time Performance", "Average efficiency of seek operations of the magnetic heads. If this value is decreasing, it is a sign of problems in the hard disk drive mechanical subsystem.")
// Power-On Hours (Maxtor may use minutes, Fujitsu may use seconds, some even temperature?)
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+3 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -58,7 +58,8 @@ inline std::string app_serialize_device_option_map(const device_option_map_t& op
std::vector<std::string> pairs;
for (device_option_map_t::const_iterator iter = option_map.begin(); iter != option_map.end(); ++iter) {
pairs.push_back(enc.encode(iter->first) + ":" + enc.encode(iter->second));
if (!iter->first.empty())
pairs.push_back(enc.encode(iter->first) + ":" + enc.encode(iter->second));
}
return hz::string_join(pairs, ';');
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+46 -37
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_zlib.txt file
***************************************************************************/
@@ -52,7 +52,6 @@ This file is not included directly, but through the compiler option
#include <iosfwd>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <ios>
@@ -63,7 +62,9 @@ This file is not included directly, but through the compiler option
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <csignal>
#include <cerrno>
#include <cstddef>
#include <cstring>
@@ -72,16 +73,14 @@ This file is not included directly, but through the compiler option
#endif
// most of the other headers
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#ifdef ENABLE_GLIB
// #include <dirent.h>
#if defined ENABLE_GLIB && ENABLE_GLIB
#include <glib.h>
#endif
#ifdef ENABLE_GLIBMM
#if defined ENABLE_GLIBMM && ENABLE_GLIBMM
#include <sigc++/sigc++.h>
#include <gtkmm.h> // if we have glibmm, we're building everything
#include <gtk/gtk.h>
@@ -96,28 +95,34 @@ This file is not included directly, but through the compiler option
// this is either defined to 1 (by autoconf), or undefined
#ifdef HAVE_LONG_LONG_INT
// pcrecpp uses this
#ifndef HAVE_LONG_LONG
#define HAVE_LONG_LONG
#endif
#define DISABLE_LL_INT 0
#else // there is no long long int
// explicitly disable it in our code. by default, it assumes that long long int exists.
#define DISABLE_LL_INT
#define DISABLE_LL_INT 1
#endif
// this is either defined to 1 (by autoconf), or undefined
#ifdef HAVE_UNSIGNED_LONG_LONG_INT
// pcrecpp uses this
#ifndef HAVE_UNSIGNED_LONG_LONG
#define HAVE_UNSIGNED_LONG_LONG
#endif
#define DISABLE_ULL_INT 0
#else // there is no long long int
// explicitly disable it in our code. by default, it assumes that long long int exists.
#define DISABLE_ULL_INT
#define DISABLE_ULL_INT 1
#endif
@@ -127,22 +132,20 @@ This file is not included directly, but through the compiler option
// HAVE_DECL_func means that it's declared in a header.
// HAVE_DECL_func is always defined as 0 or 1.
// check if it's not in stdlib.h
#if defined HAVE_DECL_STRTOF && !HAVE_DECL_STRTOF
// #ifdef HAVE_STRTOF // it's not in header, but it is in a library
// float strtof(const char *nptr, char **endptr);
// #else // neither header, nor library
#define DISABLE_STRTOF
// #endif
// check if it's not in stdlib.h.
// HAVE_DECL_* is always either 1 or 0.
#if !defined DISABLE_STRTOF && defined HAVE_DECL_STRTOF && !HAVE_DECL_STRTOF
#define DISABLE_STRTOF 1
#else
#define DISABLE_STRTOF 0
#endif
#if defined HAVE_DECL_STRTOLD && !HAVE_DECL_STRTOLD
// #ifdef HAVE_STRTOLD
// long double strtold(const char *nptr, char **endptr);
// #else
#define DISABLE_STRTOLD
// #endif
// HAVE_DECL_* is always either 1 or 0.
#if !defined DISABLE_STRTOLD && defined HAVE_DECL_STRTOLD && !HAVE_DECL_STRTOLD
#define DISABLE_STRTOLD 1
#else
#define DISABLE_STRTOLD 0
#endif
@@ -156,8 +159,8 @@ This file is not included directly, but through the compiler option
// -- These have effect in rmn, hz error library, hz string_tools.
// These will be defined automatically by autoconf if found.
// #define ENABLE_GLIB
// #define ENABLE_GLIBMM
// #define ENABLE_GLIB 1
// #define ENABLE_GLIBMM 1
// -- RMN settings - see rmn/rmn.h for details
@@ -169,20 +172,26 @@ This file is not included directly, but through the compiler option
// makes the headers work in full when there is no config.h.
// -- Define this if using -fno-rtti or similar (automatic from autoconf).
#ifndef HAVE_RTTI
#define DISABLE_RTTI
// HAVE_RTTI is always defined as 1 or 0.
#if !defined DISABLE_RTTI && defined HAVE_RTTI && !HAVE_RTTI
#define DISABLE_RTTI 1
#else
#define DISABLE_RTTI 0
#endif
// -- Define this if using -fno-exceptions (automatic from autoconf).
#ifndef HAVE_EXCEPTIONS
#define DISABLE_EXCEPTIONS
// HAVE_EXCEPTIONS is always defined as 1 or 0.
#if !defined DISABLE_EXCEPTIONS && defined HAVE_EXCEPTIONS && !HAVE_EXCEPTIONS
#define DISABLE_EXCEPTIONS 1
#else
#define DISABLE_EXCEPTIONS 0
#endif
// -- Default policy for synchronization primitives (sync.h);
// (define only one of these):
/*
// check if any of them are forced
#if (!defined HZ_SYNC_DEFAULT_POLICY_BOOST) \
&& (!defined HZ_SYNC_DEFAULT_POLICY_GLIB) \
@@ -191,7 +200,7 @@ This file is not included directly, but through the compiler option
&& (!defined HZ_SYNC_DEFAULT_POLICY_PTHREAD) \
&& (!defined HZ_SYNC_DEFAULT_POLICY_WIN32)
#if defined ENABLE_GLIB
#if defined ENABLE_GLIB && ENABLE_GLIB
#define HZ_SYNC_DEFAULT_POLICY_GLIB
#elif defined _WIN32
#define HZ_SYNC_DEFAULT_POLICY_WIN32
@@ -205,19 +214,19 @@ This file is not included directly, but through the compiler option
// #define HZ_SYNC_DEFAULT_POLICY_POCO
#endif
*/
// -- Default policy for thread-local storage pointer (tls.h);
// (define only one of these):
/*
// check if any of them are forced
#if (!defined HZ_TLS_DEFAULT_POLICY_BOOST) \
&& (!defined HZ_TLS_DEFAULT_POLICY_GLIB) \
&& (!defined HZ_TLS_DEFAULT_POLICY_PTHREAD) \
&& (!defined HZ_TLS_DEFAULT_POLICY_WIN32)
#if defined ENABLE_GLIB
#if defined ENABLE_GLIB && ENABLE_GLIB
#define HZ_TLS_DEFAULT_POLICY_GLIB
#elif defined _WIN32
@@ -233,7 +242,7 @@ This file is not included directly, but through the compiler option
// #define HZ_TLS_DEFAULT_POLICY_WIN32
#endif
*/
// -- hz/debug.h settings.
@@ -270,8 +279,8 @@ This file is not included directly, but through the compiler option
// #define INTRUSIVE_PTR_REF_TRACING
// This enables runtime checks for errors (with exception throwing)
#ifdef DEBUG_BUILD
#define INTRUSIVE_PTR_RUNTIME_CHECKS
#if defined DEBUG_BUILD && !defined INTRUSIVE_PTR_RUNTIME_CHECKS
#define INTRUSIVE_PTR_RUNTIME_CHECKS 1
#endif
+5 -2
View File
@@ -1,9 +1,11 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include "hz/hz_config.h" // VERSION
#include <list> // list is more header-lightweight than vector
#include "hz/debug.h"
@@ -37,6 +39,7 @@ GscAboutDialog::GscAboutDialog(BaseObjectType* gtkcobj, const app_ui_res_ref_t&
// We don't set either, but rely on Glib::set_application_name() during init, which
// works with both older and newer versions.
set_version(VERSION);
// set these properties here (after setting hooks) to make the links work.
set_website("http://gsmartcontrol.berlios.de/");
@@ -44,7 +47,7 @@ GscAboutDialog::GscAboutDialog(BaseObjectType* gtkcobj, const app_ui_res_ref_t&
set_license(LicenseTextResData().get_string());
// spammers go away
set_copyright("Copyright (C) 2008 Alexander Shaduri " "<ashaduri" "" "@" "" "" "gmail.com>");
set_copyright("Copyright (C) 2008 - 2009 Alexander Shaduri " "<ashaduri" "" "@" "" "" "gmail.com>");
std::string authors_str = AuthorsTextResData().get_string();
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+14 -11
View File
@@ -1,10 +1,11 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
#include <sstream>
#include <cstddef> // std::size_t
#include <gtkmm/button.h>
#include <gtkmm/entry.h>
#include <gtkmm/textview.h>
@@ -90,13 +91,13 @@ GscExecutorLogWindow::GscExecutorLogWindow(BaseObjectType* gtkcobj, const app_ui
// Setting text on this entry segfaults under win32, (utf8 conversion doesn't
// help, not that it should). Seems to be connected to non-english locale.
// Surprisingly, the treeview column text still works.
// Any solutions?
#ifdef _WIN32
Gtk::HBox* command_hbox = this->lookup_widget<Gtk::HBox*>("command_hbox");
if (command_hbox)
command_hbox->hide();
#endif
// The problem seems to have disappeared (new compiler/runtime?)
// #ifdef _WIN32
// Gtk::HBox* command_hbox = this->lookup_widget<Gtk::HBox*>("command_hbox");
// if (command_hbox)
// command_hbox->hide();
// #endif
// ---------------
@@ -230,14 +231,14 @@ void GscExecutorLogWindow::on_window_save_all_button_clicked()
{
// complete libdebug output + execution logs
std::stringstream exss;
std::ostringstream exss;
exss << "\n------------------------- LIBDEBUG LOG -------------------------\n\n\n";
exss << app_get_debug_buffer_str() << "\n\n\n";
exss << "\n\n\n------------------------- EXECTION LOG -------------------------\n\n\n";
for (unsigned int i = 0; i < entries.size(); ++i) {
for (std::size_t i = 0; i < entries.size(); ++i) {
exss << "\n\n\n------------------------- EXECUTED COMMAND " << (i+1) << " -------------------------\n\n";
exss << "\n---------------" << "Command" << "---------------\n";
exss << entries[i]->command << "\n";
@@ -353,13 +354,15 @@ void GscExecutorLogWindow::on_tree_selection_changed()
}
}
#ifndef _WIN32
// Hide in win32 because it is known to cause segfaults there (see above).
// Not anymore...
// #ifndef _WIN32
Gtk::Entry* command_entry = this->lookup_widget<Gtk::Entry*>("command_entry");
if (command_entry) {
std::string cmd_text = entry->command + " " + entry->parameters;
command_entry->set_text(cmd_text);
}
#endif
// #endif
Gtk::Button* window_save_current_button = this->lookup_widget<Gtk::Button*>("window_save_current_button");
if (window_save_current_button)
+3 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -8,6 +8,7 @@
#define GSC_EXECUTOR_LOG_WINDOW_H
#include <vector>
#include <cstddef> // std::size_t
#include <gtkmm/window.h>
#include <gtkmm/liststore.h>
#include <gtkmm/treeselection.h>
@@ -51,7 +52,7 @@ class GscExecutorLogWindow : public AppUIResWidget<GscExecutorLogWindow, false>
Glib::RefPtr<Gtk::ListStore> list_store;
Glib::RefPtr<Gtk::TreeSelection> selection;
Gtk::TreeModelColumn<unsigned int> col_num;
Gtk::TreeModelColumn<std::size_t> col_num;
Gtk::TreeModelColumn<std::string> col_command;
Gtk::TreeModelColumn<CmdexSyncCommandInfoRefPtr> col_entry;
+3 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -173,7 +173,8 @@ void GscHelpWindow::set_topic(const Glib::ustring& topic)
for (Gtk::TreeIter iter = list_store->children().begin(); iter != list_store->children().end(); ++iter) {
if (iter->get_value(col_topic) == topic) {
selection->select(*iter);
treeview->scroll_to_cell(list_store->get_path(iter), *(treeview->get_column(0)), 0.3, 0.); // about 30% from top
// about 30% from top
treeview->scroll_to_cell(list_store->get_path(iter), *(treeview->get_column(0)), 0.3f, 0.f);
break;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+149 -96
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -11,7 +11,7 @@
#include "hz/down_cast.h"
#include "hz/string_num.h" // number_to_string
#include "hz/string_format.h" // string_sprintf
#include "hz/string_sprintf.h" // string_sprintf
#include "hz/string_algo.h" // string_join
#include "hz/fs_file.h" // hz::File
#include "hz/format_unit.h" // format_time_length
@@ -76,7 +76,7 @@ namespace {
label->set_flags(label->get_flags() & ~Gtk::CAN_FOCUS);
std::string fg;
if (app_property_get_label_hilight_color(iter->property->warning, fg))
if (app_property_get_label_highlight_color(iter->property->warning, fg))
label->set_markup("<span color=\"" + fg + "\">" + label_text + "</span>");
vbox->pack_start(*label, false, false);
@@ -100,7 +100,7 @@ namespace {
Gtk::CellRendererText* crt = hz::down_cast<Gtk::CellRendererText*>(cr);
if (crt) {
std::string fg, bg;
if (app_property_get_row_hilight_colors(p->warning, fg, bg)) {
if (app_property_get_row_highlight_colors(p->warning, fg, bg)) {
// Note: property_cell_background makes horizontal tree lines disappear around it,
// but property_background doesn't play nice with sorted column color.
crt->property_cell_background() = bg;
@@ -115,7 +115,7 @@ namespace {
}
inline void app_hilight_tab_label(Gtk::Widget* label_widget,
inline void app_highlight_tab_label(Gtk::Widget* label_widget,
StorageProperty::warning_t warning, const Glib::ustring& original_label)
{
Gtk::Label* label = hz::down_cast<Gtk::Label*>(label_widget);
@@ -128,7 +128,7 @@ namespace {
}
std::string fg;
if (app_property_get_label_hilight_color(warning, fg))
if (app_property_get_label_highlight_color(warning, fg))
label->set_markup_with_mnemonic("<span color=\"" + fg + "\">" + original_label + "</span>");
}
@@ -161,7 +161,7 @@ namespace {
// glade/gtkbuilder needs this constructor
GscInfoWindow::GscInfoWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& ref_ui)
: AppUIResWidget<GscInfoWindow, true>(gtkcobj, ref_ui),
device_name_label(0)
device_name_label(0), test_force_bar_update(true)
{
// Create missing widgets
@@ -358,8 +358,10 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
for (prop_iterator iter = props.begin(); iter != props.end(); ++iter) {
if (iter->section == StorageProperty::section_info) {
if (iter->generic_name == "smartctl_version") {
if (iter->generic_name == "smartctl_version_full") {
version_props.push_back(*iter);
} else if (iter->generic_name == "smartctl_version") {
continue; // we use the full version string instead.
} else {
id_props.push_back(*iter);
}
@@ -411,7 +413,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
value->set_markup(Glib::Markup::escape_text(iter->format_value()));
std::string fg;
if (app_property_get_label_hilight_color(iter->warning, fg)) {
if (app_property_get_label_highlight_color(iter->warning, fg)) {
name->set_markup("<span color=\"" + fg + "\">"+ name->get_label() + "</span>");
value->set_markup("<span color=\"" + fg + "\">"+ value->get_label() + "</span>");
}
@@ -434,7 +436,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
identity_table->show_all();
// tab label
app_hilight_tab_label(lookup_widget("identity_tab_label"), max_warning, tab_identity_name);
app_highlight_tab_label(lookup_widget("identity_tab_label"), max_warning, tab_identity_name);
} while (false);
@@ -529,7 +531,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
}
// tab label
app_hilight_tab_label(lookup_widget("capabilities_tab_label"), max_warning, tab_capabilities_name);
app_highlight_tab_label(lookup_widget("capabilities_tab_label"), max_warning, tab_capabilities_name);
} while (false);
@@ -678,7 +680,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
app_set_top_labels(label_vbox, label_strings);
// tab label
app_hilight_tab_label(lookup_widget("attributes_tab_label"), max_warning, tab_attributes_name);
app_highlight_tab_label(lookup_widget("attributes_tab_label"), max_warning, tab_attributes_name);
} while (false);
@@ -800,7 +802,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
row[col_num] = iter->value_error_block.error_num;
row[col_hours] = iter->value_error_block.lifetime_hours;
row[col_state] = iter->value_error_block.device_state;
row[col_type] = StorageErrorBlock::get_readable_error_type(iter->value_error_block.reported_type);
row[col_type] = StorageErrorBlock::get_readable_error_types(iter->value_error_block.reported_types);
row[col_details] = (type_details.empty() ? "-" : type_details); // e.g. OBS has no details
row[col_tooltip] = iter->get_description();
row[col_storage] = &(*iter);
@@ -816,7 +818,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
app_set_top_labels(label_vbox, label_strings);
// tab label
app_hilight_tab_label(lookup_widget("error_log_tab_label"), max_warning, tab_error_log_name);
app_highlight_tab_label(lookup_widget("error_log_tab_label"), max_warning, tab_error_log_name);
} while (false);
@@ -929,7 +931,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests
app_set_top_labels(label_vbox, label_strings);
// tab label
app_hilight_tab_label(lookup_widget("selftest_log_tab_label"), max_warning, tab_selftest_log_name);
app_highlight_tab_label(lookup_widget("selftest_log_tab_label"), max_warning, tab_selftest_log_name);
} while (false);
@@ -1087,7 +1089,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
}
// tab label
app_hilight_tab_label(lookup_widget("identity_tab_label"), StorageProperty::warning_none, tab_identity_name);
app_highlight_tab_label(lookup_widget("identity_tab_label"), StorageProperty::warning_none, tab_identity_name);
}
{
@@ -1103,7 +1105,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
}
// tab label
app_hilight_tab_label(lookup_widget("capabilities_tab_label"), StorageProperty::warning_none, tab_capabilities_name);
app_highlight_tab_label(lookup_widget("capabilities_tab_label"), StorageProperty::warning_none, tab_capabilities_name);
}
{
@@ -1120,7 +1122,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
}
// tab label
app_hilight_tab_label(lookup_widget("attributes_tab_label"), StorageProperty::warning_none, tab_attributes_name);
app_highlight_tab_label(lookup_widget("attributes_tab_label"), StorageProperty::warning_none, tab_attributes_name);
}
{
@@ -1144,7 +1146,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
}
// tab label
app_hilight_tab_label(lookup_widget("error_log_tab_label"), StorageProperty::warning_none, tab_error_log_name);
app_highlight_tab_label(lookup_widget("error_log_tab_label"), StorageProperty::warning_none, tab_error_log_name);
}
{
@@ -1161,7 +1163,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
}
// tab label
app_hilight_tab_label(lookup_widget("selftest_log_tab_label"), StorageProperty::warning_none, tab_selftest_log_name);
app_highlight_tab_label(lookup_widget("selftest_log_tab_label"), StorageProperty::warning_none, tab_selftest_log_name);
}
{
@@ -1217,7 +1219,7 @@ void GscInfoWindow::clear_ui_info(bool clear_tests_too)
// tab label
app_hilight_tab_label(lookup_widget("test_tab_label"), StorageProperty::warning_none, tab_test_name);
app_highlight_tab_label(lookup_widget("test_tab_label"), StorageProperty::warning_none, tab_test_name);
}
}
@@ -1365,115 +1367,117 @@ void GscInfoWindow::on_test_type_combo_changed()
// Note: Another loop like this may run inside it for another drive.
void GscInfoWindow::test_loop()
gboolean GscInfoWindow::test_idle_callback(void* data)
{
if (!current_test) // shouldn't happen
return;
GscInfoWindow* self = static_cast<GscInfoWindow*>(data);
DBG_ASSERT(self);
// Switch GUI to running test mode
if (!self->current_test) // shouldn't happen
return false; // stop
Gtk::ComboBox* test_type_combo = lookup_widget<Gtk::ComboBox*>("test_type_combo");
if (test_type_combo)
test_type_combo->set_sensitive(false);
Gtk::Button* test_execute_button = lookup_widget<Gtk::Button*>("test_execute_button");
if (test_execute_button)
test_execute_button->set_sensitive(false);
Gtk::ProgressBar* test_completion_progressbar =
self->lookup_widget<Gtk::ProgressBar*>("test_completion_progressbar");
Gtk::ProgressBar* test_completion_progressbar = lookup_widget<Gtk::ProgressBar*>("test_completion_progressbar");
if (test_completion_progressbar) {
test_completion_progressbar->set_text("");
test_completion_progressbar->set_sensitive(true);
test_completion_progressbar->show();
}
bool active = true;
Gtk::Button* test_stop_button = lookup_widget<Gtk::Button*>("test_stop_button");
if (test_stop_button) {
test_stop_button->set_sensitive(true); // true while test is active
test_stop_button->show();
}
std::string error_msg; // our errors
Glib::Timer timer_poll, timer_bar;
// one update() is performed by start(), so do the timeout first
while (true) {
if (!current_test->is_active()) // check status
do { // goto
if (!self->current_test->is_active()) { // check status
active = false;
break;
}
int8_t rem_percent = current_test->get_remaining_percent();
int8_t rem_percent = self->current_test->get_remaining_percent();
std::string rem_percent_str = (rem_percent == -1 ? "Unknown" : hz::number_to_string(100 - rem_percent));
timer_poll.start(); // restart it
int64_t poll_in = current_test->get_poll_in_seconds(); // sec
int64_t poll_in = self->current_test->get_poll_in_seconds(); // sec
timer_bar.start(); // restart
bool force_bar_update = true; // every time after poll
// wait until next poll (up to several minutes)
while (timer_poll.elapsed() < static_cast<double>(poll_in)) { // elapsed() is seconds in double.
// One update() is performed by start(), so do the timeout first.
Glib::usleep(30*1000); // 30msec. don't do more - we may have two or more loops like this
// Wait until next poll (up to several minutes). Meanwhile, interpolate
// the remaining time, update the progressbar, etc...
if (self->test_timer_poll.elapsed() < static_cast<double>(poll_in)) { // elapsed() is seconds in double.
if (force_bar_update || timer_bar.elapsed() >= 5.) { // update progress bar every 5 seconds or after poll.
// Update progress bar right after poll, plus every 5 seconds.
if (self->test_force_bar_update || self->test_timer_bar.elapsed() >= 5.) {
int64_t rem_seconds = current_test->get_remaining_seconds();
std::string rem_seconds_str = (rem_seconds == -1 ? "Unknown" : hz::format_time_length(rem_seconds));
Glib::ustring bar_str = hz::string_sprintf("Test completion: %s%%; ETA: %s",
rem_percent_str.c_str(), rem_seconds_str.c_str());
if (!error_msg.empty())
bar_str = error_msg; // better than popup every few seconds
int64_t rem_seconds = self->current_test->get_remaining_seconds();
if (test_completion_progressbar) {
std::string rem_seconds_str = (rem_seconds == -1 ? "Unknown" : hz::format_time_length(rem_seconds));
Glib::ustring bar_str;
if (self->test_error_msg.empty()) {
bar_str = hz::string_sprintf("Test completion: %s%%; ETA: %s",
rem_percent_str.c_str(), rem_seconds_str.c_str());
} else {
bar_str = self->test_error_msg; // better than popup every few seconds
}
test_completion_progressbar->set_text(bar_str);
test_completion_progressbar->set_fraction(std::max(0., std::min(1., 1. - (rem_percent / 100.))));
}
force_bar_update = false;
timer_bar.start(); // restart
self->test_force_bar_update = false;
self->test_timer_bar.start(); // restart
}
while (Gtk::Main::events_pending()) {
Gtk::Main::iteration();
}
if (!current_test->is_active()) // check status
if (!self->current_test->is_active()) { // check status
active = false;
break;
}
} else { // it's poll time
if (!self->current_test->is_active()) { // the inner loop stopped, stop this one too
active = false;
break;
}
SmartctlExecutorGuiRefPtr ex(new SmartctlExecutorGui());
ex->create_running_dialog(self);
self->test_error_msg = self->current_test->update(ex);
if (!self->test_error_msg.empty()) {
// gui_show_error_dialog("Cannot monitor test progress", self->test_error_msg, this); // better show in progressbar.
self->current_test->force_stop(ex); // what else can we do?
active = false;
break;
}
self->test_timer_poll.start(); // restart it
self->test_force_bar_update = true; // force progressbar / ETA update on the next tick
}
if (!current_test->is_active()) // the inner loop stopped, stop this one too
break;
SmartctlExecutorGuiRefPtr ex(new SmartctlExecutorGui());
ex->create_running_dialog(this);
} while (false);
error_msg = current_test->update(ex);
if (!error_msg.empty()) {
// gui_show_error_dialog("Cannot monitor test progress", error_msg, this); // better show in progressbar.
current_test->force_stop(ex); // what else can we do?
}
if (active) {
return true; // continue the idle callback
}
timer_poll.stop(); // just in case
timer_bar.stop(); // just in case
// Test is finished, clean up
// Test is finished
self->test_timer_poll.stop(); // just in case
self->test_timer_bar.stop(); // just in case
StorageSelftestEntry::status_t status = current_test->get_status();
StorageSelftestEntry::status_t status = self->current_test->get_status();
bool aborted = false;
StorageSelftestEntry::status_severity_t severity = StorageSelftestEntry::severity_none;
std::string result_msg;
if (!error_msg.empty()) {
if (!self->test_error_msg.empty()) {
aborted = true;
severity = StorageSelftestEntry::severity_error;
result_msg = "<b>Test aborted: </b>" + error_msg;
result_msg = "<b>Test aborted: </b>" + self->test_error_msg;
} else {
severity = StorageSelftestEntry::get_status_severity(status);
@@ -1495,15 +1499,18 @@ void GscInfoWindow::test_loop()
}
Gtk::ComboBox* test_type_combo = self->lookup_widget<Gtk::ComboBox*>("test_type_combo");
if (test_type_combo)
test_type_combo->set_sensitive(true);
Gtk::Button* test_execute_button = self->lookup_widget<Gtk::Button*>("test_execute_button");
if (test_execute_button)
test_execute_button->set_sensitive(true);
if (test_completion_progressbar)
test_completion_progressbar->set_text(aborted ? "Test aborted" : "Test completed");
Gtk::Button* test_stop_button = self->lookup_widget<Gtk::Button*>("test_stop_button");
if (test_stop_button)
test_stop_button->set_sensitive(false);
@@ -1514,28 +1521,31 @@ void GscInfoWindow::test_loop()
stock_id = Gtk::Stock::DIALOG_WARNING;
}
Gtk::Image* test_result_image = lookup_widget<Gtk::Image*>("test_result_image");
Gtk::Image* test_result_image = self->lookup_widget<Gtk::Image*>("test_result_image");
// we use large icon size here because the icons we use are from dialogs.
// unfortunately, there are no non-dialog icons of this sort.
if (test_result_image)
test_result_image->set(stock_id, Gtk::ICON_SIZE_DND);
Gtk::Label* test_result_label = lookup_widget<Gtk::Label*>("test_result_label");
Gtk::Label* test_result_label = self->lookup_widget<Gtk::Label*>("test_result_label");
if (test_result_label)
test_result_label->set_markup(result_msg);
Gtk::HBox* test_result_hbox = lookup_widget<Gtk::HBox*>("test_result_hbox");
Gtk::HBox* test_result_hbox = self->lookup_widget<Gtk::HBox*>("test_result_hbox");
if (test_result_hbox)
test_result_hbox->show();
this->refresh_info(false); // don't clear the tests tab
self->refresh_info(false); // don't clear the tests tab
return false; // stop idle callback
}
void GscInfoWindow::on_test_execute_button_clicked()
{
Gtk::ComboBox* test_type_combo = lookup_widget<Gtk::ComboBox*>("test_type_combo");
@@ -1561,8 +1571,51 @@ void GscInfoWindow::on_test_execute_button_clicked()
current_test = test;
// The Main Test Loop (tm)
test_loop();
// Switch GUI to "running test" mode
if (test_type_combo)
test_type_combo->set_sensitive(false);
Gtk::Button* test_execute_button = lookup_widget<Gtk::Button*>("test_execute_button");
if (test_execute_button)
test_execute_button->set_sensitive(false);
Gtk::ProgressBar* test_completion_progressbar = lookup_widget<Gtk::ProgressBar*>("test_completion_progressbar");
if (test_completion_progressbar) {
test_completion_progressbar->set_text("");
test_completion_progressbar->set_sensitive(true);
test_completion_progressbar->show();
}
Gtk::Button* test_stop_button = lookup_widget<Gtk::Button*>("test_stop_button");
if (test_stop_button) {
test_stop_button->set_sensitive(true); // true while test is active
test_stop_button->show();
}
// reset these
test_error_msg = "";
test_timer_poll.start();
test_timer_bar.start();
test_force_bar_update = true;
// We don't use idle function here, because it has the following problem:
// CmdexSync::execute() (which is called on force_stop()) calls g_main_context_pending(),
// which returns true EVERY time, until the idle callback returns false.
// So, force_stop() exits its "execute abort" command only when the
// idle callback polls the drive on the next timeout and sees that the test
// has been actually aborted.
// So, we use timeout callback - and hope that there are no usleeps
// with 300ms so that g_main_context_pending() returns false at least once,
// to escape the execute() loop.
// g_idle_add(test_idle_callback, this);
g_timeout_add(300, test_idle_callback, this); // every 300ms
}
@@ -1582,7 +1635,7 @@ void GscInfoWindow::on_test_stop_button_clicked()
return;
}
// nothing else to do - the cleanup is performed by test_loop.
// nothing else to do - the cleanup is performed by the idle callback.
}
+10 -4
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -70,14 +70,13 @@ class GscInfoWindow : public AppUIResWidget<GscInfoWindow, true> {
void show_tests();
void test_loop(); // Runs a GUI loop until test is running
protected:
// -------------------- Callbacks
static gboolean test_idle_callback(void* data);
// ---------- override virtual methods
@@ -136,6 +135,13 @@ class GscInfoWindow : public AppUIResWidget<GscInfoWindow, true> {
SelfTestPtr current_test; // currently running test, or 0.
// test idle callback temporaries
std::string test_error_msg; // our errors
Glib::Timer test_timer_poll;
Glib::Timer test_timer_bar;
bool test_force_bar_update;
// test type combobox stuff
Gtk::TreeModelColumn<Glib::ustring> test_combo_col_name;
Gtk::TreeModelColumn<Glib::ustring> test_combo_col_description;
+68 -19
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -26,9 +26,10 @@
#include "libdebug/libdebug.h" // include full libdebug here (to add domains, etc...)
#include "rconfig/rconfig.h" // include full rconfig here
#include "hz/data_file.h" // data_file_add_search_directory
#include "hz/fs_tools.h" // get_home_dir
#include "hz/fs_tools.h" // get_user_config_dir()
#include "hz/fs_path.h" // FsPath
#include "hz/string_algo.h" // string_join
#include "hz/string_algo.h" // string_join()
#include "hz/win32_tools.h" // win32_get_registry_value_string()
#include "gsc_main_window.h"
#include "gsc_executor_log_window.h"
@@ -43,7 +44,7 @@ namespace {
static debug_channel_base_ptr s_debug_buf_channel;
static std::stringstream s_debug_buf_channel_stream;
static std::ostringstream s_debug_buf_channel_stream;
// This function is not thread-safe. The channel must be locked properly.
@@ -73,30 +74,75 @@ std::string app_get_debug_buffer_str()
inline bool app_init_config()
{
// $XDG_CONFIG_DIRS defaults to /etc/xdg, which is really silly.
// Actually, the whole specification is silly imho, since instead of
// removing just one directory/file I have to remove 3 now (and tell
// the users to do the same thing). And the *_DIRS stuff completely
// breaks parallel installations of the same program. Implementing
// only $XDG_CONFIG_HOME is harmless enough, so we do it.
s_home_config_file = hz::get_user_config_dir() + hz::DIR_SEPARATOR_S
+ "gsmartcontrol" + hz::DIR_SEPARATOR_S + "gsmartcontrol.conf";
std::string global_config_file;
std::string old_local_config; // pre-XDG and pre-CSIDL_APPDATA file for migration
#ifdef _WIN32
std::string global_config_file = "gsmartcontrol.conf"; // installation dir
s_home_config_file = hz::get_home_dir() + hz::DIR_SEPARATOR_S
+ "gsmartcontrol.conf"; // $HOME/program_name.conf
global_config_file = "gsmartcontrol.conf"; // CWD, installation dir by default.
std::string old_config_dir;
hz::win32_get_registry_value_string(HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Personal", old_config_dir);
old_local_config = old_config_dir + hz::DIR_SEPARATOR_S + "gsmartcontrol.conf";
#else
std::string global_config_file = std::string(PACKAGE_SYSCONF_DIR)
global_config_file = std::string(PACKAGE_SYSCONF_DIR)
+ hz::DIR_SEPARATOR_S + "gsmartcontrol.conf";
s_home_config_file = hz::get_home_dir() + hz::DIR_SEPARATOR_S + ".gsmartcontrolrc";
old_local_config = hz::get_home_dir() + hz::DIR_SEPARATOR_S + ".gsmartcontrolrc";
#endif
debug_out_dump("app", DBG_FUNC_MSG << "Global config file: \"" << global_config_file << "\"\n");
debug_out_dump("app", DBG_FUNC_MSG << "Local config file: \"" << s_home_config_file << "\"\n");
debug_out_dump("app", DBG_FUNC_MSG << "Old local config file: \"" << old_local_config << "\"\n");
hz::FsPath gp(global_config_file); // Default system-wide settings. This file is empty by default.
hz::FsPath hp(s_home_config_file); // Per-user settings.
hz::FsPath op(old_local_config); // Old user settings, should be migrated.
if (gp.exists() && gp.is_readable())
if (gp.exists() && gp.is_readable()) { // load global first
rconfig::load_from_file(gp.str());
}
if (hp.exists() && hp.is_readable())
if (hp.exists() && hp.is_readable()) { // load local
rconfig::load_from_file(hp.str());
} else {
// create the parent directories of the config file
hz::FsPath config_loc(hp.get_dirname());
if (!config_loc.exists()) {
config_loc.make_dir(0700, true); // with parents.
}
if (op.exists() && op.is_readable()) { // load the old config if the new one doesn't exist.
debug_print_info("app", "Old configuration file found at \"%s\", migrating to \"%s\".\n", op.c_str(), hp.c_str());
rconfig::load_from_file(op.str());
// force saving of the config to the new location (so that it's preserved in case of crash).
if (rconfig::save_to_file(hp.str())) {
// remove the old config
op.remove();
}
}
}
rconfig::dump_tree();
init_default_settings(); // initialize /default
#ifdef ENABLE_GLIB
#if defined ENABLE_GLIB && ENABLE_GLIB
rconfig::autosave_set_config_file(s_home_config_file);
uint32_t autosave_timeout = rconfig::get_data<uint32_t>("system/config_autosave_timeout");
if (autosave_timeout)
@@ -179,6 +225,8 @@ inline bool parse_cmdline_args(CmdArgs& args, int& argc, char**& argv)
g_option_context_add_group(context, debug_get_option_group());
g_option_context_parse(context, &argc, &argv, &error);
g_option_context_free(context);
if (error)
g_error_free(error);
return true;
}
@@ -192,9 +240,9 @@ inline void app_print_version_info()
std::string warningtext = std::string("\nWarning: GSmartControl");
warningtext += " comes with ABSOLUTELY NO WARRANTY.\n";
warningtext += "See LICENSE_gsmartcontrol.txt file for details.\n";
warningtext += "\nCopyright (C) 2008 Alexander Shaduri <ashaduri" "" "@" "" "" "gmail.com>\n\n";
warningtext += "\nCopyright (C) 2008 - 2009 Alexander Shaduri <ashaduri" "" "@" "" "" "gmail.com>\n\n";
std::printf("%s%s", versiontext.c_str(), warningtext.c_str());
std::fprintf(stdout, "%s%s", versiontext.c_str(), warningtext.c_str());
}
@@ -211,7 +259,7 @@ bool app_init_and_loop(int& argc, char**& argv)
// initialize GThread (for mutexes, etc... to work). Must be called before any other glib function.
Glib::thread_init();
// Glib::thread_init();
// parse command line args
@@ -293,7 +341,7 @@ bool app_init_and_loop(int& argc, char**& argv)
#ifdef _WIN32
// Now that all program-specific locale setup has been performed,
// make sure the future locale changes affect only current thread.
// Not available on mingw, so disable for now.
// Not available in mingw, so disable for now.
// _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
#endif
@@ -318,7 +366,8 @@ bool app_init_and_loop(int& argc, char**& argv)
// Add data file search paths
#ifdef _WIN32
hz::data_file_add_search_directory("."); // the program is bundled with all the files in the same directory
// In windows the program is distributed with all the data files in the same directory.
hz::data_file_add_search_directory(".");
#else
#ifdef DEBUG_BUILD
hz::data_file_add_search_directory(std::string(TOP_SRC_DIR) + "/src/res"); // application data resources
@@ -332,7 +381,7 @@ bool app_init_and_loop(int& argc, char**& argv)
// set default icon for all windows.
// set_default_icon_name is available since 2.12 in gtkmm, but since 2.6 in gtk.
#ifndef _WIN32 // win32 version has its icon compiled-in.
#ifndef _WIN32 // win32 version has its icon compiled-in, so no need to set it there.
{
// we load it via icontheme to provide multi-size version.
GtkIconTheme* default_icon_theme = gtk_icon_theme_get_default();
@@ -411,7 +460,7 @@ void app_quit()
debug_out_info("app", "Saving config before exit...\n");
// save the config
#ifdef ENABLE_GLIB
#if defined ENABLE_GLIB && ENABLE_GLIB
rconfig::autosave_force_now();
#else
rconfig::save_to_file(s_home_config_file);
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
+13 -4
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -9,28 +9,37 @@
#include <cstdlib> // EXIT_*
#include "hz/hz_config.h" // HAVE_VERBOSE_TERMINATE_HANDLER
#include "hz/win32_tools.h" // hz::win32_*
#include "gsc_init.h" // app_init_and_loop()
int main (int argc, char** argv)
int main(int argc, char* argv[])
{
// we still leave __GNUC__ for autoconf-less setups.
#if defined HAVE_VERBOSE_TERMINATE_HANDLER || defined __GNUC__
#if defined HAVE_VERBOSE_TERMINATE_HANDLER && HAVE_VERBOSE_TERMINATE_HANDLER
// Verbose uncaught exception handler
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#else
try {
#endif
// debug builds already have a console, no need to create one.
#if defined _WIN32 && !(defined DEBUG_BUILD && DEBUG_BUILD)
// if the console is not open, or unsupported (win2k), use files.
if (!hz::win32_redirect_stdio_to_console()) { // redirect stdout/stderr to console (if open and supported)
hz::win32_redirect_stdio_to_files(); // redirect stdout/stderr to output files
}
#endif
// initialize stuff and enter the main loop
if (!app_init_and_loop(argc, argv))
return EXIT_FAILURE;
// print uncaught exceptions for non-gcc-compatible
#if !(defined HAVE_VERBOSE_TERMINATE_HANDLER || defined __GNUC__)
#if !(defined HAVE_VERBOSE_TERMINATE_HANDLER && HAVE_VERBOSE_TERMINATE_HANDLER)
}
catch(std::exception& e) {
// don't use anything other than cerr here, it's the most safe option.
+28 -13
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -15,9 +15,10 @@
#include "applib/storage_detector.h"
#include "applib/smartctl_parser.h"
#include "applib/gui_utils.h" // gui_show_error_dialog
#include "applib/smartctl_executor.h" // get_smartctl_binary()
#include "applib/smartctl_executor_gui.h"
#include "applib/app_gtkmm_utils.h" // app_gtkmm_*
#include "applib/storage_property_colors.h" // app_property_get_label_hilight_color
#include "applib/storage_property_colors.h" // app_property_get_label_highlight_color
#include "applib/app_pcrecpp.h" // app_pcre_match
#include "gsc_init.h" // app_quit()
@@ -40,7 +41,8 @@
GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& ref_ui)
: AppUIResWidget<GscMainWindow, false>(gtkcobj, ref_ui), iconview(0),
action_handling_enabled_(true), name_label(0), health_label(0), family_label(0)
action_handling_enabled_(true), name_label(0), health_label(0), family_label(0),
scanning_(false)
{
APP_GTKMM_CONNECT_VIRTUAL(delete_event); // make sure the event handler is called
@@ -60,11 +62,11 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& re
bool show_output_button = true;
do {
std::string smartctl_binary, smartctl_def_options;
rconfig::get_data("system/smartctl_binary", smartctl_binary);
std::string smartctl_binary = get_smartctl_binary();
// Don't use default options here - they are used when invoked
// with a device option.
// std::string smartctl_def_options;
// rconfig::get_data("system/smartctl_options", smartctl_def_options);
if (smartctl_binary.empty()) {
@@ -94,7 +96,8 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& re
break;
}
if (SmartctlParser::parse_version(output).empty()) {
std::string version, version_full;
if (!SmartctlParser::parse_version(output, version, version_full)) {
error_msg = "Smartctl returned invalid output.";
break;
}
@@ -357,7 +360,7 @@ bool GscMainWindow::create_widgets()
}
catch(Glib::Error& ex)
{
debug_out_error("app", DBG_FUNC_MSG << "Create failed: " << ex.what() << "\n");
debug_out_error("app", DBG_FUNC_MSG << "UI creation failed: " << ex.what() << "\n");
return false;
}
@@ -443,7 +446,12 @@ void GscMainWindow::on_action_activated(GscMainWindow::action_t action_type)
return;
}
debug_out_info("app", DBG_FUNC_MSG << "Action activated: \"" << action->get_name() << "\"\n");
std::string action_name = action->get_name();
// Do NOT output action->get_name() directly, it dies with unhandled conversion error
// exception if used with operator <<.
debug_out_info("app", DBG_FUNC_MSG << "Action activated: \"" + action_name << "\"\n");
switch (action_type) {
case action_quit:
@@ -573,7 +581,7 @@ void GscMainWindow::on_action_activated(GscMainWindow::action_t action_type)
}
default:
debug_out_error("app", DBG_FUNC_MSG << "Unknown action: \"" << action->get_name() << "\"\n");
debug_out_error("app", DBG_FUNC_MSG << "Unknown action: \"" << action_name << "\"\n");
break;
}
}
@@ -898,7 +906,7 @@ void GscMainWindow::update_status_widgets()
if (health_prop.generic_name == "overall_health") {
health_label->set_text(health_prop.format_value());
std::string fg;
if (app_property_get_label_hilight_color(health_prop.warning, fg)) {
if (app_property_get_label_highlight_color(health_prop.warning, fg)) {
health_label->set_markup("<span color=\"" + fg + "\">"+ health_label->get_text() + "</span>");
}
// don't set description tooltip - we already have the basic one.
@@ -932,6 +940,11 @@ void GscMainWindow::update_status_widgets()
void GscMainWindow::rescan_devices()
{
// ignore double-scan (may happen because we use gtk loop iterations here).
if (this->scanning_)
return;
this->scanning_ = true;
// don't manipulate window sensitiveness here - it breaks things
// (cursors, gtk errors pop out, etc...)
@@ -1008,6 +1021,8 @@ void GscMainWindow::rescan_devices()
// in case there are no drives in the system.
if (iconview->num_icons == 0)
iconview->empty_view_message = GscMainWindowIconView::message_no_drives_found;
this->scanning_ = false;
}
@@ -1183,7 +1198,7 @@ void GscMainWindow::show_add_device_chooser()
"For example, pd0 means the first physical drive",
dev, last_str, this, false)) {
last_str = dev; // safe for the future
this->add_device(dev);
this->add_device(dev); // both the GUI and the API is in utf-8, no conversion is necessary.
}
@@ -1214,7 +1229,7 @@ void GscMainWindow::show_add_device_chooser()
{
last_dir = dialog.get_current_folder(); // safe for the future
std::string file = dialog.get_filename();
std::string file = dialog.get_filename(); // in fs encoding
this->add_device(file);
break;
}
@@ -1257,7 +1272,7 @@ void GscMainWindow::show_load_virtual_file_chooser()
{
last_dir = dialog.get_current_folder(); // safe for the future
std::string file = dialog.get_filename();
std::string file = dialog.get_filename(); // in fs encoding
this->add_virtual_drive(file);
break;
}
+3 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -128,6 +128,8 @@ class GscMainWindow : public AppUIResWidget<GscMainWindow, false> {
WrappingLabel* health_label;
WrappingLabel* family_label;
bool scanning_;
// -------------------- Callbacks
+2 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -194,7 +194,7 @@ class GscMainWindowIconView : public Gtk::IconView {
gtk_icon_view_set_cursor(GTK_ICON_VIEW(this->gobj()), tpath.gobj(), cell->gobj(), false);
}
#endif
this->select_path(tpath); // hilight it
this->select_path(tpath); // highlight it
}
++num_icons;
+20 -5
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/
@@ -135,8 +135,8 @@ class GscPreferencesDeviceOptionsTreeView : public Gtk::TreeView {
Gtk::TreeNodeChildren children = model->children();
for (Gtk::TreeNodeChildren::iterator iter = children.begin(); iter != children.end(); ++iter) {
Gtk::TreeModel::Row row = *iter;
if (devmap.find(row[col_device_real]) == devmap.end())
devmap[row[col_device_real]] = row[col_parameters];
if (!row.get_value(col_device_real).empty() && devmap.find(row.get_value(col_device_real)) == devmap.end())
devmap[row.get_value(col_device_real)] = row.get_value(col_parameters);
}
return devmap;
@@ -229,6 +229,13 @@ GscPreferencesWindow::GscPreferencesWindow(BaseObjectType* gtkcobj, const app_ui
// we can't do this in treeview's constructor, it doesn't know about this window yet.
this->device_widget_set_remove_possible(false); // initial state
// hide win32-only options for non-win32.
#ifndef _WIN32
Gtk::CheckButton* smartctl_search_check = this->lookup_widget<Gtk::CheckButton*>("search_in_smartmontools_first_check");
if (smartctl_search_check)
smartctl_search_check->hide();
#endif
// ---------------
@@ -308,16 +315,21 @@ void GscPreferencesWindow::import_config()
// ------- General tab
bool scan_on_startup;
bool scan_on_startup = 0;
if ( prefs_config_get("gui/scan_on_startup", scan_on_startup)
&& (check = this->lookup_widget<Gtk::CheckButton*>("scan_on_startup_check")) )
check->set_active(scan_on_startup);
bool show_smart_capable_only;
bool show_smart_capable_only = 0;
if ( prefs_config_get("gui/show_smart_capable_only", show_smart_capable_only)
&& (check = this->lookup_widget<Gtk::CheckButton*>("show_smart_capable_only_check")) )
check->set_active(show_smart_capable_only);
bool win32_search_smartctl_in_smartmontools = 0;
if ( prefs_config_get("system/win32_search_smartctl_in_smartmontools", win32_search_smartctl_in_smartmontools)
&& (check = this->lookup_widget<Gtk::CheckButton*>("search_in_smartmontools_first_check")) )
check->set_active(win32_search_smartctl_in_smartmontools);
std::string smartctl_binary;
if ( prefs_config_get("system/smartctl_binary", smartctl_binary)
&& (entry = this->lookup_widget<Gtk::Entry*>("smartctl_binary_entry")) )
@@ -363,6 +375,9 @@ void GscPreferencesWindow::export_config()
if ((check = this->lookup_widget<Gtk::CheckButton*>("show_smart_capable_only_check")))
prefs_config_set("gui/show_smart_capable_only", bool(check->get_active()));
if ((check = this->lookup_widget<Gtk::CheckButton*>("search_in_smartmontools_first_check")))
prefs_config_set("system/win32_search_smartctl_in_smartmontools", bool(check->get_active()));
if ((entry = this->lookup_widget<Gtk::Entry*>("smartctl_binary_entry")))
prefs_config_set("system/smartctl_binary", std::string(entry->get_text()));
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
Copyright:
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
(C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_gsmartcontrol.txt
***************************************************************************/

Some files were not shown because too many files have changed in this diff Show More