Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
168aeec882 | ||
|
|
afdb516386 | ||
|
|
9a1f28fe9a | ||
|
|
b4583a7cc6 | ||
|
|
9918b13214 | ||
|
|
3f9d830294 | ||
|
|
7b2627b236 | ||
|
|
c40d87b3ae | ||
|
|
99f707b6c6 | ||
|
|
a561d5fef6 | ||
|
|
1d305e7626 | ||
|
|
194fb51f75 | ||
|
|
e2dc39bff2 | ||
|
|
836aa73430 | ||
|
|
63f5b885a3 | ||
|
|
c68d017475 | ||
|
|
bbe3bac923 | ||
|
|
2293e357f4 | ||
|
|
85dbceb14d | ||
|
|
45cba39be7 | ||
|
|
a0b235dd8a | ||
|
|
7e3db9ec30 | ||
|
|
6cc8770599 | ||
|
|
462d465f3a | ||
|
|
6ac62cd0de | ||
|
|
1174b62b8f | ||
|
|
ef713900a0 | ||
|
|
c60f6815fa | ||
|
|
7ca709fcbb | ||
|
|
c3ce878376 | ||
|
|
a06ac42eff | ||
|
|
444eb6c211 | ||
|
|
eb6cbe1ee0 | ||
|
|
bcae9a2c37 | ||
|
|
d411b34dae | ||
|
|
a0fad4375a | ||
|
|
ffb02984fe | ||
|
|
b400df2565 | ||
|
|
b06607cc37 | ||
|
|
8881f42470 | ||
|
|
6558d31680 | ||
|
|
6e949677ec | ||
|
|
72f2d166b6 | ||
|
|
7b13cdf7b3 | ||
|
|
c7bdaad30a | ||
|
|
fd9fce25fc | ||
|
|
5ba7add5b5 | ||
|
|
68889d3804 | ||
|
|
8ab18d433a | ||
|
|
13d83949c4 | ||
|
|
daf98009d4 | ||
|
|
0cf5848772 | ||
|
|
0ecc4bd8d3 | ||
|
|
388a195794 | ||
|
|
0f89010225 | ||
|
|
42da49c5c1 | ||
|
|
0ffba26b1f | ||
|
|
b19b094aaa | ||
|
|
5cc1e898b9 | ||
|
|
a4aa68a085 |
@@ -68,7 +68,7 @@ src-rpm: dist
|
||||
|
||||
|
||||
# NSIS installer support.
|
||||
# Requires wine, installed NSIS, smartctl-nc.exe, smartctl.exe.
|
||||
# Requires wine, installed NSIS, smartctl-nc.exe, smartctl.exe, update-smart-drivedb.exe.
|
||||
# Gtkmm dlls and pcre dlls are required if linking against them.
|
||||
# dos2unix on build machine.
|
||||
# Execute only with win32 build present.
|
||||
@@ -91,6 +91,8 @@ win-dist-clean: win-dist-cleanup
|
||||
win-dist-prepare-all: nsis-dist-prepare win-zip-dist-prepare
|
||||
|
||||
|
||||
# Don't strip smartctl (it will only change the header), and
|
||||
# don't strip update-smart-drivedb (it will break its CRC check).
|
||||
win-dist-prepare: all
|
||||
$(MKDIR_P) win-dist
|
||||
cp $(top_srcdir)/data/icon_*.png win-dist/
|
||||
@@ -100,13 +102,13 @@ win-dist-prepare: all
|
||||
cp $(top_srcdir)/AUTHORS.txt $(top_srcdir)/LICENSE_* $(top_srcdir)/README.txt win-dist/doc/
|
||||
cp $(top_srcdir)/NEWS win-dist/doc/NEWS.txt
|
||||
|
||||
cp "@WINDOWS_BINDIR@"/smartctl-nc.exe win-dist/
|
||||
cp "@WINDOWS_BINDIR@"/smartctl.exe win-dist/
|
||||
|
||||
cp src/gsmartcontrol.exe src/gsmartcontrol.exe.manifest win-dist/
|
||||
|
||||
unix2dos win-dist/doc/*.txt
|
||||
$(STRIP) win-dist/*.exe
|
||||
|
||||
cp -p "@WINDOWS_BINDIR@"/smartctl-nc.exe win-dist/
|
||||
cp -p "@WINDOWS_BINDIR@"/smartctl.exe win-dist/
|
||||
cp -p "@WINDOWS_BINDIR@"/update-smart-drivedb.exe win-dist/
|
||||
|
||||
|
||||
nsis-dist-prepare: win-dist-prepare
|
||||
@@ -1,5 +1,53 @@
|
||||
|
||||
Version 0.8.6, released on 2011-05-29
|
||||
Version 0.9.0, released on 2017-05-11
|
||||
Implemented (untested) support for Linux-based Areca controllers with
|
||||
enclosures.
|
||||
Implemented (untested) support for Windows-based Areca controllers (thanks
|
||||
to Richard Kagerer).
|
||||
Implemented (untested) support for Linux-based HP controllers with cciss
|
||||
and hpsa/hpahcisr drivers (thanks to Fabrice Bacchella).
|
||||
Changes in Preferences no longer fail silently until rescan/restart.
|
||||
Better drive detection under Windows after removable drives are detached.
|
||||
Windows version is no longer marked as "dpi aware" since it's not
|
||||
supported that well.
|
||||
Drive attribute descriptions have been updated (including clarifications
|
||||
for SSDs).
|
||||
Added support for SSD-only and HDD-only vendor attributes.
|
||||
Devices having only basic info can be displayed now in the info window.
|
||||
Fixed BDRW drive detection (it was detected as a HDD).
|
||||
Other minor improvements.
|
||||
A number of issues have been fixed (including a crash).
|
||||
|
||||
Version 0.8.7, released on 2012-08-11
|
||||
Implemented support for Adaptec RAID 5805 controller and possibly other
|
||||
Adaptec models as well (Linux).
|
||||
Implemented support for Areca RAID controller detection under Linux
|
||||
(untested).
|
||||
Implemented support for 3ware 3w-sas-supported (twl) RAID controller
|
||||
detection under Linux (untested).
|
||||
Implemented support for systems with several different 3ware controllers
|
||||
(twa/twe/twl).
|
||||
Fixed invalid parsing of tw_cli output which caused non-detection of
|
||||
drives and controllers with controller or port numbers greater than 9
|
||||
if tw_cli was found (3ware linux, windows).
|
||||
The duplicate drives are no longer shown for some Intel matrix controllers
|
||||
under Windows; Intel RAID controllers are fully supported under
|
||||
Windows now.
|
||||
Added options to show device name and serial number under drive icons.
|
||||
Updated SMART attribute definitions and added warnings for SSD lifetime
|
||||
attributes.
|
||||
gsmartcontrol-root has a new argument "--desktop=..." which replaces the
|
||||
old positional argument; compatibility with the old invocation syntax
|
||||
has been retained.
|
||||
Completely documented the source using doxygen tags.
|
||||
Added support for Fedora's consolehelper.
|
||||
Made GSmartControl DPI-aware under Windows.
|
||||
Fixed compilation issues with clang and gcc 4.7, as well as glib 2.31.x
|
||||
and newer.
|
||||
Fixed minor issues in NSIS installer.
|
||||
Fixed other minor bugs and made minor improvements.
|
||||
|
||||
Version 0.8.6, released on 2011-06-12
|
||||
Support detecting drives behind 3ware controllers (Linux, Windows),
|
||||
including tw_cli/cx/px mode in Windows. Having tw_cli is recommended
|
||||
but not required.
|
||||
@@ -1,19 +1,20 @@
|
||||
|
||||
About GSmartControl
|
||||
|
||||
GSmartControl - Hard disk drive health inspection tool.
|
||||
GSmartControl - Hard disk drive and SSD 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.
|
||||
Technology) data on modern hard disk and solid-state drives. It allows you to
|
||||
inspect the drive's SMART data to determine its health, as well as run various
|
||||
tests on it.
|
||||
|
||||
Note: GSmartControl supports ATA drives (both PATA and SATA), various USB to
|
||||
ATA bridges and drives behind 3ware RAID controllers.
|
||||
ATA bridges and drives behind some RAID controllers (selected models of
|
||||
3ware, Areca, Adaptec, Intel RAID controllers).
|
||||
|
||||
http://gsmartcontrol.berlios.de
|
||||
http://gsmartcontrol.sourceforge.net
|
||||
|
||||
|
||||
|
||||
@@ -51,15 +52,15 @@ methods to predict certain kinds of failures with certain chance of success.
|
||||
Long answer: read below.
|
||||
|
||||
Self-Monitoring, Analysis, and Reporting Technology, or SMART, is a
|
||||
monitoring system for hard drives to detect and report various indicators of
|
||||
reliability, in the hope of anticipating failures. It is implemented inside
|
||||
the drives SMART provides several ways of monitoring hard drive health. It
|
||||
may provide information about general health, various drive attributes (for
|
||||
example, number of unreadable sectors), error logs, and so on. It may also
|
||||
provide ways to instruct the drive to run various self-tests, which may report
|
||||
valuable information. It may even automatically scan the disk surface in when
|
||||
the drive is idle, and repair the defects, reallocating the data to more safe
|
||||
areas.
|
||||
monitoring system for hard drives and SSDs to detect and report various
|
||||
indicators of reliability, in the hope of anticipating failures. SMART is
|
||||
implemented inside the drives, providing several ways of monitoring the drive
|
||||
health. It may present information about general health, various drive
|
||||
attributes (for example, number of unreadable sectors), error logs, and so on.
|
||||
It may also provide ways to instruct the drive to run various self-tests,
|
||||
which may report valuable information. It may even automatically scan the disk
|
||||
surface in when the drive is idle, repairing the defects while reallocating
|
||||
the data to more safe areas.
|
||||
|
||||
While having SMART sounds really good, there are some nuances to consider. One
|
||||
of the common pitfalls is that it may create a false sense of security. That
|
||||
@@ -75,15 +76,15 @@ necessarily agree on precise attribute definitions and measurement units, the
|
||||
exact meaning of the attributes may vary greatly across different drive
|
||||
models.
|
||||
|
||||
At present SMART is implemented individually by manufacturers, and while some
|
||||
At present SMART is implemented individually by manufacturers. While some
|
||||
aspects are standardized for compatibility, others are not. In fact, most
|
||||
manufacturers refer the users to their own health monitoring utilities, and
|
||||
manufacturers refer the users to their own health monitoring utilities and
|
||||
advice against taking SMART data seriously. Nevertheless, SMART may prove an
|
||||
effective measure against data loss.
|
||||
|
||||
Yet another issue is that quite often the drives have bugs which prevent
|
||||
correct SMART usage. This is usually due to buggy firmware, or the
|
||||
manufacturer ignoring the standard. Luckily, smartmontools usually detects
|
||||
manufacturer ignoring the standards. Luckily, smartmontools usually detects
|
||||
these bugs and works around them.
|
||||
|
||||
|
||||
@@ -101,7 +102,7 @@ You need to have the following software installed:
|
||||
* Gtkmm, version 2.6 or higher - see http://www.gtkmm.org .
|
||||
|
||||
* libglademm, version 2.4 or higher - see http://www.gtkmm.org .
|
||||
Note: libglademm is not needed when using GTK / Gtkmm 2.12 or newer.
|
||||
Note: libglademm is not needed when using GTK+ / Gtkmm 2.12 or newer.
|
||||
|
||||
Note that having GTK+ 2.12 and Gtkmm 2.12 is HIGHLY recommended. While earlier
|
||||
versions may work, they may produce suboptimal results and buggy behavior.
|
||||
@@ -131,7 +132,6 @@ Note: If using the official Windows package, the requirements are listed on
|
||||
GSmartControl's website.
|
||||
|
||||
|
||||
|
||||
The following operating systems are supported:
|
||||
|
||||
* Linux - All the popular configurations should work.
|
||||
@@ -148,11 +148,9 @@ 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: 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.
|
||||
not been tested yet.
|
||||
|
||||
* Mac OS X - 3rd-party testing by Fink project.
|
||||
* Mac OS X - 3rd-party testing by the MacPorts and Fink projects.
|
||||
|
||||
* DragonFlyBSD - Code written but no testing has been performed yet. Expected
|
||||
to work without any issues.
|
||||
@@ -189,6 +187,18 @@ directly from the build directory.
|
||||
|
||||
|
||||
|
||||
Smartctl Options
|
||||
|
||||
GSmartControl tries its best to guard the user from having to specify smartctl
|
||||
options. However, this is not always possible due to drive firmware bugs,
|
||||
unimplemented features, and so on. The smartctl manual page contains all the
|
||||
information you may need when dealing with smartctl.
|
||||
See http://smartmontools.sourceforge.net/man/smartctl.8.html
|
||||
|
||||
Additional information is available at http://smartmontools.sourceforge.net
|
||||
|
||||
|
||||
|
||||
Command Line Options
|
||||
|
||||
GSmartControl inherits options from GTK+ and other libraries, so be sure to
|
||||
@@ -202,22 +212,24 @@ The most important parameters are:
|
||||
|
||||
-?, --help - Show help options.
|
||||
|
||||
-V, --version - Display version information.
|
||||
-l, --no-locale - Don't use system locale.
|
||||
|
||||
-l, --no-locale - Disable locale.
|
||||
-V, --version - Display version information.
|
||||
|
||||
--no-scan - Don't scan devices on startup.
|
||||
|
||||
--no-hide-tabs - Don't hide non-identity tabs when SMART is disabled.
|
||||
--no-hide-tabs - Don't hide non-identity tabs when SMART is disabled. Useful
|
||||
for debugging.
|
||||
|
||||
--add-virtual - Load smartctl data from file, creating a virtual drive.
|
||||
--add-virtual - Load smartctl data from file, creating a virtual drive. You
|
||||
can specify this option multiple times.
|
||||
|
||||
--add-device - Add this device to device list. The format of the device is
|
||||
"<device>::<type>::<extra_args>", where type and extra_args are optional.
|
||||
This option is useful with --no-scan to list certain drives only. You can
|
||||
specify this option multiple times.
|
||||
Example: --add-device /dev/sda --add-device /dev/twa0::3ware,2
|
||||
--add-device '/dev/sdb::::-T permissive'
|
||||
"<device>::<type>::<extra_args>", where type and extra_args are optional. This
|
||||
option is useful with --no-scan to list certain drives only. You can specify
|
||||
this option multiple times.
|
||||
Example: --add-device /dev/sda --add-device /dev/twa0::3ware,2 --add-device
|
||||
'/dev/sdb::::-T permissive'.
|
||||
|
||||
-v, --verbose - Enable verbose logging; same as --verbosity-level 5.
|
||||
|
||||
@@ -286,7 +298,7 @@ For more information, see smartctl and smartd documentation.
|
||||
Known Issues
|
||||
|
||||
Only ATA drives (both PATA and SATA), various USB to ATA bridges and drives
|
||||
behind 3ware RAID controllers are supported for now. The main reasons are:
|
||||
behind some RAID controllers are supported for now. The main reasons are:
|
||||
|
||||
* We can't support drives which don't work with smartmontools. This affects
|
||||
drives which don't support SMART or don't export SMART data correctly (e.g.
|
||||
@@ -296,7 +308,7 @@ some USB enclosures, RAIDs, etc...).
|
||||
Also, SCSI drives are rarely found in desktop systems and the servers rarely
|
||||
have X11 / Gtkmm running, so this is a low priority task.
|
||||
|
||||
* I only have ATA drives, so testing would be almost impossible.
|
||||
* I only have ATA drives, so testing anything else is very difficult.
|
||||
|
||||
Immediate Offline Tests are not supported. I haven't found a way to reliably
|
||||
monitor them yet. Besides, they run automatically anyway if Automatic Offline
|
||||
@@ -20,26 +20,63 @@ with existing model, which should be unset.
|
||||
|
||||
|
||||
Bugs / patches:
|
||||
|
||||
Patch pangomm for Pango::strip_markup().
|
||||
|
||||
+ gtkmm bug: No Gtk::AboutDialog::set_logo(NULL);
|
||||
|
||||
+ Gtk::Main m(argc, argv, false);
|
||||
If gtk_get_option_group() and g_option_context_parse() were used before,
|
||||
this generates a warning:
|
||||
(gsmartcontrol:28241): Gtk-WARNING **: gtk_disable_setlocale() must be called before gtk_init()
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
TODO:
|
||||
|
||||
Don't rely on smartctl return code (2), parse the output instead.
|
||||
This will allow us to show the Info page.
|
||||
|
||||
test, release RC version for testing.
|
||||
Update to drivedb.h from 5.41, include 5.41 into release.
|
||||
?Fix not being able to quit while executing commands.
|
||||
Cannot reproduce.
|
||||
https://www.google.com/search?client=opera&q=IA__gtk_main_quit:+assertion+%60main_loops+!=+NULL'+failed&sourceid=opera&ie=utf-8&oe=utf-8&channel=suggest
|
||||
https://developer.gnome.org/gtk2/2.24/gtk2-General.html#gtk-main-quit
|
||||
https://www.google.com/search?num=50&hl=en&safe=off&client=opera&hs=Dr5&channel=suggest&q=calling+gtk_main_quit+during+gtk_main_iteration+warning&oq=calling+gtk_main_quit+during+gtk_main_iteration+warning&gs_l=serp.12...7064.8155.0.12753.8.8.0.0.0.0.216.935.0j6j1.7.0.les%3B..0.0...1c.1.4.serp.GUiDL5IM2U8
|
||||
https://developer.gnome.org/glib/2.34/glib-The-Main-Event-Loop.html#g-main-loop-quit
|
||||
|
||||
Port to GTK2 with disable-deprecated flags, then GTK3.
|
||||
Drop support for old distros.
|
||||
|
||||
|
||||
In main window add multi-selection support and right-click menu with various
|
||||
tests, so that it's possible to run multiple tests in parallel from there.
|
||||
|
||||
|
||||
Areca detection
|
||||
Linux:
|
||||
Somehow differentiate between the cards with expanders (-d areca,N/E) and without (-d areca,N).
|
||||
The expander ones seem to have "ix" (case-insensitive) as their name suffixes.
|
||||
areca,N - N is [1,24].
|
||||
areca,N/E - N is [1,128], E is [1,8].
|
||||
We should limit these using some config key (36 for N and 4 for E seems ok).
|
||||
N/E syntax is since smartmontools 5.43.
|
||||
For older versions we get: /dev/<something>: Option -d areca,N requires N to be a non-negative integer
|
||||
Windows Detection:
|
||||
Credit Richard Kagerer.
|
||||
|
||||
|
||||
Credit Fabrice Bacchella for Linux CCISS detection.
|
||||
|
||||
|
||||
|
||||
|
||||
Add ability (through ctrl-C?) to copy individual rows from attributes page,
|
||||
in tab-separated format (for easy pasting into libreoffice).
|
||||
|
||||
|
||||
Investiage the new "-l ssd" and "-l devstat" options (since 5.42)
|
||||
|
||||
Check also other options in 5.42 and 5.43.
|
||||
"-g all" looks promising alongside -i (shows APM and other stuff as well).
|
||||
|
||||
Add --identify option to context menu, for convenience.
|
||||
|
||||
Add menu item - "update drive database" (not sure about linux, should
|
||||
check if it's supported first; also need to run it in terminal).
|
||||
|
||||
|
||||
Testing:
|
||||
@@ -51,13 +88,19 @@ Testing:
|
||||
may be stuck due to bad firmware, e.g. 3ware/windows).
|
||||
|
||||
|
||||
Add support for launching with consolehelper (from usermode package).
|
||||
Fedora uses this by default.
|
||||
Investigate Fedora selinux situation.
|
||||
usermode-gtk contains consolehelper-gtk, not sure about our package
|
||||
requirement. consolehelper-gtk is not supposed to be launched by user,
|
||||
but I think we can check it with "which".
|
||||
http://fedoranews.org/contributors/matt_hansen/nautilus/
|
||||
|
||||
48-bit ATA command support:
|
||||
'-l xerror' -> Extended Comprehensive Error log: An multi-sector and
|
||||
LBA48 capable version of '-l error'. Output is similar, except more
|
||||
entries can exists and the high bytes of the registers are also printed.
|
||||
Some newer drives (Samsung) only write to this log.
|
||||
|
||||
'-l xselftest' -> Extended Self Test Log: An multi-sector and LBA48
|
||||
capable version of '-l selftest'. Output will be similar, except more
|
||||
entries can exists and the LBA values can be somewhat longer.
|
||||
|
||||
"smartctl -l this_wont_exist" gives the list of supported logs - this
|
||||
is needed to detect xerror / xselftest support in smartctl.
|
||||
|
||||
|
||||
Rework drive properties UI:
|
||||
@@ -92,6 +135,12 @@ Monitor:
|
||||
Periodically see if drives were added / removed (possibly use OS callbacks
|
||||
instead of polling?)
|
||||
|
||||
Win7 widget:
|
||||
Can be done in html/js.
|
||||
Shows temperature
|
||||
Detects drives
|
||||
Opens GSmartControl
|
||||
|
||||
If a drive is not recognized, suggest using -d (sat, sat,12, ...)
|
||||
Refer the user to
|
||||
http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_USB-Devices
|
||||
@@ -101,21 +150,11 @@ If a drive is not recognized, suggest using -d (sat, sat,12, ...)
|
||||
RAID:
|
||||
http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_RAID-Controllers
|
||||
|
||||
Areca Linux:
|
||||
Call as: smartctl -i -d areca,[1-24] /dev/sg0
|
||||
Detection:
|
||||
Check if /proc/scsi/sg/device_strs contains "Areca RAID controller".
|
||||
If not, there's no Areca controller present.
|
||||
Check /proc/scsi/sg/devices, the line # with type 3 is the sg* number.
|
||||
The "host" field value is the N value in /sys, see below.
|
||||
Check /sys/bus/scsi/devices/hostN/scsi_host/hostN/host_fw_hd_channels, set
|
||||
its contents as the number of ports. If not present, use 24.
|
||||
Probe each port for a valid drive: If the output contains "Device Read Identity Failed",
|
||||
then there is no drive on that port (or Areca has an old firmware, nothing we can
|
||||
do there).
|
||||
Notification: If /sys/bus/scsi/devices/hostN/scsi_host/hostN/host_fw_version
|
||||
is older than "V1.46 2009-01-06", notify the user (maybe its better to grep
|
||||
the smartctl output for that on port 0?).
|
||||
Areca Windows:
|
||||
Detection not supported by smartctl --scan-open.
|
||||
|
||||
Areca FreeBSD: since 5.42.
|
||||
Call as: smartctl -a -d areca,[1-24] /dev/arcmsr1
|
||||
|
||||
3ware FreeBSD:
|
||||
Call as: smartctl -i -d 3ware,[0-127] /dev/twa0 (or twe0)
|
||||
@@ -142,21 +181,6 @@ RAID:
|
||||
Detection: unknown.
|
||||
TODO: Analyze sent info.
|
||||
|
||||
CCISS (HP (Compaq) Smart Array Controller) Linux:
|
||||
Call as: smartctl -a -d cciss,[0-127] /dev/cciss/c0d0
|
||||
c0d0 is the controller (d0 seems to be a logical drive, doesn't matter?).
|
||||
/dev/cciss/c0d0p1 is the first ordinary partition (used in mount, etc...).
|
||||
The port limit had a brief regression in 5.39.x (limited to 15).
|
||||
5.39 doesn't seem to work at all (prereleases work with P400 controller)?
|
||||
Possibly a 64-bit-only issue?
|
||||
To detect controller presence: cat /proc/devices, contains "cciss0"
|
||||
for controller 0.
|
||||
There is a cciss_vol_status utility but it doesn't report anything except "OK" status.
|
||||
It may not return the "SMART Health Status: OK" line in smartctl -i for some reason?
|
||||
(It returns it in -a though, and in some freebsd output I found).
|
||||
If no /dev/cciss exists, you may need to run "cd /dev; ./MAKEDEV cciss".
|
||||
Smartctl SVN has some /dev/sg* stuff, check it out.
|
||||
|
||||
CCISS (HP (Compaq) Smart Array Controller) FreeBSD:
|
||||
Seems to be the same as Linux (uses the same driver?).
|
||||
Detection: unknown.
|
||||
@@ -172,20 +196,6 @@ libdebug:
|
||||
use format_time() instead of ctime() and friends, with ISO formatting.
|
||||
|
||||
|
||||
48-bit ATA command support:
|
||||
'-l xerror' -> Extended Comprehensive Error log: An multi-sector and
|
||||
LBA48 capable version of '-l error'. Output is similar, except more
|
||||
entries can exists and the high bytes of the registers are also printed.
|
||||
Some newer drives (Samsung) only write to this log.
|
||||
|
||||
'-l xselftest' -> Extended Self Test Log: An multi-sector and LBA48
|
||||
capable version of '-l selftest'. Output will be similar, except more
|
||||
entries can exists and the LBA values can be somewhat longer.
|
||||
|
||||
"smartctl -l this_wont_exist" gives the list of supported logs - this
|
||||
is needed to detect xerror / xselftest support in smartctl.
|
||||
|
||||
|
||||
|
||||
'-l sataphy' -> SATA Phy event counters: Non-SMART feature, useful to detect SATA cabling problems.
|
||||
|
||||
@@ -30,7 +30,7 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# ---- Common compiler options (warnings, etc...)
|
||||
|
||||
AC_ARG_ENABLE(common-options, AS_HELP_STRING([--enable-common-options=<compiler>|auto|none],
|
||||
[enable useful compilation options (warnings, mostly). Accepted values are auto, none, gnu, intel, sun. (Default: auto)]),
|
||||
[enable useful compilation options (warnings, mostly). Accepted values are auto, none, gnu, clang, intel, sun. (Default: auto)]),
|
||||
[app_cv_compiler_common_options=${enableval}], [app_cv_compiler_common_options=auto])
|
||||
|
||||
# the default value is "yes" (if no value given after =), treat it as auto.
|
||||
@@ -47,8 +47,8 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
|
||||
if test "x$app_cv_compiler_common_options" != "xnone"; then
|
||||
|
||||
# gcc / gnu environment, mingw, cygwin.
|
||||
if test "x$app_cv_compiler_common_options" = "xgnu"; then
|
||||
# gcc (or clang) / gnu environment, mingw, cygwin.
|
||||
if test "x$app_cv_compiler_common_options" = "xgnu" || test "x$app_cv_compiler_common_options" = "xclang"; 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
|
||||
@@ -63,6 +63,10 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
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";
|
||||
if test "x$app_cv_compiler_common_options" = "xclang"; then
|
||||
# these are really annoying
|
||||
app_cv_compiler_tmp_var="$app_cv_compiler_tmp_var -Wno-sign-conversion -Wno-format-security"
|
||||
fi
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags $app_cv_compiler_tmp_var";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags $app_cv_compiler_tmp_var";
|
||||
|
||||
@@ -102,7 +106,7 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# ---- Compiler options for debug builds
|
||||
|
||||
AC_ARG_ENABLE(debug-options, AS_HELP_STRING([--enable-debug-options=<compiler>|auto|none],
|
||||
[enable debug build options. Accepted values are auto, none, gnu, intel, sun. (Default: none)]),
|
||||
[enable debug build options. Accepted values are auto, none, gnu, clang, intel, sun. (Default: none)]),
|
||||
[app_cv_compiler_debug_options=${enableval}], [app_cv_compiler_debug_options=none])
|
||||
|
||||
# the default value is "yes" (if no value given after =), treat it as auto.
|
||||
@@ -124,7 +128,7 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
AC_DEFINE([DEBUG_BUILD], [1], [Defined for debug builds])
|
||||
|
||||
# gcc, mingw
|
||||
if test "x$app_cv_compiler_debug_options" = "xgnu"; then
|
||||
if test "x$app_cv_compiler_debug_options" = "xgnu" || test "x$app_cv_compiler_debug_options" = "xclang"; then
|
||||
# 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";
|
||||
@@ -154,7 +158,7 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# ---- Compiler options for optimized builds
|
||||
|
||||
AC_ARG_ENABLE(optimize-options, AS_HELP_STRING([--enable-optimize-options=<compiler>|auto|none],
|
||||
[enable optimized build options. Accepted values are auto, none, gnu, intel, sun. (Default: none)]),
|
||||
[enable optimized build options. Accepted values are auto, none, gnu, clang, intel, sun. (Default: none)]),
|
||||
[app_cv_compiler_optimize_options=${enableval}], [app_cv_compiler_optimize_options=none])
|
||||
|
||||
# the default value is "yes" (if no value given after =), treat it as auto.
|
||||
@@ -172,7 +176,7 @@ AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
if test "x$app_cv_compiler_optimize_options" != "xnone"; then
|
||||
|
||||
# gcc, mingw
|
||||
if test "x$app_cv_compiler_optimize_options" = "xgnu"; then
|
||||
if test "x$app_cv_compiler_optimize_options" = "xgnu" || test "x$app_cv_compiler_optimize_options" = "xclang"; then
|
||||
# -mtune=generic is since gcc 4.0 iirc
|
||||
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";
|
||||
@@ -55,8 +55,8 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
linux)
|
||||
# glibc manual says that defining either _REENTRANT or _THREAD_SAFE
|
||||
# enables some thread-safe implementations of glibc functions.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel" \
|
||||
|| test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang" \
|
||||
|| test "$ax_cv_cxx_compiler_vendor" = "intel" || test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
@@ -77,12 +77,12 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
;;
|
||||
|
||||
windows*)
|
||||
# NOTE: Not sure about cygwin.
|
||||
# NOTE: Not sure about cygwin or clang.
|
||||
# NOTE: This only enables multithreaded code generation. For linking
|
||||
# with pthreads-win32 you need additional flags.
|
||||
# gcc man page: -mthreads: Support thread-safe exception handling on Mingw32.
|
||||
# -mthreads defines -D_MT, and links with -lmingwthrd.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
app_cv_target_thread_cflags="-mthreads -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-mthreads -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-mthreads"
|
||||
@@ -104,7 +104,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
# NOTE: Not sure about debian gnu/kfreebsd and gnu/netbsd.
|
||||
# Freebsd had -kthread, but it has been discontinued (afaik).
|
||||
# For freebsd -pthread replaces libc with libc_r.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
@@ -113,7 +113,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
;;
|
||||
|
||||
openbsd)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
@@ -123,7 +123,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
|
||||
netbsd)
|
||||
# See sys/featuretest.h
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_REENTRANT"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
@@ -132,7 +132,7 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
;;
|
||||
|
||||
solaris)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread).
|
||||
# _REENTRANT is needed to enable some thread-safe equivalents of standard
|
||||
# functions.
|
||||
@@ -159,14 +159,14 @@ AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
;;
|
||||
|
||||
darwin)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
# Darwin produces mt code by default, and -pthread is an error.
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
qnx)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang"; then
|
||||
# afaik, gcc/qnx produces mt code by default (at least on newer qnx releases),
|
||||
# so no flags are needed.
|
||||
app_cv_target_thread_found="yes"
|
||||
@@ -53,7 +53,7 @@ AC_DEFUN([AX_COMPILER_VENDOR],
|
||||
AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
|
||||
[ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
|
||||
# note: don't check for gcc first since some other compilers define __GNUC__
|
||||
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
|
||||
for ventest in clang:__clang__ intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
|
||||
vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
|
||||
#if !($vencpp)
|
||||
@@ -8,7 +8,7 @@ configure_script="$2";
|
||||
if [ "$type" == "" ]; then
|
||||
echo "Usage: $0 <type> [<configure_script>]"
|
||||
echo "where <type> is one of:"
|
||||
echo "debug optimized icc win32 win32-debug win64-debug sun portland open64";
|
||||
echo "debug optimized icc clang win32 win32-debug win64-debug sun portland open64";
|
||||
echo "<configure_script> is ../configure by default"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -25,13 +25,16 @@ case $type in
|
||||
flags="--disable-user-flags --enable-optimize-options --enable-tests" ;;
|
||||
debug)
|
||||
flags="--enable-debug-options --enable-tests" ;;
|
||||
clang)
|
||||
flags="CC=clang CXX=clang++ --enable-debug-options --enable-tests" ;;
|
||||
icc)
|
||||
flags="CC=icc64 CXX=icpc64 --disable-user-flags --enable-tests" ;;
|
||||
win32)
|
||||
flags="CC=i386-pc-mingw32-gcc CXX=i386-pc-mingw32-g++ \
|
||||
PKG_CONFIG_PATH=/cross/w32/target/lib/pkgconfig PKG_CONFIG_LIBDIR=\"\" \
|
||||
PATH=\"/cross/w32/gcc-bin:/cross/w32/target/bin:$PATH\" \
|
||||
--with-windows-gtk-name=gtk2-runtime-2.16.6-2010-05-12-ash --disable-user-flags \
|
||||
--with-windows-gtk-name=gtk2-runtime-2.24.10-2012-10-10-ash --disable-user-flags \
|
||||
--with-nsis=/root/.wine/drive_c/Programs_x86/NSIS/makensis.exe \
|
||||
--enable-optimize-options --enable-tests --build=i686-linux --host=i386-pc-mingw32" ;;
|
||||
win32-debug)
|
||||
flags="CC=i386-pc-mingw32-gcc CXX=i386-pc-mingw32-g++ \
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
AC_INIT([GSmartControl],[0.8.6],[],[gsmartcontrol])
|
||||
AC_INIT([GSmartControl],[0.9.0],[],[gsmartcontrol])
|
||||
|
||||
AC_CONFIG_SRCDIR([configure.ac])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -454,7 +454,8 @@ ADDITIONAL_INCLUDES="-I\$(top_builddir) -I\$(top_srcdir)/src -I\$(top_srcdir)/sr
|
||||
# (e.g. gccfss (gcc frontend / sun backend), etc...).
|
||||
# We use -include only when using pch.
|
||||
if test "x$app_cv_compiler_gcc_pch" = "xyes"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel" || test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "clang" \
|
||||
|| test "$ax_cv_cxx_compiler_vendor" = "intel" || test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
# This auto-includes this file when compiling any file. Benefits include pch support.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -include global_macros.h"
|
||||
fi
|
||||
@@ -528,7 +529,7 @@ AC_SUBST(AUTODIRS)
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
AC_CONFIG_FILES([ data/gsmartcontrol.desktop \
|
||||
AC_CONFIG_FILES([ data/gsmartcontrol.desktop data/gsmartcontrol.appdata.xml \
|
||||
data/nsis/distribution.txt data/nsis/distribution-nogtk.txt data/nsis/gsmartcontrol.nsi \
|
||||
debian.dist/changelog \
|
||||
src/gsc_winres.rc src/gsmartcontrol.exe.manifest \
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
@@ -40,6 +40,10 @@ appdata_DATA = icon_cddvd.png icon_hdd.png
|
||||
desktopdir = $(datadir)/applications
|
||||
desktop_DATA = gsmartcontrol.desktop
|
||||
|
||||
# Appdata files
|
||||
metainfodir = $(datadir)/metainfo
|
||||
metainfo_DATA = gsmartcontrol.appdata.xml
|
||||
|
||||
|
||||
# Application pixmap (fallback icon for desktop files).
|
||||
# Same as 48/gsmartcontrol.png.
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2014 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -11,18 +11,43 @@
|
||||
EXEC_BIN="@prefix@/bin/gsmartcontrol";
|
||||
prog_name="gsmartcontrol"
|
||||
|
||||
DESKTOP="$1";
|
||||
|
||||
# This works for --help too
|
||||
if [ "$DESKTOP" = "" ]; then
|
||||
DESKTOP="auto"; # default
|
||||
# Preserve quotes in arguments
|
||||
final_args_quoted="";
|
||||
for i in "$@";do
|
||||
final_args_quoted="$final_args_quoted \"${i//\"/\\\"}\"";
|
||||
done;
|
||||
|
||||
elif [ "$DESKTOP" != "auto" ] && [ "$DESKTOP" != "kde" ] && \
|
||||
|
||||
DESKTOP="auto";
|
||||
|
||||
# Compatibility with old syntax:
|
||||
# gsmartcontrol-root [<desktop> [program_options]]
|
||||
if [ "$1" == "auto" ] || [ "$1" == "kde" ] || [ "$1" == "gnome" ] || [ "$1" == "other" ]; then
|
||||
DESKTOP="$1";
|
||||
shift; # remove $1
|
||||
else
|
||||
# New syntax:
|
||||
# gsmartcontrol-root [--desktop=<auto|kde|gnome|other>] [program_options]
|
||||
|
||||
for arg in $*; do
|
||||
case $arg in
|
||||
--desktop=*)
|
||||
DESKTOP="${arg#*=}";
|
||||
final_args_quoted="${final_args_quoted/\"$arg\"/}";
|
||||
;;
|
||||
*)
|
||||
# unknown option
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$DESKTOP" != "auto" ] && [ "$DESKTOP" != "kde" ] && \
|
||||
[ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
|
||||
echo "Usage: $0 [<auto|kde|gnome|other> [<${prog_name}_options>] ]";
|
||||
echo "Usage: $0 [--desktop=<auto|kde|gnome|other>] [<${prog_name}_options>]";
|
||||
exit 1;
|
||||
fi
|
||||
shift; # remove $1
|
||||
|
||||
|
||||
# Auto-detect current desktop if auto was specified.
|
||||
@@ -42,6 +67,9 @@ fi
|
||||
# echo $DESKTOP;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# They're basically the same, only the order is different.
|
||||
# sux requires xterm to ask for the password.
|
||||
# xdg-su is basically like this script, except worse :)
|
||||
@@ -86,9 +114,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).
|
||||
# Add @prefix@/sbin as well (freebsd seems to require it).
|
||||
# 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";
|
||||
EXTRA_PATHS="/usr/bin:/usr/sbin:/usr/local/sbin:@prefix@/sbin";
|
||||
export PATH="$EXTRA_PATHS:$PATH"
|
||||
|
||||
|
||||
@@ -101,29 +130,30 @@ export PATH="$EXTRA_PATHS:$PATH"
|
||||
# su-to-root -X -c 'gsmartcontrol --no-scan'
|
||||
# xterm -e sux -c 'gsmartcontrol --no-scan' # sux asks for password in a terminal
|
||||
|
||||
|
||||
full_cmd="";
|
||||
|
||||
if [ "$GSMARTCONTROL_SU" != "" ]; then
|
||||
full_cmd="$GSMARTCONTROL_SU '$EXEC_BIN $@'";
|
||||
full_cmd="$GSMARTCONTROL_SU '$EXEC_BIN $final_args_quoted'";
|
||||
|
||||
elif [ "$found_su" = "sux" ]; then
|
||||
full_cmd="xterm -e sux -c '$EXEC_BIN $@'";
|
||||
full_cmd="xterm -e sux -c '$EXEC_BIN $final_args_quoted'";
|
||||
|
||||
elif [ "$found_su" = "gksu" ]; then
|
||||
full_cmd="$found_su '$EXEC_BIN $@'";
|
||||
full_cmd="$found_su '$EXEC_BIN $final_args_quoted'";
|
||||
|
||||
elif [ "$found_su" = "beesu" ]; then
|
||||
full_cmd="$found_su -P '$EXEC_BIN $@'";
|
||||
full_cmd="$found_su -P '$EXEC_BIN $final_args_quoted'";
|
||||
|
||||
elif [ "$found_su" = "su-to-root" ]; then
|
||||
full_cmd="$found_su -X -c '$EXEC_BIN $@'";
|
||||
full_cmd="$found_su -X -c '$EXEC_BIN $final_args_quoted'";
|
||||
|
||||
else # gnomesu, kdesu, xdg-su
|
||||
full_cmd="$found_su -c '$EXEC_BIN $@'";
|
||||
full_cmd="$found_su -c '$EXEC_BIN $final_args_quoted'";
|
||||
fi
|
||||
|
||||
|
||||
#echo $full_cmd
|
||||
# echo $full_cmd
|
||||
eval $full_cmd
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.TH GSmartControl "1" "" "gsmartcontrol " "User Commands"
|
||||
.SH NAME
|
||||
GSmartControl \- Hard disk drive health inspection tool
|
||||
GSmartControl \- Hard disk drive and SSD health inspection tool
|
||||
.SH SYNOPSIS
|
||||
\fBgsmartcontrol\fP [OPTIONS]
|
||||
|
||||
\fBgsmartcontrol\-root\fP [\fI<desktop>\fP [OPTIONS]]
|
||||
\fBgsmartcontrol\-root\fP [--desktop=\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.
|
||||
and solid-state 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.
|
||||
@@ -37,7 +37,7 @@ Show logging options
|
||||
.SS "Application Options:"
|
||||
.TP
|
||||
\fB\-l\fP, \fB\-\-no\-locale\fP
|
||||
Disable locale
|
||||
Don't use system locale
|
||||
.TP
|
||||
\fB\-V\fP, \fB\-\-version\fP
|
||||
Display version information
|
||||
@@ -49,10 +49,17 @@ Don't scan devices on startup
|
||||
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
|
||||
Load smartctl data from file, creating a virtual drive. You
|
||||
can specify this option multiple times.
|
||||
.TP
|
||||
\fB\-\-add\-device\fP
|
||||
Add this device to device list. Useful with \fB\-\-no\-scan\fP to list certain drives only.
|
||||
Add this device to device list. The format of the device is
|
||||
\fI<device>::<type>::<extra_args>\fP, where type and extra_args are optional.
|
||||
This option is useful with \fB\-\-no\-scan\fP to list certain drives only. You
|
||||
can specify this option multiple times. Example:\fR
|
||||
.nf
|
||||
\-\-add\-device /dev/sda \-\-add\-device /dev/twa0::3ware,2 \-\-add\-device '/dev/sdb::::-T permissive'
|
||||
.fi
|
||||
.TP
|
||||
\fB\-\-display\fP=\fIDISPLAY\fP
|
||||
X display to use
|
||||
@@ -67,8 +74,8 @@ Disable logging; same as \fB\-\-verbosity\-level\fP 0
|
||||
Set verbosity level [0\-5]
|
||||
.PP
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2008 \- 2009 Alexander Shaduri <ashaduri \'at\' gmail.com>
|
||||
Copyright \(co 2008 \- 2012 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.
|
||||
<giuseppe@iuculano.it> for the Debian project.
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2017 GSmartControl developers -->
|
||||
<component type="desktop">
|
||||
<id>gsmartcontrol</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0 and GPL-3.0</project_license>
|
||||
<name>GSmartControl</name>
|
||||
<summary>Hard Disk and SSD Health Inspection</summary>
|
||||
<description>
|
||||
<p>
|
||||
GSmartControl is a graphical user interface for smartctl, which is a tool for
|
||||
querying and controlling SMART (Self-Monitoring, Analysis, and Reporting
|
||||
Technology) data in hard disk and solid-state drives. It allows you to inspect
|
||||
the drive's SMART data to determine its health, as well as run various tests
|
||||
on it.
|
||||
</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">gsmartcontrol.desktop</launchable>
|
||||
<url type="homepage">http://gsmartcontrol.sourceforge.net</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Main window</caption>
|
||||
<image>http://gsmartcontrol.sourceforge.net/home/images/main_ok.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Drive identity information</caption>
|
||||
<image>http://gsmartcontrol.sourceforge.net/home/images/info_identity.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Attribute list of a failing drive</caption>
|
||||
<image>http://gsmartcontrol.sourceforge.net/home/images/info_failing.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
</component>
|
||||
@@ -8,9 +8,9 @@ Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
GenericName=Hard Disk Health Inspection
|
||||
GenericName=Hard Disk and SSD Health Inspection
|
||||
# tooltip
|
||||
Comment=Monitor and control SMART data on hard disks
|
||||
Comment=Monitor and control SMART data on hard disk and solid-state drives
|
||||
|
||||
# If it's a name only, it looks for "name.[png|xpm]" file in
|
||||
# $XDG_DATA_DIRS/icons and /usr/share/pixmaps.
|
||||
@@ -24,6 +24,3 @@ Icon=gsmartcontrol
|
||||
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol-root"
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@@ -1,12 +1,12 @@
|
||||
|
||||
GSmartControl - Hard disk drive health inspection tool
|
||||
GSmartControl - Hard disk drive and SSD health inspection tool
|
||||
Version @VERSION@
|
||||
|
||||
The latest version of this distribution, as well as the source code of
|
||||
GSmartControl, can be found at
|
||||
http://gsmartcontrol.berlios.de
|
||||
http://gsmartcontrol.sourceforge.net
|
||||
and
|
||||
http://developer.berlios.de/project/showfiles.php?group_id=10075
|
||||
https://sourceforge.net/projects/gsmartcontrol/files/
|
||||
|
||||
You need GTK+ for Windows Runtime package to use this program. You can get one
|
||||
at http://gtk-win.sf.net (you must download at least version 2.16.6-2010-02-21
|
||||
@@ -20,9 +20,9 @@ binary was compiled for 32-bit Windows, and should work on both 32-bit and
|
||||
64-bit Windows. The binary was statically compiled against Gtkmm
|
||||
(http://www.gtkmm.org/) and related libraries, and PCRE (http://www.pcre.org/).
|
||||
|
||||
* Smartctl binaries (from smartmontools 5.41, http://smartmontools.sf.net/)
|
||||
* Smartctl binaries (from smartmontools 6.5, http://smartmontools.sf.net/)
|
||||
- smartctl-nc.exe (compiled without console output), smartctl.exe (compiled
|
||||
with console output).
|
||||
with console output), update-smart-drivedb.exe (drive database updater).
|
||||
|
||||
|
||||
The combined distribution is multi-licensed under GNU GPL versions 2 and 3.
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
GSmartControl - Hard disk drive health inspection tool
|
||||
GSmartControl - Hard disk drive and SSD health inspection tool
|
||||
Version @VERSION@
|
||||
|
||||
The latest version of this distribution, as well as the source code of
|
||||
GSmartControl, can be found at
|
||||
http://gsmartcontrol.berlios.de
|
||||
http://gsmartcontrol.sourceforge.net
|
||||
and
|
||||
http://developer.berlios.de/project/showfiles.php?group_id=10075
|
||||
https://sourceforge.net/projects/gsmartcontrol/files/
|
||||
|
||||
|
||||
This distribution includes:
|
||||
@@ -16,9 +16,9 @@ binary was compiled for 32-bit Windows, and should work on both 32-bit and
|
||||
64-bit Windows. The binary was statically compiled against Gtkmm
|
||||
(http://www.gtkmm.org/) and related libraries, and PCRE (http://www.pcre.org/).
|
||||
|
||||
* Smartctl binaries (from smartmontools 5.41, http://smartmontools.sf.net/)
|
||||
* Smartctl binaries (from smartmontools 6.5, http://smartmontools.sf.net/)
|
||||
- smartctl-nc.exe (compiled without console output), smartctl.exe (compiled
|
||||
with console output).
|
||||
with console output), update-smart-drivedb.exe (drive database updater).
|
||||
|
||||
* GTK+ for Windows Runtime package (@GTK_INSTALLER_NAME@)
|
||||
from http://gtk-win.sf.net, either in original or unpacked form.
|
||||
@@ -13,7 +13,7 @@
|
||||
!define PRODUCT_NAME "GSmartControl"
|
||||
!define PRODUCT_NAME_SMALL "gsmartcontrol"
|
||||
!define PRODUCT_PUBLISHER "Alexander Shaduri"
|
||||
!define PRODUCT_WEB_SITE "http://gsmartcontrol.berlios.de"
|
||||
!define PRODUCT_WEB_SITE "http://gsmartcontrol.sourceforge.net"
|
||||
|
||||
;!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\AppMainExe.exe"
|
||||
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
@@ -158,6 +158,7 @@ SectionIn 1 RO
|
||||
; File *.dll
|
||||
File smartctl-nc.exe
|
||||
File smartctl.exe
|
||||
File update-smart-drivedb.exe
|
||||
|
||||
; Include the "doc" directory completely, excluding the file we're not using (e.g. the -nogtk file in gtk installer).
|
||||
!ifdef NO_GTK
|
||||
@@ -168,7 +169,7 @@ SectionIn 1 RO
|
||||
|
||||
; Add Shortcuts (this inherits the exe's run permissions)
|
||||
CreateShortCut "$SMPROGRAMS\GSmartControl.lnk" "$INSTDIR\gsmartcontrol.exe" "" \
|
||||
"$INSTDIR\gsmartcontrol.ico" "" SW_SHOWNORMAL "" "GSmartControl - Hard disk drive health inspection tool"
|
||||
"$INSTDIR\gsmartcontrol.ico" "" SW_SHOWNORMAL "" "GSmartControl - Hard disk drive and SSD health inspection tool"
|
||||
|
||||
SectionEnd
|
||||
|
||||
@@ -300,7 +301,7 @@ FunctionEnd
|
||||
; Section descriptions
|
||||
!ifndef NO_GTK ; this page is shown only when using gtk
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecMain} "GSmartControl - hard disk drive health inspection tool"
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecMain} "GSmartControl - hard disk drive and SSD health inspection tool"
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecGtkPrivate} "GTK+ libraries, needed by GSmartControl. \
|
||||
This will install a private version of GTK+, usable only by GSmartControl."
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecGtkPublic} "GTK+ libraries, needed by GSmartControl. \
|
||||
@@ -400,15 +401,29 @@ Section Uninstall
|
||||
; Delete "$INSTDIR\*.dll"
|
||||
Delete "$INSTDIR\smartctl-nc.exe"
|
||||
Delete "$INSTDIR\smartctl.exe"
|
||||
Delete "$INSTDIR\update-smart-drivedb.exe"
|
||||
|
||||
; update-smart-drivedb may leave these
|
||||
Delete "$INSTDIR\drivedb.h"
|
||||
Delete "$INSTDIR\drivedb.h.new"
|
||||
Delete "$INSTDIR\drivedb.h.old"
|
||||
Delete "$INSTDIR\drivedb.h.error"
|
||||
Delete "$INSTDIR\drivedb.h.lastcheck"
|
||||
|
||||
RMDir /r "$INSTDIR\doc"
|
||||
|
||||
; leftover from gtk
|
||||
RMDir /r "$INSTDIR\share"
|
||||
|
||||
; clean up generated stuff
|
||||
Delete "$INSTDIR\*stdout.txt"
|
||||
Delete "$INSTDIR\*stderr.txt"
|
||||
|
||||
RMDir "$INSTDIR" ; only if empty
|
||||
|
||||
; For some reason, sometimes it's not deleted in the sections, so do it here.
|
||||
Delete "$INSTDIR\${GTK_INSTALLER_EXE}"
|
||||
|
||||
!ifndef NO_GTK
|
||||
StrCmp $gtk_mode "private" skip_exe_PATH_remove
|
||||
!endif
|
||||
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
@@ -1,21 +1,21 @@
|
||||
Source: gsmartcontrol
|
||||
Section: utils
|
||||
Priority: extra
|
||||
Homepage: http://gsmartcontrol.berlios.de/
|
||||
Homepage: http://gsmartcontrol.sourceforge.net/
|
||||
Maintainer: Alexander Shaduri <ashaduriREMOVETHIS@gmail.com>
|
||||
# technically, we don't need libglademm if gtkmm >= 2.12, but it won't get
|
||||
# into Depends if it's not needed, so let's leave it here.
|
||||
# libglademm is also needed if libgtkmm-2.4 < 2.12, but don't write it
|
||||
# here - newer distributions don't contain it.
|
||||
Build-Depends: debhelper (>= 5), autotools-dev,
|
||||
libpcre3-dev, libgtkmm-2.4-dev (>= 2.6.0), libglademm-2.4-dev
|
||||
libpcre3-dev, libgtkmm-2.4-dev (>= 2.6.0)
|
||||
Standards-Version: 3.7.3
|
||||
|
||||
Package: gsmartcontrol
|
||||
Architecture: any
|
||||
#Depends: ${shlibs:Depends}, ${misc:Depends}, smartmontools, menu
|
||||
Depends: ${shlibs:Depends}, smartmontools, menu
|
||||
Description: Hard disk drive health inspection tool
|
||||
Description: Hard disk drive and SSD health inspection tool
|
||||
GSmartControl is a graphical user interface for smartctl (from smartmontools
|
||||
package), which is a tool for querying and controlling SMART
|
||||
(Self-Monitoring, Analysis, and Reporting Technology) data on modern hard
|
||||
disk drives. It allows you to inspect the drive's SMART data to determine its
|
||||
health, as well as run various tests on it.
|
||||
disk and solid-state drives. It allows you to inspect the drive's SMART data
|
||||
to determine its health, as well as run various tests on it.
|
||||
@@ -1,11 +1,11 @@
|
||||
This package was debianized by Alexander Shaduri <ashaduri 'at' gmail.com> on
|
||||
Sat, 15 Nov 2008 00:12:04 +0400.
|
||||
|
||||
It was downloaded from <http://gsmartcontrol.berlios.de/>
|
||||
It was downloaded from <http://gsmartcontrol.sourceforge.net/>
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Copyright (C) 2008 - 2012 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 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com> and
|
||||
The Debian packaging is (C) 2008 - 2012 Alexander Shaduri <ashaduri 'at' gmail.com> and
|
||||
is licensed under the GPLv2 and GPLv3, see above.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
?package(gsmartcontrol):needs="X11" section="Applications/System/Hardware"\
|
||||
title="GSmartControl" command="/usr/bin/gsmartcontrol-root"\
|
||||
longtitle="Hard Disk Health Inspection"\
|
||||
longtitle="Hard Disk and SSD Health Inspection"\
|
||||
icon="/usr/share/pixmaps/gsmartcontrol.xpm"
|
||||
@@ -0,0 +1,35 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2012 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
// This file is for generating documentation only. Do NOT include it.
|
||||
/// \file
|
||||
/// \author Alexander Shaduri
|
||||
|
||||
/**
|
||||
\mainpage GSmartControl Index
|
||||
|
||||
|
||||
\section intro_section Introduction
|
||||
This is GSmartControl internal documentation.
|
||||
*/
|
||||
|
||||
// Group definitions and titles.
|
||||
|
||||
/**
|
||||
\addtogroup applib Application-Specific Components
|
||||
\addtogroup applib_tests Tests of Application-Specific Components
|
||||
\addtogroup hz HZ Common System Components
|
||||
\addtogroup hz_tests Tests for HZ Common System Components
|
||||
\addtogroup libdebug LibDebug Flexible Debug Logging
|
||||
\addtogroup libdebug_tests Tests for LibDebug Flexible Debug Logging
|
||||
\addtogroup rmn Resource Manager
|
||||
\addtogroup rmn_tests Tests for Resource Manager
|
||||
\addtogroup rconfig Resource Manager-Based Configuration
|
||||
\addtogroup rconfig_tests Tests for Resource Manager-Based Configuration
|
||||
\addtogroup gsc GSmartControl Application
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 - 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# (C) 2008 - 2012 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Name: gsmartcontrol
|
||||
Version: @VERSION@
|
||||
Release: 1as
|
||||
License: GPLv2, GPLv3
|
||||
Url: http://gsmartcontrol.berlios.de
|
||||
License: GPL-2.0 AND GPL-3.0
|
||||
Url: http://gsmartcontrol.sourceforge.net
|
||||
Vendor: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Packager: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# Packager: Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
Source: gsmartcontrol-%{version}.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
Summary: GSmartControl - Hard Disk Health Inspection Tool
|
||||
Summary: GSmartControl - Hard Disk Drive and SSD Health Inspection Tool
|
||||
|
||||
%if 0%{?mandriva_version}
|
||||
Group: System/Kernel and hardware
|
||||
@@ -15,12 +15,6 @@ Group: System/Kernel and hardware
|
||||
Group: Hardware/Other
|
||||
%endif
|
||||
|
||||
# Support build service rpmlint. Disabled - the build service
|
||||
# stopped recognizing the flag for some architectures.
|
||||
# %if 0%{?opensuse_bs} && 0%{?suse_version} >= 1010
|
||||
# Support: rpmlint-bs
|
||||
# %endif
|
||||
|
||||
|
||||
# Dependencies for various distributions. The actual deps are:
|
||||
# smartmontools, pcre, (gtkmm2 >= 2.12 || (gtkmm2 >= 2.6.0 && libglademm >= 2.4.0))
|
||||
@@ -46,6 +40,11 @@ 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
|
||||
BuildRequires: update-desktop-files
|
||||
|
||||
%if 0%{?suse_version} >= 1030
|
||||
BuildRequires: fdupes
|
||||
%endif
|
||||
|
||||
%endif
|
||||
|
||||
@@ -62,10 +61,10 @@ Requires: smartmontools, pcre, gtkmm24 >= 2.6.0, libglademm24 >= 2.4.0
|
||||
BuildRequires: gcc-c++, pcre-devel, gtkmm24-devel >= 2.6.0, libglademm24-devel >= 2.4.0
|
||||
%endif
|
||||
|
||||
# Fedora doesn't include gnomesu or anything similar except beesu (since 11), so force it.
|
||||
# usermode-gtk is for consolehelper-gtk (optional for beesu, needed for GUI auth).
|
||||
%if 0%{?fedora_version} >= 11
|
||||
Requires: beesu, usermode-gtk
|
||||
# Fedora with consolehelper.
|
||||
# usermode-gtk is for consolehelper-gtk.
|
||||
%if 0%{?fedora_version}
|
||||
Requires: usermode-gtk
|
||||
%endif
|
||||
|
||||
%endif
|
||||
@@ -89,8 +88,9 @@ BuildRequires: gcc-c++, gcc-cpp, pcre-devel, gtkmm2.4-devel >= 2.6.0, libglademm
|
||||
%description
|
||||
GSmartControl is a graphical user interface for smartctl, which is a tool for
|
||||
querying and controlling SMART (Self-Monitoring, Analysis, and Reporting
|
||||
Technology) data in 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.
|
||||
Technology) data in hard disk and solid-state drives. It allows you to inspect
|
||||
the drive's SMART data to determine its health, as well as run various tests
|
||||
on it.
|
||||
|
||||
%prep
|
||||
|
||||
@@ -104,21 +104,80 @@ SMART data to determine its health, as well as run various tests on it.
|
||||
|
||||
%build
|
||||
# Set up for parallel builds
|
||||
numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :`
|
||||
if [ "$numprocs" = "0" ]; then
|
||||
numprocs=1
|
||||
fi
|
||||
|
||||
make -j$numprocs
|
||||
# make
|
||||
#numprocs=`grep -E -c ^cpu[0-9]+ /proc/stat || :`
|
||||
#if [ "$numprocs" = "0" ]; then
|
||||
# numprocs=1
|
||||
#fi
|
||||
#make -j$numprocs
|
||||
make %{?_smp_mflags}
|
||||
|
||||
|
||||
%install
|
||||
# %makeinstall
|
||||
|
||||
# %%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%{?suse_version}
|
||||
%suse_update_desktop_file -n %{name}
|
||||
|
||||
|
||||
# There are some png file duplicates, hardlink them.
|
||||
%if 0%{?suse_version} >= 1030
|
||||
%fdupes
|
||||
%endif
|
||||
|
||||
|
||||
# We install icons, so this is needed.
|
||||
%if 0%{?suse_version} >= 1140
|
||||
%post
|
||||
%icon_theme_cache_post
|
||||
|
||||
%postun
|
||||
%icon_theme_cache_postun
|
||||
%endif
|
||||
|
||||
# endif suse
|
||||
%endif
|
||||
|
||||
|
||||
%if 0%{?fedora_version}
|
||||
# We still retain gsmartcontrol-root for consistency with other distributions.
|
||||
|
||||
# Make the desktop file run gsmartcontrol instead of gsmartcontrol-root
|
||||
sed "s|gsmartcontrol-root|gsmartcontrol|g" %{buildroot}%{_datadir}/applications/gsmartcontrol.desktop > %{buildroot}%{_datadir}/applications/gsmartcontrol.desktop.new
|
||||
mv -f %{buildroot}%{_datadir}/applications/gsmartcontrol.desktop.new %{buildroot}%{_datadir}/applications/gsmartcontrol.desktop
|
||||
|
||||
# The rest is taken from the official fedora spec:
|
||||
# http://pkgs.fedoraproject.org/cgit/gsmartcontrol.git/tree/
|
||||
|
||||
# Set up for console-helper
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
# Add a copy as "gsmartcontrol-noroot", since gsmartcontrol will always
|
||||
# ask for root password.
|
||||
cp %{buildroot}%{_bindir}/%{name} %{buildroot}%{_bindir}/%{name}-noroot
|
||||
mv %{buildroot}%{_bindir}/%{name} %{buildroot}%{_sbindir}/%{name}
|
||||
ln -s consolehelper %{buildroot}%{_bindir}/%{name}
|
||||
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/pam.d
|
||||
cat <<EOF >%{buildroot}%{_sysconfdir}/pam.d/%{name}
|
||||
#%%PAM-1.0
|
||||
auth include config-util
|
||||
account include config-util
|
||||
session include config-util
|
||||
EOF
|
||||
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/security/console.apps
|
||||
cat <<EOF >%{buildroot}%{_sysconfdir}/security/console.apps/%{name}
|
||||
USER=root
|
||||
PROGRAM=/usr/sbin/gsmartcontrol
|
||||
SESSION=true
|
||||
EOF
|
||||
|
||||
# endif fedora
|
||||
%endif
|
||||
|
||||
|
||||
%if 0%{?mandriva_version}
|
||||
desktop-file-install --vendor="" \
|
||||
@@ -137,29 +196,23 @@ rm -rf %buildroot
|
||||
%defattr(-,root,root)
|
||||
|
||||
%attr(0755,root,root) %{_bindir}/*
|
||||
# %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/*
|
||||
# %%attr(0644,root,root) %%config(noreplace) %%{_sysconfdir}/*
|
||||
|
||||
%doc %{_datadir}/doc/gsmartcontrol
|
||||
%doc %{_mandir}/man1/*
|
||||
|
||||
%{_datadir}/gsmartcontrol
|
||||
# %{_datadir}/gsmartcontrol/*
|
||||
# %%{_datadir}/gsmartcontrol/*
|
||||
%{_datadir}/applications/*.desktop
|
||||
%{_datadir}/metainfo
|
||||
%{_datadir}/metainfo/*.appdata.xml
|
||||
%{_datadir}/icons/*
|
||||
%{_datadir}/pixmaps/*
|
||||
|
||||
|
||||
%if 0%{?fedora_version}
|
||||
%config(noreplace) %{_sysconfdir}/pam.d/%{name}
|
||||
%config(noreplace) %{_sysconfdir}/security/console.apps/%{name}
|
||||
%{_sbindir}/gsmartcontrol
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Dec 10 2010 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Fixes for Fedora 14.
|
||||
|
||||
* Fri Nov 14 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Updated .spec file to incorporate changes from the official Mandriva package.
|
||||
|
||||
* Mon Oct 06 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Updated .spec file to support OpenSUSE < 10.3, Fedora and friends,
|
||||
Mandriva (for OpenSUSE Build Service).
|
||||
|
||||
* Mon Sep 15 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
- Initial .spec file.
|
||||
@@ -1,97 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_GTKMM_UTILS_H
|
||||
#define APP_GTKMM_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <gtkmm/widget.h>
|
||||
#include <gtkmm/treeviewcolumn.h>
|
||||
#include <gtkmm/treemodelcolumn.h>
|
||||
#include <gtkmm/treeview.h>
|
||||
#include <gtkmm/combobox.h>
|
||||
#include <gtkmm/cellrenderertext.h>
|
||||
#include <gtkmm/iconview.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/icontheme.h> // must include (even if gtkmm.h is included) for older gtkmm (at least 2.6, but not 2.12)
|
||||
|
||||
#include "hz/down_cast.h"
|
||||
|
||||
|
||||
|
||||
// Note: This works only if the column has custom widget set.
|
||||
Gtk::Widget* app_gtkmm_get_column_header(Gtk::TreeViewColumn& column);
|
||||
|
||||
|
||||
// Read column header text and create a label with that text, set it as column's custom widget.
|
||||
Gtk::Widget* app_gtkmm_labelize_column(Gtk::TreeViewColumn& column);
|
||||
|
||||
|
||||
// unset model on treeview, cross-gtkmm-version.
|
||||
void app_gtkmm_treeview_unset_model(Gtk::TreeView* treeview);
|
||||
|
||||
|
||||
// unset model on combobox (there's no straight way to do it in gtkmm, I think)
|
||||
void app_gtkmm_combobox_unset_model(Gtk::ComboBox* box);
|
||||
|
||||
|
||||
// A wrapper around set_tooltip_*() for portability across different gtkmm versions.
|
||||
void app_gtkmm_set_widget_tooltip(Gtk::Widget& widget,
|
||||
const Glib::ustring& tooltip_text, bool use_markup = false);
|
||||
|
||||
|
||||
// A portable wrapper around TreeView::set_tooltip_column().
|
||||
void gtkmm_set_treeview_tooltip_column(Gtk::TreeView* treeview,
|
||||
Gtk::TreeModelColumn<Glib::ustring>& col_tooltip);
|
||||
|
||||
// A portable wrapper around IconView::set_tooltip_column().
|
||||
void gtkmm_set_iconview_tooltip_column(Gtk::IconView* iconview,
|
||||
Gtk::TreeModelColumn<Glib::ustring>& col_tooltip, Glib::RefPtr<Gtk::ListStore> model);
|
||||
|
||||
|
||||
|
||||
// Convenience function for creating a TreeViewColumn .
|
||||
template<typename T> inline
|
||||
int app_gtkmm_create_tree_view_column(Gtk::TreeModelColumn<T>& mcol, Gtk::TreeView& treeview,
|
||||
const Glib::ustring& title, const Glib::ustring& tooltip_text, bool sortable = false, bool cell_markup = false)
|
||||
{
|
||||
int num_tree_cols = treeview.append_column(title, mcol);
|
||||
Gtk::TreeViewColumn* tcol = treeview.get_column(num_tree_cols - 1);
|
||||
if (tcol) {
|
||||
if (sortable)
|
||||
tcol->set_sort_column(mcol);
|
||||
|
||||
app_gtkmm_labelize_column(*tcol);
|
||||
tcol->set_reorderable(true);
|
||||
tcol->set_resizable(true);
|
||||
}
|
||||
|
||||
Gtk::Widget* header = app_gtkmm_get_column_header(*tcol);
|
||||
if (header)
|
||||
app_gtkmm_set_widget_tooltip(*header, tooltip_text);
|
||||
|
||||
if (cell_markup) {
|
||||
Gtk::CellRendererText* cr_type = hz::down_cast<Gtk::CellRendererText*>(treeview.get_column_cell_renderer(num_tree_cols - 1));
|
||||
if (cr_type) { // may not be true if it's not Text (unless static_cast is used, in which case we're screwed)
|
||||
treeview.get_column(num_tree_cols - 1)->clear_attributes(*cr_type); // clear "text" attribute. "markup" won't work without this.
|
||||
treeview.get_column(num_tree_cols - 1)->add_attribute(cr_type->property_markup(), mcol); // render col_type as markup.
|
||||
}
|
||||
}
|
||||
|
||||
return num_tree_cols;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool app_gtkmm_icon_theme_has_icon(Glib::RefPtr<Gtk::IconTheme> theme,
|
||||
const Glib::ustring& icon_name, int size);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,312 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_CMDEX_H
|
||||
#define APP_CMDEX_H
|
||||
|
||||
#include <string>
|
||||
#include <glib.h>
|
||||
|
||||
#include "hz/process_signal.h" // hz::SIGNAL_*
|
||||
#include "hz/error_holder.h"
|
||||
#include "hz/sync.h" // hz::SyncPolicyNone
|
||||
|
||||
|
||||
|
||||
/*
|
||||
There are two ways to detect when the command exits:
|
||||
|
||||
1. Add a callback to signal_exited.
|
||||
|
||||
2. Manually poll stopped_cleanup_needed() (from the same 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::SyncPolicyNone> {
|
||||
|
||||
public:
|
||||
|
||||
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*);
|
||||
|
||||
|
||||
Cmdex(
|
||||
// exit_status_translator_func_t translator_func,
|
||||
exited_callback_func_t exited_cb = NULL, void* exited_cb_data = NULL
|
||||
)
|
||||
: 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),
|
||||
translator_func_(0), translator_func_data_(0),
|
||||
exited_callback_(exited_cb), exited_callback_data_(exited_cb_data)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
// Please don't destroy this object unless the child has exited. It will leak stuff
|
||||
// and possibly crash, etc... .
|
||||
~Cmdex()
|
||||
{
|
||||
// This will help if object is destroyed after the command has exited, but before
|
||||
// stopped_cleanup() has been called.
|
||||
stopped_cleanup();
|
||||
|
||||
g_timer_destroy(timer_);
|
||||
|
||||
// no need to destroy the channels - stopped_cleanup() calls
|
||||
// cleanup_members(), which deletes them.
|
||||
}
|
||||
|
||||
|
||||
// Call before execute.
|
||||
// Note: The command and the arguments _must_ be shell-escaped.
|
||||
// Use g_shell_quote() or Glib::shell_quote(). Note that each argument
|
||||
// must be escaped separately.
|
||||
void set_command(const std::string& command_exec, const std::string& command_args)
|
||||
{
|
||||
command_exec_ = command_exec;
|
||||
command_args_ = command_args;
|
||||
}
|
||||
|
||||
|
||||
// launch the command.
|
||||
bool execute();
|
||||
|
||||
|
||||
// send SIGTERM(15) (terminate).
|
||||
// use after execute(). using it after the command has exited has no effect.
|
||||
bool try_stop(hz::signal_t sig = hz::SIGNAL_SIGTERM);
|
||||
|
||||
|
||||
// Send SIGKILL(9) (kill). This signal cannot be overridden in child process.
|
||||
// use after execute(). using it after the command has exited has no effect.
|
||||
bool try_kill()
|
||||
{
|
||||
return try_stop(hz::SIGNAL_SIGKILL);
|
||||
}
|
||||
|
||||
|
||||
// set a timeout (since call to this function) to terminate, kill or both (use 0 to ignore the parameter).
|
||||
// the timeouts will be unset automatically when the command exits.
|
||||
// This has an effect only if the command is running (after execute()).
|
||||
void set_stop_timeouts(int term_timeout_msec = 0, int kill_timeout_msec = 0);
|
||||
|
||||
// Unset timeouts. This will stop the timeout counters.
|
||||
// This has an effect only if the command is running (after execute()).
|
||||
void unset_stop_timeouts();
|
||||
|
||||
|
||||
// If stopped_cleanup_needed() returned true, call this. The command
|
||||
// should be exited by this time. Must be called before the next execute().
|
||||
void stopped_cleanup();
|
||||
|
||||
|
||||
// Returns true if command has stopped.
|
||||
// Call repeatedly in a waiting function, after execute(). When returns true, call stopped_cleanup().
|
||||
bool stopped_cleanup_needed()
|
||||
{
|
||||
return (child_watch_handler_called_);
|
||||
}
|
||||
|
||||
|
||||
// The process is running. Note that if this returns false, it doesn't mean that
|
||||
// the io channels have been closed or that the data may be read safely. Poll
|
||||
// stopped_cleanup_needed() instead.
|
||||
bool is_running() const
|
||||
{
|
||||
return running_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 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 (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 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)
|
||||
{
|
||||
if (stdout_buffer_size)
|
||||
channel_stdout_buffer_size_ = stdout_buffer_size; // 100K by default
|
||||
if (stderr_buffer_size)
|
||||
channel_stderr_buffer_size_ = stderr_buffer_size; // 10K by default
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
// debug_out_dump("app", str_stdout_);
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stdout_;
|
||||
str_stdout_.clear();
|
||||
return ret;
|
||||
}
|
||||
return str_stdout_;
|
||||
}
|
||||
|
||||
|
||||
// See notes on get_stdout_str().
|
||||
std::string get_stderr_str(bool clear_existing = false)
|
||||
{
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stderr_;
|
||||
str_stderr_.clear();
|
||||
return ret;
|
||||
}
|
||||
return str_stderr_;
|
||||
}
|
||||
|
||||
|
||||
// Return execution time, in seconds. Call after execute().
|
||||
double get_execution_time()
|
||||
{
|
||||
gulong microsec = 0;
|
||||
return g_timer_elapsed(timer_, µsec);
|
||||
}
|
||||
|
||||
|
||||
// this will disconnect earlier slots. Call before execute().
|
||||
void set_exit_status_translator(exit_status_translator_func_t func, void* user_data)
|
||||
{
|
||||
translator_func_ = func;
|
||||
translator_func_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
// You can use stopped_cleanup_needed() polling instead.
|
||||
void set_exited_callback(exited_callback_func_t func, void* user_data)
|
||||
{
|
||||
exited_callback_ = func;
|
||||
exited_callback_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// these are sorta-private
|
||||
|
||||
// for passing to callback
|
||||
enum channel_t {
|
||||
channel_type_stdout,
|
||||
channel_type_stderr
|
||||
};
|
||||
|
||||
|
||||
// Callbacks (Note: These are called by the real callbacks)
|
||||
|
||||
static void on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data);
|
||||
|
||||
static gboolean on_channel_io(GIOChannel* source,
|
||||
GIOCondition cond, Cmdex* self, channel_t type);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void cleanup_members()
|
||||
{
|
||||
kill_signal_sent_ = 0;
|
||||
child_watch_handler_called_ = false;
|
||||
pid_ = 0;
|
||||
waitpid_status_ = 0;
|
||||
event_source_id_stdout_ = 0;
|
||||
event_source_id_stderr_ = 0;
|
||||
fd_stdout_ = 0;
|
||||
fd_stderr_ = 0;
|
||||
|
||||
if (channel_stdout_) {
|
||||
g_io_channel_shutdown(channel_stdout_, false, NULL);
|
||||
g_io_channel_unref(channel_stdout_);
|
||||
channel_stdout_ = 0;
|
||||
}
|
||||
if (channel_stderr_) {
|
||||
g_io_channel_shutdown(channel_stderr_, false, NULL);
|
||||
g_io_channel_unref(channel_stderr_);
|
||||
channel_stderr_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// default command and its args. std::strings, not ustrings.
|
||||
std::string command_exec_; // binary name. NOT affected by cleanup().
|
||||
std::string command_args_; // args that always go with binary. NOT affected by cleanup().
|
||||
|
||||
|
||||
bool running_; // child process is running now. NOT affected by cleanup().
|
||||
int kill_signal_sent_; // command has been sent this signal to terminate
|
||||
bool child_watch_handler_called_; // true after child_watch_handler callback, before stopped_cleanup().
|
||||
|
||||
GPid pid_; // int in Unix, pointer in win32
|
||||
int waitpid_status_; // after the command is stopped, before cleanup, this will be available.
|
||||
|
||||
|
||||
GTimer* timer_; // keep track of elapsed time since command execution. not used by this class, but may be handy.
|
||||
|
||||
int event_source_id_term;
|
||||
int event_source_id_kill;
|
||||
|
||||
|
||||
int fd_stdout_;
|
||||
int fd_stderr_;
|
||||
|
||||
GIOChannel* channel_stdout_;
|
||||
GIOChannel* channel_stderr_;
|
||||
|
||||
int channel_stdout_buffer_size_; // NOT affected by cleanup().
|
||||
int channel_stderr_buffer_size_; // NOT affected by cleanup().
|
||||
|
||||
int event_source_id_stdout_;
|
||||
int event_source_id_stderr_;
|
||||
|
||||
std::string str_stdout_; // NOT affected by cleanup().
|
||||
std::string str_stderr_; // NOT affected by cleanup().
|
||||
|
||||
|
||||
// signals
|
||||
|
||||
// convert command exit status to message string
|
||||
exit_status_translator_func_t translator_func_; // NOT affected by cleanup().
|
||||
void* translator_func_data_;
|
||||
|
||||
// "command exited" signal callback.
|
||||
exited_callback_func_t exited_callback_; // NOT affected by cleanup().
|
||||
void* exited_callback_data_;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,120 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_CMDEX_SYNC_GUI_H
|
||||
#define APP_CMDEX_SYNC_GUI_H
|
||||
|
||||
#include <gtkmm/messagedialog.h>
|
||||
#include <glibmm/timer.h>
|
||||
|
||||
#include "hz/noncopyable.h"
|
||||
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
// CmdexSync with GUI support
|
||||
|
||||
|
||||
|
||||
// same as CmdexSync, but with GTK UI stuff.
|
||||
// this one is noncopyable, because we don't copy the dialogs, etc...
|
||||
class CmdexSyncGui : public CmdexSync, public hz::noncopyable {
|
||||
|
||||
public:
|
||||
|
||||
CmdexSyncGui(const std::string& cmd, const std::string& cmdargs)
|
||||
: CmdexSync(cmd, cmdargs), execution_running_(false), should_abort_(false),
|
||||
running_dialog_(0), running_dialog_shown_(false), running_dialog_abort_mode_(false)
|
||||
{
|
||||
signal_execute_tick.connect(sigc::mem_fun(*this, &CmdexSyncGui::execute_tick_func));
|
||||
}
|
||||
|
||||
|
||||
CmdexSyncGui()
|
||||
: execution_running_(false), should_abort_(false),
|
||||
running_dialog_(0), running_dialog_shown_(false), running_dialog_abort_mode_(false)
|
||||
{
|
||||
signal_execute_tick.connect(sigc::mem_fun(*this, &CmdexSyncGui::execute_tick_func));
|
||||
}
|
||||
|
||||
|
||||
~CmdexSyncGui()
|
||||
{
|
||||
delete running_dialog_;
|
||||
}
|
||||
|
||||
|
||||
virtual bool execute();
|
||||
|
||||
|
||||
// UI callbacks may use this to abort execution.
|
||||
void set_should_abort()
|
||||
{
|
||||
should_abort_ = true;
|
||||
}
|
||||
|
||||
|
||||
// create a dialog or return already existing one.
|
||||
// the dialog will be auto-created and displayed on execute().
|
||||
// you need the function only if you intend to modify it before execute().
|
||||
Gtk::MessageDialog* create_running_dialog(Gtk::Window* parent = 0, const Glib::ustring& msg = "");
|
||||
|
||||
|
||||
Gtk::MessageDialog* get_running_dialog()
|
||||
{
|
||||
return running_dialog_;
|
||||
}
|
||||
|
||||
|
||||
// this actually shows the dialog only after some time has passed,
|
||||
// to avoid very quick show/hide.
|
||||
void show_hide_dialog(bool show);
|
||||
|
||||
|
||||
// called from ticker function in running mode, to show the dialog when requested time elapses.
|
||||
void update_dialog_show_timer();
|
||||
|
||||
|
||||
|
||||
// switch the dialog to "Aborting..." mode
|
||||
void set_running_dialog_abort_mode(bool aborting);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// dialog callback.
|
||||
void on_running_dialog_response(int response_id)
|
||||
{
|
||||
// Try to abort if Cancel was clicked
|
||||
if (response_id == Gtk::RESPONSE_CANCEL)
|
||||
set_should_abort();
|
||||
}
|
||||
|
||||
|
||||
// this function is called every time something happens
|
||||
// with the executor.
|
||||
bool execute_tick_func(tick_status_t status);
|
||||
|
||||
|
||||
bool execution_running_;
|
||||
bool should_abort_; // GUI callbacks may set this to abort the execution
|
||||
|
||||
Gtk::MessageDialog* running_dialog_;
|
||||
bool running_dialog_shown_;
|
||||
bool running_dialog_abort_mode_;
|
||||
Glib::Timer running_dialog_timer_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SELFTEST_H
|
||||
#define SELFTEST_H
|
||||
|
||||
#include <string>
|
||||
#include <glibmm/timer.h>
|
||||
|
||||
#include "hz/cstdint.h"
|
||||
#include "hz/intrusive_ptr.h"
|
||||
|
||||
#include "storage_device.h"
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
class SelfTest : public hz::intrusive_ptr_referenced {
|
||||
public:
|
||||
|
||||
enum test_t {
|
||||
type_ioffline, // immediate offline, not supported yet
|
||||
type_short,
|
||||
type_long,
|
||||
type_conveyance
|
||||
};
|
||||
|
||||
static std::string get_test_name(test_t t)
|
||||
{
|
||||
switch (t) {
|
||||
case type_ioffline: return "Immediate Offline Test";
|
||||
case type_short: return "Short Self-test";
|
||||
case type_long: return "Extended Self-test";
|
||||
case type_conveyance: return "Conveyance Self-test";
|
||||
};
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
// The drive must have the capabilities present in properties.
|
||||
SelfTest(StorageDeviceRefPtr drive, test_t type)
|
||||
: drive_(drive), type_(type)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
void clear() // clear results of previous test
|
||||
{
|
||||
status_ = StorageSelftestEntry::status_unknown;
|
||||
remaining_percent_ = -1;
|
||||
last_seen_percent_ = -1;
|
||||
total_duration_ = -1;
|
||||
poll_in_seconds_ = -1;
|
||||
}
|
||||
|
||||
|
||||
bool is_active() const
|
||||
{
|
||||
return (status_ == StorageSelftestEntry::status_in_progress);
|
||||
}
|
||||
|
||||
|
||||
// returns -1 if n/a or unknown.
|
||||
int8_t get_remaining_percent() const
|
||||
{
|
||||
return remaining_percent_;
|
||||
}
|
||||
|
||||
|
||||
// Returns estimated time of completion for the test. returns -1 if n/a or unknown. 0 is a valid value.
|
||||
int64_t get_remaining_seconds() const;
|
||||
|
||||
|
||||
test_t get_test_type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
|
||||
StorageSelftestEntry::status_t get_status() const
|
||||
{
|
||||
return status_;
|
||||
}
|
||||
|
||||
|
||||
// get the number of seconds after which the caller should call update().
|
||||
int64_t get_poll_in_seconds() const
|
||||
{
|
||||
return poll_in_seconds_;
|
||||
}
|
||||
|
||||
|
||||
// gets a constant "test duration during idle" capability drive's stored capabilities. -1 if N/A.
|
||||
int64_t get_min_duration_seconds() const;
|
||||
|
||||
|
||||
// gets the current test type support status from drive's stored capabilities.
|
||||
bool is_supported() const;
|
||||
|
||||
|
||||
// These return an error message, or empty string if no error.
|
||||
|
||||
// start the test
|
||||
std::string start(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
|
||||
|
||||
|
||||
// abort the running test
|
||||
std::string force_stop(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
|
||||
|
||||
|
||||
// update status variables
|
||||
std::string update(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
|
||||
|
||||
|
||||
private:
|
||||
StorageDeviceRefPtr drive_;
|
||||
|
||||
test_t type_;
|
||||
|
||||
// status variables:
|
||||
StorageSelftestEntry::status_t status_;
|
||||
int8_t remaining_percent_; // 0 means unknown, -1 means n/a. Set to 100 on start.
|
||||
int8_t last_seen_percent_; // to detect changes in percentage (needed for timer update)
|
||||
mutable int64_t total_duration_; // total duration needed for the test, as reported by drive. constant. this is a cache.
|
||||
int64_t poll_in_seconds_; // the user is asked to poll after this much seconds have passed.
|
||||
|
||||
Glib::Timer timer_; // counts time since the last percent change
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
typedef hz::intrusive_ptr<SelfTest> SelfTestPtr;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,159 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_DETECTOR_HELPERS_H
|
||||
#define STORAGE_DETECTOR_HELPERS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "executor_factory.h"
|
||||
#include "storage_device.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Get number of ports using tw_cli. Return -1 on error.
|
||||
inline std::string tw_cli_get_drives(const std::string& dev, int scsi_host_no,
|
||||
std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory, bool use_tw_cli_dev)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string command_options = hz::string_sprintf("/c%d show all", scsi_host_no);
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), command_options);
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
pcrecpp::RE port_re = app_pcre_re("/^p([0-9])+[ \\t]+([^\\t\\n]+)/mi");
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string port_str, status;
|
||||
if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &port_str, &status)) {
|
||||
if (status != "NOT-PRESENT") {
|
||||
int port = -1;
|
||||
hz::string_is_numeric(port_str, port);
|
||||
if (port != -1) {
|
||||
if (use_tw_cli_dev) { // use "tw_cli/cx/py" device
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice("tw_cli/c"
|
||||
+ hz::number_to_string(scsi_host_no) + "/p" + hz::number_to_string(port))));
|
||||
} else {
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(dev, "3ware," + hz::number_to_string(port))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Return 3ware SCSI host numbers (same as /c switch to tw_cli)
|
||||
/// \return error string on error
|
||||
inline std::string tw_cli_get_controllers(ExecutorFactoryRefPtr ex_factory, std::vector<int>& controllers)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> executor = ex_factory->create_executor(ExecutorFactory::ExecutorTwCli);
|
||||
|
||||
std::string binary;
|
||||
rconfig::get_data("system/tw_cli_binary", binary);
|
||||
|
||||
if (binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli binary is not set in config.\n");
|
||||
return "tw_cli binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::vector<std::string> binaries; // binaries to try
|
||||
// Note: tw_cli is automatically added to PATH in windows, no need to look for it.
|
||||
binaries.push_back(binary);
|
||||
#ifdef CONFIG_KERNEL_LINUX
|
||||
// tw_cli may be named tw_cli.x86 or tw_cli.x86_64 in linux
|
||||
binaries.push_back(binary + ".x86_64"); // try this first
|
||||
binaries.push_back(binary + ".x86");
|
||||
#endif
|
||||
|
||||
for (std::size_t i = 0; i < binaries.size(); ++i) {
|
||||
executor->set_command(Glib::shell_quote(binaries.at(i)), "show");
|
||||
|
||||
if (!executor->execute() || !executor->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n");
|
||||
} else {
|
||||
break; // found it
|
||||
}
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(executor->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "tw_cli returned an empty output.\n");
|
||||
return "tw_cli returned an empty output.";
|
||||
}
|
||||
|
||||
// split to lines
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
pcrecpp::RE controller_re = app_pcre_re("/^c([0-9])+[ \\t]+/mi");
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string controller_str;
|
||||
if (controller_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &controller_str)) {
|
||||
int controller = -1;
|
||||
hz::string_is_numeric(controller_str, controller);
|
||||
if (controller != -1) {
|
||||
controllers.push_back(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,497 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "storage_detector_linux.h"
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets(), std::FILE
|
||||
#include <cerrno> // ENXIO
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_path_utils.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
// Linux 2.6 with udev. Scan /dev/disk/by-id - the directory entries there
|
||||
// are symlinks to respective /dev devices. Some devices have multiple
|
||||
// links pointing to them, so unique filter is needed.
|
||||
/*
|
||||
Sample listing:
|
||||
------------------------------------------------------------
|
||||
# ls -1 /dev/disk/by-id
|
||||
ata-ST31000340AS_9QJ0FFG7
|
||||
ata-ST31000340AS_9QJ0FFG7-part1
|
||||
ata-ST31000340AS_9QJ0FFG7-part2
|
||||
ata-ST3500630AS_9QG0R38D
|
||||
ata-ST3500630AS_9QG0R38D-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part2
|
||||
scsi-SATA_ST3500630AS_9QG0R38D
|
||||
scsi-SATA_ST3500630AS_9QG0R38D-part1
|
||||
*/
|
||||
/*
|
||||
// We don't use udev anymore - not all distros have it, and e.g. Ubuntu
|
||||
// has it all wrong (two symlinks (sda, sdb) pointing both to sdb).
|
||||
inline std::string detect_drives_linux_udev_byid(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through device scan directory /dev/disk/by-id...\n");
|
||||
|
||||
std::string dev_dir; // this defaults to "/dev/disk/by-id"
|
||||
if (!rconfig::get_data("system/linux_udev_byid_path", dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory path is not set.\n");
|
||||
return "Device scan directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.list(all_devices, false)) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
blacklist.push_back("/-part[0-9]+$/");
|
||||
|
||||
// filter-out the ones with "partN" in them
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// those are usually relative links, so find out where they are pointing to.
|
||||
std::string link_dest;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
path.compress(); // compress in case there are ../-s.
|
||||
}
|
||||
|
||||
// skip number-ended devices, in case we couldn't filter out the scan directory correctly
|
||||
// (it's user-settable after all).
|
||||
// if (app_pcre_match("/[0-9]+$/", path.str()))
|
||||
// continue;
|
||||
|
||||
if (std::find(devices.begin(), devices.end(), path.str()) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path.str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Procfs files don't support SEEK_END or ftello() (I think). Anyway, they can't
|
||||
// be read through hz::File::get_contents, so use this function instead.
|
||||
inline bool read_proc_file(hz::File& file, std::vector<std::string>& lines)
|
||||
{
|
||||
if (!file.open("rb")) // closed automatically
|
||||
return false; // the error message is in File itself.
|
||||
|
||||
std::FILE* fp = file.get_handle();
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char line[256];
|
||||
while (std::fgets(line, static_cast<int>(sizeof(line)), fp) != NULL) {
|
||||
if (*line != '\0')
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_partitions_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_partitions_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file path is not set.\n");
|
||||
return "Partitions file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Partitions file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_devices_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_devices_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Devices file path is not set.\n");
|
||||
return "Devices file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Devices file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Devices file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read /proc/partitions file. Return error message on error.
|
||||
inline std::string read_proc_scsi_scsi_file(std::vector<std::string>& lines)
|
||||
{
|
||||
std::string path;
|
||||
if (!rconfig::get_data("system/linux_proc_scsi_scsi_path", path) || path.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "SCSI file path is not set.\n");
|
||||
return "SCSI file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(path);
|
||||
if (!read_proc_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "SCSI file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "SCSI file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Get number of ports by sequentially running smartctl on each port, until
|
||||
/// one of the gives an error. Return -1 on error.
|
||||
inline std::string smartctl_get_drives(const std::string& dev, const std::string& type,
|
||||
int from, int to, std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
for (int i = from; i <= to; ++i) {
|
||||
std::string type_arg = hz::string_sprintf(type.c_str(), i);
|
||||
StorageDeviceRefPtr drive(new StorageDevice(dev, type_arg));
|
||||
|
||||
// std::string error_msg = execute_smartctl(dev, "-d " + type_arg, "-i", smartctl_ex, output);
|
||||
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
std::string output = drive->get_info_output();
|
||||
|
||||
// if we've reached smartctl port limit (older versions may have smaller limits), abort.
|
||||
if (app_pcre_match("/VALID ARGUMENTS ARE/mi", output)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_info("app", "Smartctl returned with an error: " << error_msg);
|
||||
} else {
|
||||
drives.push_back(drive);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Linux (tested with 2.4 and 2.6) /proc/partitions. Parses the file, appends /dev to each entry.
|
||||
// Note that file format changed from 2.4 to 2.6 (some statistics fields moved to another file).
|
||||
// No /proc/partitions on freebsd, solaris or osx, afaik.
|
||||
/*
|
||||
Sample 1 (2.4, devfs, with statistics):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
||||
|
||||
3 0 60051600 ide/host0/bus0/target0/lun0/disc 72159 136746 1668720 467190 383039 658435 8342136 1659840 -429 17038808 22703194
|
||||
3 1 1638598 ide/host0/bus0/target0/lun0/part1 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 2 1028160 ide/host0/bus0/target0/lun0/part2 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3092512 ide/host0/bus0/target0/lun0/part3 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 4 1 ide/host0/bus0/target0/lun0/part4 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 5 514048 ide/host0/bus0/target0/lun0/part5 1458 7877 74680 9070 2140 18285 166272 42490 0 10100 52000
|
||||
------------------------------------------------------------
|
||||
Sample 2 (2.6):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
1 0 4096 ram0
|
||||
8 0 156290904 sda
|
||||
8 1 39070048 sda1
|
||||
8 2 7560 sda2
|
||||
8 3 1 sda3
|
||||
------------------------------------------------------------
|
||||
Sample 3 (2.6 on nokia n8xx, spaces may be missing):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
31 0 128 mtdblock0
|
||||
31 1 384 mtdblock1
|
||||
31 2 2048 mtdblock2
|
||||
31 3 2048 mtdblock3
|
||||
31 4 257536 mtdblock4
|
||||
254 0 3932160 mmcblk0
|
||||
254 1 3928064 mmcblk0p1
|
||||
254 8 1966080 mmcblk1
|
||||
254 9 2007032 mmcblk1p1
|
||||
*/
|
||||
inline std::string detect_drives_linux_proc_partitions(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /proc/partitions...\n");
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::string error_msg = read_proc_partitions_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
// fixme: not sure about how partitions are visible with twa0.
|
||||
blacklist.push_back("/d[a-z][0-9]+$/"); // sda1, hdb2 - partitions. twa0 and twe1 are drives, not partitions.
|
||||
blacklist.push_back("/ram[0-9]+$/"); // ramdisks?
|
||||
blacklist.push_back("/loop[0-9]*$/"); // not sure if loop devices go there, but anyway...
|
||||
blacklist.push_back("/part[0-9]+$/"); // devfs had them
|
||||
blacklist.push_back("/p[0-9]+$/"); // partitions are usually marked this way
|
||||
blacklist.push_back("/md[0-9]*$/"); // linux software raid
|
||||
blacklist.push_back("/dm-[0-9]*$/"); // linux device mapper
|
||||
|
||||
std::vector<std::string> devices;
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string line = hz::string_trim_copy(lines[i]);
|
||||
if (line.empty() || app_pcre_match("/^major/", line)) // file header
|
||||
continue;
|
||||
|
||||
std::string dev;
|
||||
if (!app_pcre_match("/^[ \\t]*[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+([^ \\t\\n]+)/", line, &dev) || dev.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse line \"" << line << "\".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, dev)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
std::string path = "/dev/" + dev; // let's just hope the it's /dev.
|
||||
if (std::find(devices.begin(), devices.end(), path) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path);
|
||||
}
|
||||
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
StorageDeviceRefPtr drive(new StorageDevice(devices.at(i)));
|
||||
drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
|
||||
// 3ware controllers also export themselves as sd*. Smartctl detects that,
|
||||
// so we can avoid adding them. Older smartctl (5.38) prints "AMCC", newer one
|
||||
// prints "AMCC/3ware controller". It's better to search it this way.
|
||||
if (!app_pcre_match("/try adding '-d 3ware,N'/im", drive->get_info_output())) {
|
||||
drives.push_back(drive);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Detect drives behind 3ware RAID controller.
|
||||
|
||||
3ware Linux:
|
||||
Call as: smartctl -i -d 3ware,[0-127] /dev/twa[0-15] (or twe[0-15])
|
||||
Use twe* for [678]xxx series, and twa* for 9xxx series.
|
||||
Note: twe* devices are limited to [0-15] ports (not sure about this).
|
||||
Note: /dev/tw* devices may not exist, they are created by smartctl on the first run.
|
||||
Note: for twe*, /dev/sda may also exist (to be used with -d 3ware,N), we should
|
||||
somehow detect and ignore them.
|
||||
Note: when specifying non-existent port, either a "Device Read Identity Failed"
|
||||
error, or a "blank" info may be returned.
|
||||
Detection:
|
||||
Grep /proc/devices for "twa" or "twe" (e.g. "251 twa"). Use this for /dev/tw* part.
|
||||
Grep /proc/scsi/scsi for AMCC or 3ware (LSI too?), use number of matched lines N
|
||||
for /dev/tw*[0, N-1].
|
||||
For detecting the number of ports, use "tw_cli /cK show all", K being the controller
|
||||
scsi number, which is displayed as scsiK in the scsi file.
|
||||
If there's no tw_cli, we'll have to scan all the ports (up to supported maximum).
|
||||
This is too slow however, so scan only 24.
|
||||
|
||||
Implementation notes: it seems that twe uses "3ware" and twa uses "AMCC".
|
||||
We can't handle a situation with both twa and twe present, since we don't know
|
||||
how they will be ordered for tw_cli.
|
||||
*/
|
||||
inline std::string detect_drives_linux_3ware(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::string error_msg = read_proc_devices_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
bool twa_found = false;
|
||||
bool twe_found = false;
|
||||
|
||||
// Check /proc/devices for twa or twe
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string dev;
|
||||
if (app_pcre_match("/^[ \\t]*[0-9]+[ \\t]+(tw[ae])/", hz::string_trim_copy(lines[i]), &dev)) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Found " << dev << " entry in devices file.\n");
|
||||
if (dev == "twa") {
|
||||
twa_found = true;
|
||||
} else if (dev == "twe") {
|
||||
twe_found = true;
|
||||
} else {
|
||||
DBG_ASSERT(0); // error in regexp?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!twa_found && !twe_found) {
|
||||
return std::string(); // no controllers
|
||||
}
|
||||
|
||||
lines.clear();
|
||||
error_msg = read_proc_scsi_scsi_file(lines);
|
||||
if (!error_msg.empty()) {
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
int num_controllers = 0;
|
||||
int last_scsi_host = 0;
|
||||
|
||||
pcrecpp::RE host_re = app_pcre_re("^Host: scsi([0-9]+)");
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
// The format of this file is scsi host number on one line, vendor on another.
|
||||
// debug_out_error("app", "SCSI Line: " << hz::string_trim_copy(lines[i]) << "\n");
|
||||
std::string scsi_host_str;
|
||||
if (host_re.PartialMatch(hz::string_trim_copy(lines[i]), &scsi_host_str)) {
|
||||
// debug_out_dump("app", "SCSI Host " << scsi_host_str << " found.\n");
|
||||
hz::string_is_numeric(scsi_host_str, last_scsi_host);
|
||||
}
|
||||
if (!app_pcre_match("/Vendor: (AMCC)|(3ware) /i", hz::string_trim_copy(lines[i]))) {
|
||||
continue; // not a supported controller
|
||||
}
|
||||
|
||||
debug_out_dump("app", "Found AMCC/3ware controller in SCSI file, SCSI host " << last_scsi_host << ".\n");
|
||||
|
||||
// We can't handle both twa and twe in one system, so assume twa by default.
|
||||
// We can't map twaX to scsiY, so lets assume the relative order is the same.
|
||||
std::string dev = std::string("/dev/") + (twa_found ? "twa" : "twe") + hz::number_to_string(num_controllers);
|
||||
|
||||
error_msg = tw_cli_get_drives(dev, last_scsi_host, drives, ex_factory, false);
|
||||
if (!error_msg.empty()) { // no tw_cli
|
||||
int max_ports = rconfig::get_data<int32_t>("system/linux_max_scan_ports");
|
||||
max_ports = std::max(max_ports, 23); // 128 smartctl calls are too much (it's too slow). Settle for 24.
|
||||
error_msg = smartctl_get_drives(dev, "3ware,%d", 0, max_ports, drives, ex_factory);
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Couldn't get number of ports on a 3ware controller.\n");
|
||||
}
|
||||
|
||||
++num_controllers;
|
||||
}
|
||||
|
||||
if (num_controllers == 0) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "3ware entry found in devices file, but SCSI file contains no known entries.\n");
|
||||
}
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
} // anon ns
|
||||
|
||||
|
||||
|
||||
|
||||
std::string detect_drives_linux(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<std::string> error_msgs;
|
||||
std::string error_msg;
|
||||
|
||||
// Disable by-id detection - it's unreliable on broken systems.
|
||||
// For example, on Ubuntu 8.04, /dev/disk/by-id contains two device
|
||||
// links for two drives, but both point to the same sdb (instead of
|
||||
// sda and sdb). Plus, there are no "*-partN" files (not that we need them).
|
||||
// error_msg = detect_drives_linux_udev_byid(devices); // linux udev
|
||||
|
||||
error_msg = detect_drives_linux_proc_partitions(drives, ex_factory);
|
||||
if (!error_msg.empty()) {
|
||||
error_msgs.push_back(error_msg);
|
||||
}
|
||||
|
||||
error_msg = detect_drives_linux_3ware(drives, ex_factory);
|
||||
if (!error_msg.empty()) {
|
||||
error_msgs.push_back(error_msg);
|
||||
}
|
||||
|
||||
return hz::string_join(error_msgs, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CONFIG_KERNEL_LINUX
|
||||
@@ -1,209 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "storage_detector_win32.h"
|
||||
|
||||
#if defined CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
|
||||
#include <windows.h> // CreateFileA(), CloseHandle(), etc...
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "hz/win32_tools.h"
|
||||
#include "hz/string_sprintf.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector_helpers.h"
|
||||
|
||||
|
||||
/*
|
||||
3ware Windows (XP so far, maybe the same under the others):
|
||||
For 3ware 9xxx only.
|
||||
Call as: smartctl -i sd[a-z],N
|
||||
N is port, a-z is logical drive (unit) provided by controller.
|
||||
N is limited to [0, 31] in the code.
|
||||
The sd[a-z] device actually exists as \\.\PhysicalDrive[0-N].
|
||||
No idea how to check if it's 3ware.
|
||||
Call as: smarctl -i tw_cli/cx/py
|
||||
This runs tw_cli tool and parses the output; controller x, port y.
|
||||
tw_cli may be needed for older controllers / drivers.
|
||||
In tw_cli mode only limited information-gathering is supported.
|
||||
tw_cli (part of 3DM2) is automatically added to system PATH,
|
||||
no need to look for it.
|
||||
3DM2 install can be detected by checking:
|
||||
HKEY_USERS\.DEFAULT\Software\3ware\3DM2, InstallPath
|
||||
Another option for detection (whether it's 3ware) would be getting
|
||||
\\.\PhysicalDrive0 properties, like smartctl does.
|
||||
Newer (added after 5.39.1) smartctl supports --scan-open, which will give us:
|
||||
/dev/sda,0 -d ata (opened)
|
||||
/dev/sda,1 -d ata (opened)
|
||||
-d 3ware is not needed under Windows. We should treat sda as pd0
|
||||
and remove pd0 from PhysicalDrive-detected list.
|
||||
Running smartctl on sda gives almost the same result as on sda,0.
|
||||
|
||||
|
||||
Intel Matrix RAID (since smartmontools SVN version on 2011-02-04):
|
||||
Call as: "/dev/csmi[0-9],N" where N is the port behind the logical
|
||||
scsi controller "\\.\Scsi[0-9]:".
|
||||
The prefix "/dev/" is optional.
|
||||
This is detected (with /dev/ prefix) by --scan-open.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
smartctl --scan-open output for win32 (3ware):
|
||||
/dev/sda,0 -d ata (opened)
|
||||
/dev/sda,1 -d ata (opened)
|
||||
|
||||
smartctl --scan-open output for linux:
|
||||
/dev/sda -d sat # /dev/sda [SAT], ATA device
|
||||
/dev/sdb -d sat # /dev/sdb [SAT], ATA device
|
||||
/dev/sdc -d sat # /dev/sdc [SAT], ATA device
|
||||
*/
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
/// Run "smartctl --scan-open" and pick the devices which have
|
||||
/// a port parameter. We don't pick the others because the may
|
||||
/// conflict with pd* devices, and we like pd* better than sd*.
|
||||
std::string get_scan_open_multiport_devices(std::vector<StorageDeviceRefPtr>& drives,
|
||||
ExecutorFactoryRefPtr ex_factory, std::vector<int>& equivalent_pds)
|
||||
{
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl);
|
||||
|
||||
std::string smartctl_binary = get_smartctl_binary();
|
||||
|
||||
if (smartctl_binary.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl binary is not set in config.\n");
|
||||
return "Smartctl binary is not specified in configuration.";
|
||||
}
|
||||
|
||||
std::string smartctl_def_options;
|
||||
rconfig::get_data("system/smartctl_options", smartctl_def_options);
|
||||
|
||||
if (!smartctl_def_options.empty())
|
||||
smartctl_def_options += " ";
|
||||
|
||||
smartctl_ex->set_command(Glib::shell_quote(smartctl_binary),
|
||||
smartctl_def_options + "--scan-open");
|
||||
|
||||
if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Error while executing smartctl binary.\n");
|
||||
return smartctl_ex->get_error_msg();
|
||||
}
|
||||
|
||||
// any_to_unix is needed for windows
|
||||
std::string output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str()));
|
||||
if (output.empty()) {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Smartctl returned an empty output.\n");
|
||||
return "Smartctl returned an empty output.";
|
||||
}
|
||||
|
||||
// if we've reached smartctl port limit (older versions may have smaller limits), abort.
|
||||
if (app_pcre_match("/UNRECOGNIZED OPTION/mi", output)) {
|
||||
return "Smartctl doesn't support --scan-open switch.";
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> lines;
|
||||
hz::string_split(output, '\n', lines, true);
|
||||
|
||||
// /dev/sda,0 -d ata (opened)
|
||||
// /dev/sda,1 -d ata (opened)
|
||||
// /dev/sda -d sat # /dev/sda [SAT], ATA device
|
||||
// /dev/sde,2 -d ata [ATA] (opened)
|
||||
|
||||
// we only pick the ones with ports
|
||||
pcrecpp::RE port_re = app_pcre_re("/^(/dev/[a-z0-9]+),([0-9]+)[ \\t]+-d[ \\t]+([^ \\t\\n]+)/i");
|
||||
pcrecpp::RE dev_re = app_pcre_re("/^/dev/sd([a-z])$/");
|
||||
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) {
|
||||
std::string dev, port_str, type;
|
||||
if (port_re.PartialMatch(hz::string_trim_copy(lines.at(i)), &dev, &port_str, &type)) {
|
||||
std::string letter;
|
||||
if (dev_re.PartialMatch(dev, &letter)) {
|
||||
// don't use pd* devices equivalent to these sd* devices.
|
||||
equivalent_pds.push_back(letter.at(0) - 'a');
|
||||
}
|
||||
|
||||
std::string full_dev = dev + "," + port_str;
|
||||
drives.push_back(StorageDeviceRefPtr(new StorageDevice(full_dev, type)));
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// smartctl accepts various variants, the most straight being pdN,
|
||||
// (or /dev/pdN, /dev/ being optional) where N comes from
|
||||
// "\\.\PhysicalDriveN" (winnt only).
|
||||
// http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
|
||||
|
||||
std::string detect_drives_win32(std::vector<StorageDeviceRefPtr>& drives, ExecutorFactoryRefPtr ex_factory)
|
||||
{
|
||||
std::vector<int> used_pds;
|
||||
std::string error_msg = get_scan_open_multiport_devices(drives, ex_factory, used_pds);
|
||||
bool multiport_found = !drives.empty();
|
||||
|
||||
for (int drive_num = 0; ; ++drive_num) {
|
||||
std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num);
|
||||
|
||||
// If the drive is openable, then it's there.
|
||||
// NOTE: Administrative privileges are required to open it.
|
||||
// Yes, CreateFile() is open, not create. Yes, it's silly (ah, win32...).
|
||||
// We don't use any long/unopenable files here, so use the ANSI version.
|
||||
HANDLE h = CreateFileA(name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
// The numbers seem to be consecutive, so break on first invalid.
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
if (std::find(used_pds.begin(), used_pds.end(), drive_num) == used_pds.end()) {
|
||||
std::string dev = hz::string_sprintf("pd%d", drive_num);
|
||||
drives.push_back(new StorageDevice(dev));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If smartctl --scan-open returns no "sd*,port"-style devices,
|
||||
// check if 3dm2 is installed and execute "tw_cli show" to get
|
||||
// the controllers, then use the tw_cli variant of smartctl.
|
||||
|
||||
if (!multiport_found) {
|
||||
std::string inst_path;
|
||||
hz::win32_get_registry_value_string(HKEY_USERS, ".DEFAULT\\Software\\3ware\\3DM2", "InstallPath", inst_path);
|
||||
|
||||
if (!inst_path.empty()) {
|
||||
std::vector<int> controllers;
|
||||
error_msg = tw_cli_get_controllers(ex_factory, controllers);
|
||||
// ignore the error message above, it's of no use.
|
||||
for (std::size_t i = 0; i < controllers.size(); ++i) {
|
||||
// don't specify device, it's ignored in tw_cli mode
|
||||
tw_cli_get_drives("", controllers.at(i), drives, ex_factory, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CONFIG_KERNEL_FAMILY_WINDOWS
|
||||
@@ -1,422 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_PROPERTY_H
|
||||
#define STORAGE_PROPERTY_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "hz/optional_value.h"
|
||||
#include "hz/cstdint.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// holds one block of "capabilities" subsection
|
||||
// (only for non-time-interval blocks).
|
||||
class StorageCapability {
|
||||
public:
|
||||
|
||||
StorageCapability() : flag_value(0x0)
|
||||
{ }
|
||||
|
||||
typedef std::vector<std::string> strvalue_list_t;
|
||||
|
||||
std::string reported_flag_value; // original flag value
|
||||
uint16_t flag_value; // flag value. this is one or sometimes two bytes (maybe more?)
|
||||
std::string reported_strvalue; // original flag descriptions
|
||||
strvalue_list_t strvalues;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const StorageCapability& p);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// holds one line of "attributes" subsection
|
||||
class StorageAttribute {
|
||||
public:
|
||||
|
||||
enum attr_t {
|
||||
attr_type_unknown,
|
||||
attr_type_prefail, // reported: Pre-fail
|
||||
attr_type_oldage // reported: Old_age
|
||||
};
|
||||
|
||||
static std::string get_attr_type_name(attr_t a)
|
||||
{
|
||||
switch (a) {
|
||||
case attr_type_unknown: return "[unknown]";
|
||||
case attr_type_prefail: return "pre-failure";
|
||||
case attr_type_oldage: return "old age";
|
||||
};
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
enum update_t {
|
||||
update_type_unknown,
|
||||
update_type_always, // reported: Always
|
||||
update_type_offline // reported: Offline
|
||||
};
|
||||
|
||||
static std::string get_update_type_name(update_t a)
|
||||
{
|
||||
switch (a) {
|
||||
case update_type_unknown: return "[unknown]";
|
||||
case update_type_always: return "continuously";
|
||||
case update_type_offline: return "on offline data collect.";
|
||||
};
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
enum fail_time_t {
|
||||
fail_time_unknown,
|
||||
fail_time_none, // reported: -
|
||||
fail_time_past, // reported: In_the_past
|
||||
fail_time_now // reported: FAILING_NOW
|
||||
};
|
||||
|
||||
static std::string get_fail_time_name(fail_time_t a)
|
||||
{
|
||||
switch (a) {
|
||||
case fail_time_unknown: return "[unknown]";
|
||||
case fail_time_none: return "never";
|
||||
case fail_time_past: return "in the past";
|
||||
case fail_time_now: return "now";
|
||||
};
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
StorageAttribute() : id(-1), attr_type(attr_type_unknown), update_type(update_type_unknown),
|
||||
when_failed(fail_time_unknown), raw_value_int(0)
|
||||
{ }
|
||||
|
||||
|
||||
int32_t id; ///< Attribute ID (most vendors agree on this)
|
||||
std::string flag; ///< Some have it in 0xXXXX format, others in "PO--C-" format (some WD drives?).
|
||||
hz::OptionalValue<uint8_t> value; ///< Normalized value. May be unset ("---").
|
||||
hz::OptionalValue<uint8_t> worst; ///< Worst ever value. May be unset ("---").
|
||||
hz::OptionalValue<uint8_t> threshold; ///< Threshold for normalized value. May be unset ("---").
|
||||
attr_t attr_type;
|
||||
update_t update_type;
|
||||
fail_time_t when_failed;
|
||||
std::string raw_value; ///< as presented by smartctl (formatted).
|
||||
int64_t raw_value_int; ///< same as raw_value, but parsed as int. original value is 6 bytes I think.
|
||||
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const StorageAttribute& p);
|
||||
|
||||
|
||||
|
||||
|
||||
// holds one error block of "error log" subsection
|
||||
class StorageErrorBlock {
|
||||
public:
|
||||
|
||||
StorageErrorBlock() : error_num(0), lifetime_hours(0)
|
||||
{ }
|
||||
|
||||
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::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")
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const StorageErrorBlock& b);
|
||||
|
||||
|
||||
|
||||
|
||||
// Holds one entry of selftest_log subsection.
|
||||
// Also, holds "Self-test execution status" capability's "internal" section version.
|
||||
class StorageSelftestEntry {
|
||||
public:
|
||||
|
||||
enum status_t {
|
||||
status_unknown, // initial state
|
||||
status_completed_no_error,
|
||||
status_aborted_by_host,
|
||||
status_interrupted,
|
||||
status_fatal_or_unknown, // error
|
||||
status_compl_unknown_failure, // error
|
||||
status_compl_electrical_failure, // error
|
||||
status_compl_servo_failure, // error
|
||||
status_compl_read_failure, // error
|
||||
status_compl_handling_damage, // error
|
||||
status_in_progress,
|
||||
status_reserved
|
||||
};
|
||||
|
||||
enum status_severity_t {
|
||||
severity_none,
|
||||
severity_warn,
|
||||
severity_error
|
||||
};
|
||||
|
||||
static std::string get_status_name(status_t s)
|
||||
{
|
||||
switch (s) {
|
||||
case status_unknown: return "[unknown]";
|
||||
case status_completed_no_error: return "Completed without error";
|
||||
case status_aborted_by_host: return "Manually aborted";
|
||||
case status_interrupted: return "Interrupted (host reset)";
|
||||
case status_fatal_or_unknown: return "Fatal or unknown error";
|
||||
case status_compl_unknown_failure: return "Completed with unknown failure";
|
||||
case status_compl_electrical_failure: return "Completed with electrical failure";
|
||||
case status_compl_servo_failure: return "Completed with servo/seek failure";
|
||||
case status_compl_read_failure: return "Completed with read failure";
|
||||
case status_compl_handling_damage: return "Completed: handling damage";
|
||||
case status_in_progress: return "In progress";
|
||||
case status_reserved: return "Unknown / reserved state";
|
||||
};
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
static status_severity_t get_status_severity(status_t s)
|
||||
{
|
||||
switch (s) {
|
||||
case status_unknown: return severity_none;
|
||||
case status_completed_no_error: return severity_none;
|
||||
case status_aborted_by_host: return severity_warn;
|
||||
case status_interrupted: return severity_warn;
|
||||
case status_fatal_or_unknown: return severity_error;
|
||||
case status_compl_unknown_failure: return severity_error;
|
||||
case status_compl_electrical_failure: return severity_error;
|
||||
case status_compl_servo_failure: return severity_error;
|
||||
case status_compl_read_failure: return severity_error;
|
||||
case status_compl_handling_damage: return severity_error;
|
||||
case status_in_progress: return severity_none;
|
||||
case status_reserved: return severity_none;
|
||||
};
|
||||
return severity_none;
|
||||
}
|
||||
|
||||
StorageSelftestEntry() : test_num(0), status(status_unknown),
|
||||
remaining_percent(-1), lifetime_hours()
|
||||
{ }
|
||||
|
||||
std::string get_status_str() const
|
||||
{
|
||||
return (status == status_unknown ? status_str : get_status_name(status));
|
||||
}
|
||||
|
||||
// test number. always starts from 1. larger means older or newer, depending on model.
|
||||
uint32_t test_num; // 0 for capability.
|
||||
std::string type; // Extended offline, Short offline, Conveyance offline, etc... . capability: unused.
|
||||
std::string status_str; // Self-test routine in progress, Completed without error, etc... (as reported by log or capability)
|
||||
status_t status; // same as above, but from enum
|
||||
int8_t remaining_percent; // %. 0% for completed, 90% for started. -1 if n/a.
|
||||
uint32_t lifetime_hours; // when it happened. capability: unused.
|
||||
std::string lba_of_first_error; // "-" or value (format?). capability: unused.
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const StorageSelftestEntry& b);
|
||||
|
||||
|
||||
|
||||
|
||||
class StorageProperty {
|
||||
|
||||
public:
|
||||
|
||||
// value types
|
||||
enum value_type_t {
|
||||
value_type_unknown, // empty value
|
||||
value_type_string, // string value
|
||||
value_type_integer, // int64
|
||||
value_type_bool, // enabled / disabled, available / not available. passed / not passed.
|
||||
value_type_time_length, // in seconds. e.g. 300 seconds.
|
||||
|
||||
value_type_capability, // for "capabilities" subsection (non-time-interval blocks only)
|
||||
value_type_attribute, // for "attributes" subsection
|
||||
value_type_error_block, // for "error_log" subsection
|
||||
value_type_selftest_entry // for "selftest_log" subsection
|
||||
};
|
||||
|
||||
static std::string get_value_type_name(value_type_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case value_type_unknown: return "empty";
|
||||
case value_type_string: return "string";
|
||||
case value_type_integer: return "integer";
|
||||
case value_type_bool: return "bool";
|
||||
case value_type_time_length: return "time_length";
|
||||
case value_type_capability: return "capability";
|
||||
case value_type_attribute: return "attribute";
|
||||
case value_type_error_block: return "error_block";
|
||||
case value_type_selftest_entry: return "selftest_entry";
|
||||
}
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
// sections in output
|
||||
enum section_t {
|
||||
section_unknown, // use when searching in all sections
|
||||
section_info, // Short info (--info)
|
||||
section_data, // SMART DATA
|
||||
section_internal // internal application-specific data
|
||||
};
|
||||
|
||||
static std::string get_section_name(section_t s)
|
||||
{
|
||||
switch(s) {
|
||||
case section_unknown: return "unknown";
|
||||
case section_info: return "info";
|
||||
case section_data: return "data";
|
||||
case section_internal: return "internal";
|
||||
}
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
// subsections in smart data section
|
||||
enum subsection_t {
|
||||
subsection_unknown, // use when searching in all subsections
|
||||
subsection_health, // overall-health (-H, --health)
|
||||
subsection_capabilities, // General SMART Values, aka Capabilities (-c, --capabilities)
|
||||
subsection_attributes, // Attributes (-A, --attributes). These need decoding.
|
||||
subsection_error_log, // Error Log (-l error)
|
||||
subsection_selftest_log, // Self-test log (-l selftest)
|
||||
subsection_selective_selftest_log // Selective self-test log and settings
|
||||
};
|
||||
|
||||
static std::string get_subsection_name(subsection_t s)
|
||||
{
|
||||
switch(s) {
|
||||
case subsection_unknown: return "unknown";
|
||||
case subsection_health: return "health";
|
||||
case subsection_capabilities: return "capabilities";
|
||||
case subsection_attributes: return "attributes";
|
||||
case subsection_error_log: return "error_log";
|
||||
case subsection_selftest_log: return "selftest_log";
|
||||
case subsection_selective_selftest_log: return "selective_selftest_log";
|
||||
}
|
||||
return "[error]";
|
||||
}
|
||||
|
||||
|
||||
enum warning_t {
|
||||
warning_none,
|
||||
warning_notice, // a known attribute is somewhat disturbing, but no smart error
|
||||
warning_warn, // smart warning is raised by old-age attribute
|
||||
warning_alert // smart warning is raised by pre-fail attribute, and similar errors
|
||||
};
|
||||
|
||||
|
||||
|
||||
StorageProperty()
|
||||
: section(section_unknown), subsection(subsection_unknown),
|
||||
value_type(value_type_unknown), warning(warning_none)
|
||||
{
|
||||
// value_from_db = false;
|
||||
value_integer = 0; // this should nullify all union members
|
||||
}
|
||||
|
||||
|
||||
bool empty() const // empty object - no value set.
|
||||
{
|
||||
return (value_type == value_type_unknown);
|
||||
}
|
||||
|
||||
|
||||
void dump(std::ostream& os, int internal_offset = 0) const;
|
||||
|
||||
|
||||
std::string format_value(bool add_reported_too = false) const;
|
||||
|
||||
|
||||
|
||||
std::string get_description(bool clean = false) const
|
||||
{
|
||||
if (clean)
|
||||
return this->description;
|
||||
return (this->description.empty() ? "No description available" : this->description);
|
||||
}
|
||||
|
||||
|
||||
void set_description(const std::string& descr)
|
||||
{
|
||||
this->description = descr;
|
||||
}
|
||||
|
||||
|
||||
void set_name(const std::string& rep_name, const std::string& gen_name = "", const std::string& read_name = "")
|
||||
{
|
||||
this->reported_name = rep_name;
|
||||
this->generic_name = (gen_name.empty() ? this->reported_name : gen_name);
|
||||
this->readable_name = (read_name.empty() ? this->reported_name : read_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// property name as reported by smartctl.
|
||||
std::string reported_name;
|
||||
// property name. may be same as reported_name, or something more program-identifiable.
|
||||
std::string generic_name;
|
||||
// property name. may be same as reported_name, or something more user-readable. possibly translatable.
|
||||
std::string readable_name;
|
||||
|
||||
std::string description; // description. for tooltips, etc...
|
||||
|
||||
section_t section;
|
||||
subsection_t subsection;
|
||||
|
||||
// bool empty_value; // the property has an empty value
|
||||
// bool value_from_db; // value retrieved from the database, not the drive
|
||||
|
||||
std::string reported_value; // string representation of the value as reported
|
||||
std::string readable_value; // user-friendly readable representation of value. if empty, use others.
|
||||
|
||||
value_type_t value_type;
|
||||
|
||||
std::string value_string;
|
||||
std::string value_version;
|
||||
union {
|
||||
int64_t value_integer;
|
||||
bool value_bool;
|
||||
uint64_t value_time_length; // always in seconds
|
||||
};
|
||||
|
||||
StorageCapability value_capability;
|
||||
StorageAttribute value_attribute;
|
||||
StorageErrorBlock value_error_block;
|
||||
StorageSelftestEntry value_selftest_entry;
|
||||
|
||||
warning_t warning; // warning severity
|
||||
std::string warning_reason; // reason (displayable)
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, const StorageProperty& p)
|
||||
{
|
||||
p.dump(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STORAGE_PROPERTY_DESCR_H
|
||||
#define STORAGE_PROPERTY_DESCR_H
|
||||
|
||||
#include "storage_property.h"
|
||||
|
||||
|
||||
|
||||
bool storage_property_autoset_description(StorageProperty& p);
|
||||
|
||||
StorageProperty::warning_t storage_property_autoset_warning(StorageProperty& p);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,123 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TW_CLI_EXECUTOR_H
|
||||
#define TW_CLI_EXECUTOR_H
|
||||
|
||||
#include "cmdex.h"
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
/// Executor for tw_cli (3ware utility)
|
||||
template<class ExecutorSync>
|
||||
class TwCliExecutorGeneric : public ExecutorSync {
|
||||
|
||||
public:
|
||||
|
||||
TwCliExecutorGeneric(const std::string& cmd, const std::string& cmdargs)
|
||||
: ExecutorSync(cmd, cmdargs)
|
||||
{
|
||||
this->construct();
|
||||
}
|
||||
|
||||
|
||||
TwCliExecutorGeneric()
|
||||
{
|
||||
this->construct();
|
||||
}
|
||||
|
||||
|
||||
virtual ~TwCliExecutorGeneric()
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void construct()
|
||||
{
|
||||
ExecutorSync::cmdex_.set_exit_status_translator(&TwCliExecutorGeneric::translate_exit_status, NULL);
|
||||
this->set_error_header("An error occurred while executing tw_cli:\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::string translate_exit_status(int status, void* user_data)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// import the last error from cmdex_ and clear all errors there
|
||||
virtual void import_error()
|
||||
{
|
||||
Cmdex& cmdex = this->get_command_executor();
|
||||
cmdex.errors_lock();
|
||||
|
||||
Cmdex::error_list_t errors = cmdex.get_errors(false); // these are not clones
|
||||
|
||||
hz::ErrorBase* e = 0;
|
||||
// find the last relevant error.
|
||||
// note: const_reverse_iterator doesn't work on gcc 3, so don't do it.
|
||||
for (Cmdex::error_list_t::reverse_iterator iter = errors.rbegin(); iter != errors.rend(); ++iter) {
|
||||
// ignore iochannel errors, they may mask the real errors
|
||||
if ((*iter)->get_type() != "giochannel" && (*iter)->get_type() != "custom") {
|
||||
e = (*iter)->clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cmdex.clear_errors(false); // and clear them
|
||||
|
||||
cmdex.errors_unlock();
|
||||
|
||||
if (e) { // if error is present, alert the user
|
||||
on_error_warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The warnings are already printed via debug_* in cmdex.
|
||||
virtual void on_error_warn(hz::ErrorBase* e)
|
||||
{
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
// import the error only if it's relevant.
|
||||
std::string error_type = e->get_type();
|
||||
|
||||
// ignore giochannel errors - higher level errors will be triggered, and they more user-friendly.
|
||||
if (error_type == "giochannel" || error_type == "custom") {
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_error_msg(e->get_message());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
typedef TwCliExecutorGeneric<CmdexSync> TwCliExecutor;
|
||||
|
||||
typedef hz::intrusive_ptr<TwCliExecutor> TwCliExecutorRefPtr;
|
||||
|
||||
|
||||
|
||||
typedef TwCliExecutorGeneric<CmdexSyncGui> TwCliExecutorGui;
|
||||
|
||||
typedef hz::intrusive_ptr<TwCliExecutorGui> TwCliExecutorGuiRefPtr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 - 2011 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef GSC_EXECUTOR_LOG_WINDOW_H
|
||||
#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>
|
||||
#include <gtkmm/treemodelcolumn.h>
|
||||
|
||||
#include "applib/app_ui_res_utils.h"
|
||||
#include "applib/cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// use create() / destroy() with this class instead of new / delete!
|
||||
|
||||
class GscExecutorLogWindow : public AppUIResWidget<GscExecutorLogWindow, false> {
|
||||
|
||||
public:
|
||||
|
||||
// name of glade/ui file without a .glade/.ui extension and quotes
|
||||
APP_UI_RES_DATA_INIT(gsc_executor_log_window);
|
||||
|
||||
|
||||
// glade/gtkbuilder needs this constructor
|
||||
GscExecutorLogWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& ref_ui);
|
||||
|
||||
|
||||
virtual ~GscExecutorLogWindow()
|
||||
{ }
|
||||
|
||||
|
||||
// Show this window and select the last entry
|
||||
void show_last();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Data
|
||||
|
||||
std::vector<CmdexSyncCommandInfoRefPtr> entries;
|
||||
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore> list_store;
|
||||
Glib::RefPtr<Gtk::TreeSelection> selection;
|
||||
|
||||
Gtk::TreeModelColumn<std::size_t> col_num;
|
||||
Gtk::TreeModelColumn<std::string> col_command;
|
||||
Gtk::TreeModelColumn<CmdexSyncCommandInfoRefPtr> col_entry;
|
||||
|
||||
|
||||
void clear_view_widgets(); // clear entries and textviews
|
||||
|
||||
|
||||
|
||||
// -------------------- Callbacks
|
||||
|
||||
// Attached to external source
|
||||
void on_command_output_received(const CmdexSyncCommandInfo& info);
|
||||
|
||||
|
||||
|
||||
// ---------- override virtual methods
|
||||
|
||||
bool on_delete_event_before(GdkEventAny* e)
|
||||
{
|
||||
this->hide(); // hide only, don't destroy
|
||||
return true; // event handled, don't call default virtual handler
|
||||
}
|
||||
|
||||
|
||||
// ---------- other callbacks
|
||||
|
||||
void on_window_close_button_clicked()
|
||||
{
|
||||
this->hide(); // hide only, don't destroy
|
||||
}
|
||||
|
||||
|
||||
void on_window_save_current_button_clicked();
|
||||
|
||||
|
||||
void on_window_save_all_button_clicked();
|
||||
|
||||
|
||||
void on_clear_command_list_button_clicked();
|
||||
|
||||
|
||||
void on_tree_selection_changed();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||