mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-27 22:35:36 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d007261077 | ||
|
|
f72c332264 | ||
|
|
2ca8174054 | ||
|
|
10e4496bb7 | ||
|
|
880d876ccf | ||
|
|
2ffec89ed8 |
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2006-2008 Alexander Chemeris
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -18,8 +18,9 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
|
||||
|
||||
|
||||
All files which don't have any copyright notices, tests and examples are
|
||||
covered under the Whatever License. See LICENSE_whatever.txt for details.
|
||||
All files which don't have any copyright notices, as well as tests and
|
||||
examples are covered under the Whatever License. See LICENSE_whatever.txt for
|
||||
details.
|
||||
|
||||
|
||||
Portions of this software are copyright Google Inc. See LICENSE_pcrecpp.txt
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -26,12 +26,23 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_EXCEPTIONS],
|
||||
[AC_CACHE_CHECK(whether the compiler supports exceptions,
|
||||
ac_cv_cxx_exceptions,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[try { throw 1; } catch (int i) { return i; }]])],[ac_cv_cxx_exceptions=yes],[ac_cv_cxx_exceptions=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_exceptions" = yes; then
|
||||
AC_DEFINE(HAVE_EXCEPTIONS,,[define if the compiler supports exceptions])
|
||||
fi
|
||||
ac_cv_cxx_exceptions,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
[[try { throw 1; } catch (int i) { return i; }]])],
|
||||
[ac_cv_cxx_exceptions=yes], [ac_cv_cxx_exceptions=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
|
||||
if test "$ac_cv_cxx_exceptions" = yes; then
|
||||
AC_DEFINE(HAVE_EXCEPTIONS, 1,
|
||||
[defined to 1 if the compiler supports exceptions, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_EXCEPTIONS, 0,
|
||||
[defined to 1 if the compiler supports exceptions, 0 otherwise])
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,12 +26,22 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_NAMESPACES],
|
||||
[AC_CACHE_CHECK(whether the compiler implements namespaces,
|
||||
ac_cv_cxx_namespaces,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[namespace Outer { namespace Inner { int i = 0; }}]], [[using namespace Outer::Inner; return i;]])],[ac_cv_cxx_namespaces=yes],[ac_cv_cxx_namespaces=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_namespaces" = yes; then
|
||||
AC_DEFINE(HAVE_NAMESPACES,,[define if the compiler implements namespaces])
|
||||
fi
|
||||
ac_cv_cxx_namespaces,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[namespace Outer { namespace Inner { int i = 0; }}]],
|
||||
[[using namespace Outer::Inner; return i;]])],
|
||||
[ac_cv_cxx_namespaces=yes], [ac_cv_cxx_namespaces=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_namespaces" = yes; then
|
||||
AC_DEFINE(HAVE_NAMESPACES, 1,
|
||||
[defined to 1 if the compiler implements namespaces, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_NAMESPACES, 0,
|
||||
[defined to 1 if the compiler implements namespaces, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
+31
-21
@@ -26,25 +26,35 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_RTTI],
|
||||
[AC_CACHE_CHECK(whether the compiler supports Run-Time Type Identification,
|
||||
ac_cv_cxx_rtti,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
class Base { public :
|
||||
Base () {}
|
||||
virtual int f () { return 0; }
|
||||
};
|
||||
class Derived : public Base { public :
|
||||
Derived () {}
|
||||
virtual int f () { return 1; }
|
||||
};
|
||||
]], [[Derived d;
|
||||
Base *ptr = &d;
|
||||
return typeid (*ptr) == typeid (Derived);
|
||||
]])],[ac_cv_cxx_rtti=yes],[ac_cv_cxx_rtti=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_rtti" = yes; then
|
||||
AC_DEFINE(HAVE_RTTI,,
|
||||
[define if the compiler supports Run-Time Type Identification])
|
||||
fi
|
||||
ac_cv_cxx_rtti,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
class Base {
|
||||
public:
|
||||
Base () {}
|
||||
virtual int f () { return 0; }
|
||||
};
|
||||
class Derived : public Base {
|
||||
public :
|
||||
Derived () {}
|
||||
virtual int f () { return 1; }
|
||||
};
|
||||
]], [[
|
||||
Derived d;
|
||||
Base* ptr = &d;
|
||||
return typeid (*ptr) == typeid (Derived);
|
||||
]])],
|
||||
[ac_cv_cxx_rtti=yes], [ac_cv_cxx_rtti=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_rtti" = yes; then
|
||||
AC_DEFINE(HAVE_RTTI, 1,
|
||||
[defined to 1 if the compiler supports Run-Time Type Identification, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_RTTI, 0,
|
||||
[defined to 1 if the compiler supports Run-Time Type Identification, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,16 +25,25 @@
|
||||
|
||||
AC_DEFUN([AC_CXX_VERBOSE_TERMINATE_HANDLER],
|
||||
[AC_CACHE_CHECK(whether the compiler has __gnu_cxx::__verbose_terminate_handler,
|
||||
ac_cv_verbose_terminate_handler,
|
||||
[
|
||||
AC_REQUIRE([AC_CXX_EXCEPTIONS])
|
||||
AC_REQUIRE([AC_CXX_NAMESPACES])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <exception>]], [[std::set_terminate(__gnu_cxx::__verbose_terminate_handler);]])],[ac_cv_verbose_terminate_handler=yes],[ac_cv_verbose_terminate_handler=no
|
||||
])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_verbose_terminate_handler" = yes; then
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, , [define if the compiler has __gnu_cxx::__verbose_terminate_handler])
|
||||
fi
|
||||
ac_cv_verbose_terminate_handler,
|
||||
[
|
||||
AC_REQUIRE([AC_CXX_EXCEPTIONS])
|
||||
AC_REQUIRE([AC_CXX_NAMESPACES])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[[#include <exception>]],
|
||||
[[std::set_terminate(__gnu_cxx::__verbose_terminate_handler);]])],
|
||||
[ac_cv_verbose_terminate_handler=yes], [ac_cv_verbose_terminate_handler=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_verbose_terminate_handler" = yes; then
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, 1,
|
||||
[defined to 1 if the compiler has __gnu_cxx::__verbose_terminate_handler, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_VERBOSE_TERMINATE_HANDLER, 0,
|
||||
[defined to 1 if the compiler has __gnu_cxx::__verbose_terminate_handler, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -22,6 +22,12 @@ AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
AC_ARG_ENABLE(abort-if-no-glade-reader, AS_HELP_STRING([--disable-abort-if-no-glade-reader],
|
||||
[disable abort if no glade file reader is found (default: configure aborts when glade file reader is not found)]),
|
||||
[app_cv_abort_if_no_glade_reader=${enableval}], [app_cv_abort_if_no_glade_reader=yes])
|
||||
|
||||
AC_MSG_NOTICE([Abort if no glade file reader is found: $app_cv_abort_if_no_glade_reader])
|
||||
|
||||
# This is just in case
|
||||
# PKG_PROG_PKG_CONFIG()
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports overloading between
|
||||
# extern "C" function pointer and C++ function pointer. GCC and
|
||||
# Check whether C++ compiler supports overloading of functions
|
||||
# with function pointer argument differing only in extern "C" specification,
|
||||
# that is, extern "C" function pointer and C++ function pointer. GCC and
|
||||
# Intel treat them equally, so no overloads are needed (or accepted)
|
||||
# there.
|
||||
|
||||
@@ -21,7 +22,8 @@
|
||||
# for template parameters (I don't remember the exact details).
|
||||
|
||||
|
||||
# If such support is found, HAVE_CXX_EXTERN_C_OVERLOAD is defined.
|
||||
# If such overloading support is found,
|
||||
# HAVE_CXX_EXTERN_C_OVERLOAD is defined.
|
||||
|
||||
|
||||
AC_DEFUN([APP_CXX_EXTERN_C_OVERLOAD], [
|
||||
@@ -37,8 +39,11 @@ AC_DEFUN([APP_CXX_EXTERN_C_OVERLOAD], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$ac_cv_cxx_extern_c_overload" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, ,
|
||||
[Define if the C++ complier accepts extern C function pointer overload])
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, 1,
|
||||
[Defined to 1 if the C++ complier accepts extern C function pointer overload, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, 0,
|
||||
[Defined to 1 if the C++ complier accepts extern C function pointer overload, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports C99 __func__.
|
||||
|
||||
AC_DEFUN([APP_CXX___FUNC__], [
|
||||
AC_DEFUN([APP_CXX___func__], [
|
||||
AC_CACHE_CHECK(whether $CXX recognizes __func__, app_cv_cxx___func__, [
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
@@ -17,8 +17,11 @@ AC_DEFUN([APP_CXX___FUNC__], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___func__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___func__, ,
|
||||
[Define if the C++ complier supports __func__])
|
||||
AC_DEFINE(HAVE_CXX___func__, 1,
|
||||
[Defined to 1 if the C++ complier supports __func__, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX___func__, 0,
|
||||
[Defined to 1 if the C++ complier supports __func__, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -35,8 +38,11 @@ AC_DEFUN([APP_CXX___FUNCTION__], [
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___FUNCTION__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, ,
|
||||
[Define if the C++ complier supports __FUNCTION__])
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, 1,
|
||||
[Defined to 1 if the C++ complier supports __FUNCTION__, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, 0,
|
||||
[Defined to 1 if the C++ complier supports __FUNCTION__, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -59,12 +59,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}])
|
||||
])
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_GET_MT_FLAGS(flags_prefix[, action-if-not-found])
|
||||
# This macro detects compiler flags which are needed to compile a multi-threaded
|
||||
# (possibly pthreads-based) applications on target OS. flags_prefixCFLAGS,
|
||||
# (preferably pthreads-based) applications on target OS. flags_prefixCFLAGS,
|
||||
# flags_prefixCXXFLAGS and flags_prefixLIBS will be initialized (or appended to)
|
||||
# with the correct flags.
|
||||
|
||||
@@ -47,7 +47,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
|
||||
|
||||
# Compilers use at least 3 defines to indicate thread-safe support to standard libs:
|
||||
# Compilers use at least 3 defines to enable thread-safe support:
|
||||
# _THREAD_SAFE, _MT, _REENTRANT.
|
||||
# We use the ones that are required for detected platform.
|
||||
|
||||
@@ -63,17 +63,20 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# suncc needs -lpthread on posix but not solaris.
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
# suncc's -mt expands to:
|
||||
# "-D_REENTRANT -lpthread" on Linux, uses pthreads (pthread.h);
|
||||
# "-D_REENTRANT -lthread" on Solaris, uses Solaris threads (thread.h).
|
||||
# To use pthreads on Solaris, use "-mt -lpthread".
|
||||
# http://docs.sun.com/app/docs/doc/820-7598/bjapp?a=view
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt -lpthread"
|
||||
app_cv_target_thread_libs="-mt"
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
fi
|
||||
;;
|
||||
|
||||
windows)
|
||||
windows*)
|
||||
# NOTE: Not sure about cygwin.
|
||||
# NOTE: This only enables multithreaded code generation. For linking
|
||||
# with pthreads-win32 you need additional flags.
|
||||
@@ -87,10 +90,20 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
;;
|
||||
|
||||
freebsd | dragonfly | netbsd | openbsd)
|
||||
interix)
|
||||
# Interix kernel is implemented on top of windows kernel.
|
||||
# Interix uses -D_REENTRANT for pthreads, automatically enabling -lpthread.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-D_REENTRANT"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
freebsd | dragonfly)
|
||||
# NOTE: Not sure about debian gnu/kfreebsd and gnu/netbsd.
|
||||
# Freebsd had -kthread, but it has been discontinued (afaik).
|
||||
# For freebsd -pthread already replaces libc with libc_r.
|
||||
# For freebsd -pthread replaces libc with libc_r.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
@@ -99,22 +112,48 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
fi
|
||||
;;
|
||||
|
||||
openbsd)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
fi
|
||||
;;
|
||||
|
||||
netbsd)
|
||||
# See sys/featuretest.h
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
fi
|
||||
;;
|
||||
|
||||
solaris)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread)
|
||||
app_cv_target_thread_cflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread).
|
||||
# _REENTRANT is needed to enable some thread-safe equivalents of standard
|
||||
# functions.
|
||||
# http://docs.sun.com/app/docs/doc/805-8005-04/6j7hcvqs4?l=ko&a=view
|
||||
app_cv_target_thread_cflags="-pthreads -D_MT -D_THREAD_SAFE -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthreads -D_MT -D_THREAD_SAFE -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthreads"
|
||||
app_cv_target_thread_found="yes"
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
# suncc's -mt expands to:
|
||||
# "-D_REENTRANT -lpthread" on Linux, uses pthreads (pthread.h);
|
||||
# "-D_REENTRANT -lthread" on Solaris, uses Solaris threads (thread.h).
|
||||
# To use pthreads on Solaris, use "-mt -lpthread".
|
||||
# http://docs.sun.com/app/docs/doc/820-7598/bjapp?a=view
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/pthreads-5?a=view
|
||||
# http://docs.sun.com/app/docs/doc/816-5137/compile-74765?a=view
|
||||
# There are two threading libraries, selectable via different switches.
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt"
|
||||
# We use POSIX threads, so append -lpthread.
|
||||
app_cv_target_thread_cflags="-mt -lpthread"
|
||||
app_cv_target_thread_cxxflags="-mt -lpthread"
|
||||
app_cv_target_thread_libs="-mt -lpthread"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
@@ -122,8 +161,6 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
darwin)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# Darwin produces mt code by default, and -pthread is an error.
|
||||
# gcc/darwin defines __APPLE__. __UNIX__ is not defined.
|
||||
# -D_THREAD_SAFE
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2009 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
# Basically, it's the same as AC_USE_SYSTEM_EXTENSIONS,
|
||||
# but uses compiler flag approach instead of config.h.
|
||||
|
||||
# The extensions used bring the system closer to the GNU,
|
||||
# X/Open (a superset of POSIX) and POSIX systems.
|
||||
|
||||
# You must call AX_COMPILER_VENDOR
|
||||
# and APP_DETECT_OS_ENV([target], ...) before using this macro.
|
||||
|
||||
@@ -66,10 +69,49 @@ AC_DEFUN([APP_USE_SYSTEM_EXTENSIONS], [
|
||||
solaris)
|
||||
# The problem with solaris is that it has too many incompatible
|
||||
# feature test macros, and there is no enable-all macro. Autoconf
|
||||
# mistakenly assumes that __EXTENSIONS__ is the one, but
|
||||
# it should be defined _in addition_ to feature test macros.
|
||||
# assumes that __EXTENSIONS__ is the one, but it should be defined
|
||||
# _in addition_ to feature test macros. Note that on its own, __EXTENSIONS__
|
||||
# still enables some useful stuff like _LARGEFILE64_SOURCE.
|
||||
# To support some posix macros, additional link objects are also required.
|
||||
# Some *_SOURCE feature test macros may be incompatible with C++.
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/standards-5?a=view
|
||||
app_cv_target_extension_cflags="-D__EXTENSIONS__"
|
||||
app_cv_target_extension_cxxflags="-D__EXTENSIONS__"
|
||||
;;
|
||||
|
||||
netbsd)
|
||||
# There is no enable-all macro.
|
||||
# (_XOPEN_SOURCE >= 500 || _NETBSD_SOURCE) is recommended.
|
||||
# The default is _NETBSD_SOURCE, _XOPEN_SOURCE overrides it.
|
||||
# The manual says that rename() will behave posix-like if _POSIX_C_SOURCE
|
||||
# is defined. However, stdio.h uses (_XOPEN_SOURCE <= 2) condition,
|
||||
# which is really bogus.
|
||||
# See sys/featuretest.h
|
||||
;;
|
||||
|
||||
mingw32)
|
||||
# This enables standards-compliant stdio behaviour (regarding printf and
|
||||
# friends), as opposed to msvc-compatible one. This is usually enabled
|
||||
# by default if one of the usual macros are encountered (_XOPEN_SOURCE,
|
||||
# _GNU_SOURCE, etc...).
|
||||
# Also, we make the win2k API available (includes console functions, etc...).
|
||||
# Other things to consider: _NO_OLDNAMES (disable "deprecated"
|
||||
# non-underscored names like chdir (use _chdir), etc...).
|
||||
# See _mingw.h for details.
|
||||
app_cv_target_extension_cflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0500"
|
||||
app_cv_target_extension_cxxflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0500"
|
||||
;;
|
||||
|
||||
mingw64)
|
||||
# Same as ming32, but enable "from xp" mode, since there's no x86_64 2k.
|
||||
app_cv_target_extension_cflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0501"
|
||||
app_cv_target_extension_cxxflags="-D__USE_MINGW_ANSI_STDIO=1 -DWINVER=0x0501"
|
||||
;;
|
||||
|
||||
interix)
|
||||
# As per AC_USE_SYSTEM_EXTENSIONS.
|
||||
app_cv_target_extension_cflags="-D_ALL_SOURCE"
|
||||
app_cv_target_extension_cxxflags="-D_ALL_SOURCE"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
@@ -28,29 +28,40 @@
|
||||
|
||||
AC_DEFUN([AX_CXX_GCC_ABI_DEMANGLE],
|
||||
[AC_CACHE_CHECK(whether the compiler supports GCC C++ ABI name demangling,
|
||||
ac_cv_cxx_gcc_abi_demangle,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
ac_cv_cxx_gcc_abi_demangle,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <stdlib.h> /* not cstdlib */
|
||||
|
||||
template<typename TYPE>
|
||||
class A {};
|
||||
]], [[A<int> instance;
|
||||
int status = 0;
|
||||
char* c_name = 0;
|
||||
template<typename TYPE>
|
||||
class A {};
|
||||
]], [[
|
||||
A<int> instance;
|
||||
int status = 0;
|
||||
char* c_name = 0;
|
||||
|
||||
c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status);
|
||||
c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status);
|
||||
|
||||
std::string name(c_name);
|
||||
free(c_name);
|
||||
std::string name(c_name);
|
||||
free(c_name); /* not std::free() */
|
||||
|
||||
return name == "A<int>";
|
||||
]])],[ac_cv_cxx_gcc_abi_demangle=yes],[ac_cv_cxx_gcc_abi_demangle=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_gcc_abi_demangle" = yes; then
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE,1,
|
||||
[define if the compiler supports GCC C++ ABI name demangling])
|
||||
fi
|
||||
return name == "A<int>";
|
||||
]])],
|
||||
[ac_cv_cxx_gcc_abi_demangle=yes], [ac_cv_cxx_gcc_abi_demangle=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_gcc_abi_demangle" = yes; then
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE, 1,
|
||||
[defined to 1 if the compiler supports GCC C++ ABI name demangling, 0 otherwise])
|
||||
else
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE, 0,
|
||||
[defined to 1 if the compiler supports GCC C++ ABI name demangling, 0 otherwise])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+83
-27
@@ -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" \
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
This directory contains scripts and an example crontab to allow GSmartControl
|
||||
to read smartctl data from cron-generated files. This allows users to read
|
||||
somewhat recent smartctl information without having to run GSmartControl as
|
||||
root.
|
||||
|
||||
Put the scripts into /usr/local/bin, run GSmartControl and set smartctl path
|
||||
to "/usr/local/bin/smartctl_subst.sh" (without quotes). An example crontab
|
||||
runs cron_gather_smart.sh script every 10 minutes, storing its output to
|
||||
"/var/run/smart-$devname". The smartctl_subst.sh script prints the contents of
|
||||
this file instead of running smartctl, thus eliminating the need to run
|
||||
GSmartControl as root when reading SMART values.
|
||||
|
||||
Note: These scripts provide read-only capabilities only, they don't allow
|
||||
changing SMART settings or running self-tests.
|
||||
|
||||
Contributed by Alex Butcher <alex dot butcher 'at' assursys.co.uk>.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 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
|
||||
Executable
+27
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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 |
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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="/opt/cross-tools/bin:/target/bin:$PATH"</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="" PATH="/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH"</configargs>
|
||||
<builddir>win32</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
@@ -119,8 +119,8 @@
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>i386-mingw32msvc-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-mingw32msvc-g++</cxxcompilerbinary>
|
||||
<ccompilerbinary>i386-pc-mingw32-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-pc-mingw32-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
@@ -128,21 +128,21 @@
|
||||
</win32>
|
||||
<suncc>
|
||||
<envvars>
|
||||
<envvar value="/opt/sun/sunstudio12/bin:$PATH" name="PATH" />
|
||||
<envvar value="/opt/sun/sunstudio/bin:$PATH" name="PATH" />
|
||||
</envvars>
|
||||
<configargs>--enable-tests</configargs>
|
||||
<configargs>--enable-tests PKG_CONFIG_PATH="/opt/sun/target64/lib64/pkgconfig:/usr/lib64/pkgconfig" PKG_CONFIG_LIBDIR=""</configargs>
|
||||
<builddir>suncc</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags>-s</ldflags>
|
||||
<ldflags>-R/opt/sun/target64/lib64 -L/opt/sun/target64/lib64</ldflags>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>suncc</ccompilerbinary>
|
||||
<cxxcompilerbinary>sunCC</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags>-errwarn=%all</cflags>
|
||||
<cxxflags>-DGLIBMM_HAVE_SUN_REVERSE_ITERATOR -DSIGC_HAVE_SUN_REVERSE_ITERATOR</cxxflags>
|
||||
<cflags>-errwarn=%all -I/opt/sun/target64/include</cflags>
|
||||
<cxxflags>-I/opt/sun/target64/include</cxxflags>
|
||||
<f77flags/>
|
||||
</suncc>
|
||||
<portland>
|
||||
@@ -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="/opt/cross-tools/bin:/target/bin:$PATH"</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="" PATH="/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH"</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="" PATH="/cross/w64/gcc-bin:/cross/w64/target/bin:$PATH"</configargs>
|
||||
<builddir>win64-debug</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>x86_64-pc-mingw32-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>x86_64-pc-mingw32-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</win64-debug>
|
||||
</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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,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,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,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,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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,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
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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_, µsec);
|
||||
}
|
||||
|
||||
|
||||
// don't return sigc::connection - it's better for thread-safety this way.
|
||||
// this will disconnect earlier slots. Call before execute().
|
||||
void set_exit_status_translator(exit_status_translator_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
translator_func_ = func;
|
||||
translator_func_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: The callback will be called in non-main thread! (the call is enclosed
|
||||
// in lock/unlock).
|
||||
// Don't use this unless absolutely necessary, use stopped_cleanup_needed()
|
||||
// polling instead.
|
||||
// You can use stopped_cleanup_needed() polling instead.
|
||||
void set_exited_callback(exited_callback_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
exited_callback_ = func;
|
||||
exited_callback_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// use lock() / unlock() if using members of this class outside of it.
|
||||
|
||||
void lock()
|
||||
{
|
||||
errors_lock(); // defer to parent's mutex - we use it for the whole object.
|
||||
}
|
||||
|
||||
|
||||
void unlock()
|
||||
{
|
||||
errors_unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// protect all member variable access by this mutex, as well as
|
||||
// serialize event callback execution (in respect of main thread too).
|
||||
// it's possible to implement mutexes for each member individually, but
|
||||
// it's impractical.
|
||||
// mutable allows the definition of const member functions - they only
|
||||
// read the data, but do it in a lock-protected manner.
|
||||
// mutable Glib::Mutex object_mutex; // aka access serializer mutex
|
||||
// use ErrorHolder's mutex
|
||||
|
||||
|
||||
|
||||
|
||||
// these are sorta-private
|
||||
|
||||
// for passing to callback
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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,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,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,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,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,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,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.)));
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,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,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
@@ -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.
|
||||
|
||||
@@ -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,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
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
|
||||
@@ -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,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,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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
};
|
||||
|
||||
|
||||
@@ -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>";
|
||||
}
|
||||
|
||||
@@ -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,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,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,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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,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,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,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,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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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
Reference in New Issue
Block a user