Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
042111b3a2 | ||
|
|
3a181b6880 |
@@ -18,12 +18,18 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
See LICENSE_gpl2.txt and LICENSE_gpl3.txt for details.
|
||||
|
||||
|
||||
All files which don't have any copyright notices, tests and examples are
|
||||
covered under the Whatever License. See LICENSE_whatever.txt for details.
|
||||
|
||||
|
||||
Portions of this software are copyright Google Inc. See LICENSE_pcrecpp.txt
|
||||
for details.
|
||||
|
||||
|
||||
This product includes the HZ library (or portions of it). See LICENSE_hz.txt
|
||||
for details.
|
||||
|
||||
|
||||
This product includes icons from Crystal Project,
|
||||
copyright 2006-2007 Everaldo Coelho.
|
||||
http://www.everaldo.com/crystal, http://www.yellowicon.com .
|
||||
@@ -4,21 +4,33 @@ HZ Library License
|
||||
The HZ library contains software licensed under several different licenses.
|
||||
This is due to HZ including portions of other software.
|
||||
|
||||
All original code is licensed under the Zlib License. See LICENSE_zlib.txt for
|
||||
details.
|
||||
|
||||
Portions of this software are copyright Regents of the University of California,
|
||||
see LICENSE_bsd-ucb.txt for details.
|
||||
All original code (except for the tests) is licensed under the Zlib License.
|
||||
See LICENSE_zlib.txt for details.
|
||||
|
||||
|
||||
All tests and examples are covered under the Whatever License. See
|
||||
LICENSE_whatever.txt for details.
|
||||
|
||||
|
||||
Portions of this software are copyright Regents of the University of
|
||||
California, see LICENSE_bsd-ucb.txt for details.
|
||||
|
||||
|
||||
Portions of this software are licensed under Boost Software License, see
|
||||
LICENSE_boost_1_0.txt and individual source files for copyright information.
|
||||
|
||||
|
||||
Each source file contains its copyright information.
|
||||
|
||||
If you intend to use HZ in your product, please note that you MUST include
|
||||
these licenses somewhere in your distribution (simply redistributing the
|
||||
license files or reproducing their texts in documentation and/or other supplied
|
||||
materials is OK):
|
||||
license files or reproducing their texts in documentation and/or other
|
||||
supplied materials is OK):
|
||||
* LICENSE_zlib.txt (source distributions only);
|
||||
* LICENSE_bsd-ucb.txt (source and binary distributions);
|
||||
* LICENSE_boost_1_0.txt (source distributions only).
|
||||
|
||||
If you use only portions of HZ, you may ignore this requirement for files you
|
||||
don't use. For example, if you don't use any of the Boost-licensed files, you
|
||||
are not required to distribute the Boost license.
|
||||
@@ -0,0 +1,12 @@
|
||||
Whatever License
|
||||
|
||||
THIS SOFTWARE IS PROVIDED 'AS-IS', WITHOUT ANY EXPRESS OR IMPLIED
|
||||
WARRANTY. IN NO EVENT WILL THE AUTHORS BE HELD LIABLE FOR ANY DAMAGES
|
||||
ARISING FROM THE USE OF THIS SOFTWARE.
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely.
|
||||
@@ -22,6 +22,7 @@ dist_doc_DATA = AUTHORS.txt ChangeLog NEWS README.txt \
|
||||
LICENSE_gsmartcontrol.txt \
|
||||
LICENSE_hz.txt \
|
||||
LICENSE_pcrecpp.txt \
|
||||
LICENSE_whatever.txt \
|
||||
LICENSE_zlib.txt
|
||||
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
|
||||
Version 0.8.0rc4, released on 2008-10-20
|
||||
FreeBSD support (tested with DesktopBSD 1.6 (FreeBSD 6.3) / x86).
|
||||
NetBSD support (tested with NetBSD 4.0.1 / x86).
|
||||
OpenBSD support (tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5).
|
||||
Solaris/gcc support (tested with Solaris 10 / x86 / gcc-3.4.3 / blastwave).
|
||||
Solaris/sunstudio support (tested with Solaris 10 / x86 / sunstudio12 / sunfreeware).
|
||||
Code to support Windows, Mac OS X, QNX.
|
||||
Support of older pcre versions (at least 4.5, maybe older too).
|
||||
Added gsmartcontrol_root.sh script to easily run gsmartcontrol as root.
|
||||
Improved .desktop files.
|
||||
License for tests and examples is legally more correct now.
|
||||
Minor bugfixes.
|
||||
|
||||
Version 0.8.0rc3, released on 2008-10-08
|
||||
Added support for udevless Linux distributions by providing a fallback
|
||||
/proc/partitions-based drive detection method. The new method adds
|
||||
@@ -35,6 +35,8 @@ Perform SMART self-tests.
|
||||
Ability to load smartctl output as a "virtual" device, which acts just like a
|
||||
real (read-only) device.
|
||||
|
||||
Works on most smartctl-supported operating systems.
|
||||
|
||||
Extensive help information.
|
||||
|
||||
|
||||
@@ -86,8 +88,6 @@ these bugs and works around them.
|
||||
|
||||
Software Requirements
|
||||
|
||||
So far, only Linux systems are supported.
|
||||
|
||||
You need to have the following software installed:
|
||||
|
||||
* pcre - http://www.pcre.org .
|
||||
@@ -110,6 +110,33 @@ example, to build this program on OpenSUSE, you just need to install
|
||||
smartmontools, gtkmm2-devel and pcre-devel - the rest is installed
|
||||
automatically by the package manager's dependency resolver.
|
||||
|
||||
The following operating systems are supported:
|
||||
|
||||
* Linux - All the popular configurations should work.
|
||||
|
||||
* FreeBSD - Tested with DesktopBSD 1.6 (FreeBSD 6.3) / x86.
|
||||
|
||||
* NetBSD - Tested with NetBSD 4.0.1 / x86.
|
||||
|
||||
* OpenBSD - Tested with OpenBSD 4.3 / x86-64 / gcc-3.3.5.
|
||||
|
||||
* Solaris - Tested with Solaris 10 / x86 / gcc-3.4.3 / blastwave,
|
||||
Solaris 10 / x86 / sunstudio12 / sunfreeware. OpenSolaris should work but has
|
||||
not been tested yet. Note that until either smartctl gets ATA support under
|
||||
Solaris or GSmartControl gets SCSI support, these configurations are
|
||||
essentially useless.
|
||||
|
||||
* DragonFlyBSD - Code written but no testing has been performed yet. Expected
|
||||
to work without any issues.
|
||||
|
||||
* Windows (NT line only) - Only minimal testing has been performed. Expected
|
||||
to work. The Windows port uses /dev/pd0, /dev/pd1, etc... for physical drives
|
||||
0, 1, etc... .
|
||||
|
||||
* Mac OS X - Code written but no testing has been performed yet.
|
||||
|
||||
* QNX - Code written but no testing has been performed yet.
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
@@ -120,9 +147,9 @@ Long answer: read below.
|
||||
|
||||
First, check if you can find a pre-built package for your distribution or
|
||||
operating system - they usually provide the best integration and the easiest
|
||||
installation procedure. One option is to try OpenSUSE Build Service - it
|
||||
provides ready-to-install packages for various popular Linux distributions
|
||||
(OpenSUSE, Fedora, etc...). See
|
||||
installation procedure. For Linux, one option is to try the OpenSUSE Build
|
||||
Service - it provides ready-to-install packages for various popular Linux
|
||||
distributions (OpenSUSE, Fedora, etc...). See
|
||||
http://download.opensuse.org/repositories/home:/alex_sh/ .
|
||||
|
||||
If you want to compile from source, check that you have all the required
|
||||
@@ -130,15 +157,16 @@ dependencies (see Software Requirements section). Then the usual
|
||||
|
||||
./configure; make; make install
|
||||
|
||||
will build and install it. Installation usually requires root privileges, but
|
||||
you don't need to install the program in order to run it directly from the
|
||||
compilation directory.
|
||||
will build and install it. Installation usually requires adminstrative
|
||||
privileges, but you don't need to install the program in order to run it
|
||||
directly from the compilation directory.
|
||||
|
||||
|
||||
|
||||
Permission Problems
|
||||
|
||||
Short answer: you need to be root. In X11, use kdesu, gnomesu, sux or similar.
|
||||
Short answer: you need to be root (Administrator in Windows).
|
||||
In X11, use kdesu, gnomesu, sux, xdg-su or similar.
|
||||
|
||||
Long answer: read below.
|
||||
|
||||
@@ -146,29 +174,25 @@ Most operating systems prohibit direct access to hardware to users with
|
||||
non-administrative privileges. Unfortunately, to access SMART data, smartctl
|
||||
needs to directly access the hard drive.
|
||||
|
||||
The provided desktop and menu icons should show the "Please enter the root
|
||||
The provided X11 desktop and menu icons should show the "Please enter the root
|
||||
password" dialog boxes, and, after correct information is entered, should run
|
||||
this program with root privileges. The dialogs should be available in most
|
||||
commonly used X11 desktop environments.
|
||||
|
||||
However, in case the described method is somehow inaccessible, you need to
|
||||
manually invoke the program with kdesu, gnomesu, sux or similar programs. For
|
||||
example,
|
||||
Another way is to use the included gsmartcontrol_root.sh script, which finds
|
||||
the available su program and runs gsmartcontrol with it.
|
||||
|
||||
Yet another way is to manually invoke the program with kdesu, gnomesu, sux or
|
||||
similar programs. For example,
|
||||
|
||||
kdesu -u root -c gsmartcontrol
|
||||
|
||||
will ask for root password and run gsmartcontrol with root privileges. Replace
|
||||
"kdesu" with "gnomesu" if using Gnome. The "sux" command may also help, if
|
||||
neither KDE or GNOME are available.
|
||||
"kdesu" with "gnomesu" if using Gnome. The "sux" or "xdg-su" commands may also
|
||||
help, if neither KDE or GNOME are available.
|
||||
|
||||
Another method would be to set the "setuid" flag on smartctl binary, for
|
||||
example (run as root):
|
||||
|
||||
chmod 4755 `which smartctl`
|
||||
|
||||
This method is not recommended, however, and is considered a security risk.
|
||||
Also, some systems may reset the change automatically, unless explicitly
|
||||
instructed otherwise.
|
||||
Please don't set the "setuid" flag on smartctl binary. It is considered a
|
||||
security risk.
|
||||
|
||||
|
||||
|
||||
@@ -210,7 +234,7 @@ have X11 / Gtkmm running, so this is a low priority task.
|
||||
* I only have ATA drives, so testing would be almost impossible.
|
||||
|
||||
Immediate Offline Tests are not supported. I haven't found a way to reliably
|
||||
monitor them.
|
||||
monitor them yet.
|
||||
|
||||
You may run several tests on different drives in parallel, but you will only
|
||||
see the progress information of the last executing test. So, if you run tests
|
||||
@@ -234,20 +258,30 @@ language and all.
|
||||
|
||||
Reporting Bugs
|
||||
|
||||
First, please collect the following information about your system. Without it
|
||||
it may be very hard or impossible to fix the bug.
|
||||
If it is a SMART or drive-related problem, please try to test it with smartctl
|
||||
first. Chances are, the problem you're experiencing is not tied to
|
||||
GSmartControl, but is a drive firmware or smartctl problem. For example, to
|
||||
see a complete information about your /dev/sda drive, type the following in a
|
||||
terminal emulator (e.g., xterm, konsole or gnome-terminal):
|
||||
|
||||
smartctl -a /dev/sda
|
||||
|
||||
If you still think it's a GSmartControl issue, please collect the following
|
||||
information about your system. Without it, it may be very hard or impossible
|
||||
to fix the bug.
|
||||
|
||||
* Which operating system you use (for example, OpenSUSE Linux 11.0).
|
||||
|
||||
* What version of GTK and Gtkmm you have installed. Finding this out is very
|
||||
* Which version of GTK and Gtkmm you have installed. Finding this out is very
|
||||
distribution-specific. For example, on OpenSUSE it would be
|
||||
"rpm -q gtk2 gtkmm2". Some distributions have gtkmm24 instead. You may also
|
||||
search them in your distribution's graphical package manager, if there is one.
|
||||
|
||||
* Execution log from the program, if possible. To obtain it, run the program
|
||||
with -v option, e.g. (type the following in terminal emulator or Run dialog):
|
||||
with -v option, e.g. (type the following in a terminal emulator or Run
|
||||
dialog):
|
||||
|
||||
kdesu -- biocalcon -v
|
||||
gsmartcontrol_root.sh other -v
|
||||
|
||||
Perform the steps needed to reproduce the bug, then go to
|
||||
"Options -> View Execution Log", and click "Save All".
|
||||
@@ -19,6 +19,14 @@ A treeview (also iconview, combobox) from glade comes
|
||||
with existing model, which should be unset
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
portability:
|
||||
win32 32-bit: int: 4, long: 4, pointer: 4.
|
||||
win32 64-bit: int: 4, long: 8, pointer: 8.
|
||||
|
||||
sparc: same as win32 (what about OS?).
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
GTKMM problems:
|
||||
@@ -34,43 +42,22 @@ no ComboBox::unset_model() and IconView::unset_model().
|
||||
--------------------------------------------------------
|
||||
|
||||
TODO:
|
||||
if -q is passed, Execution log doesn't contain libdebug log. fix.
|
||||
|
||||
|
||||
Drive detection - any cross-platform way to do it?
|
||||
|
||||
|
||||
FreeBSD: /dev/ad[0-3], partitions - /dev/ad[]
|
||||
http://www.freebsd.org/doc/en/books/handbook/disks-naming.html
|
||||
Non-existent devices give ENXIO (6, Device not configured).
|
||||
In Linux ENXIO has name (6, No such device or address).
|
||||
/dev/ad0s1b none swap sw 0 0
|
||||
/dev/ad0s1a / ufs rw 1 1
|
||||
/dev/acd0c /cdrom cd9660 ro,noauto 0 0
|
||||
Do NOT open cd devices - it may cause hang on music cd, etc... .
|
||||
|
||||
In the slice case the drive will be added as /dev/da1s1e. This is read as:
|
||||
SCSI disk, unit number 1 (second SCSI disk), slice 1 (PC BIOS partition 1),
|
||||
and e BSD partition. In the dedicated case, the drive will be added simply as /dev/da1e.
|
||||
|
||||
|
||||
iphone:
|
||||
/dev/disk0
|
||||
/dev/disk0s1, /dev/disk0s2
|
||||
|
||||
|
||||
|
||||
libdebug:
|
||||
per-channel disabling.
|
||||
per-channel formatting.
|
||||
all flags should be per-channel.
|
||||
bug: if -q is passed, Execution log doesn't contain libdebug log. (requires per-channel status control).
|
||||
|
||||
desktop files: gnomesu / gtksu wrapper.
|
||||
desktop_other - find suitable su.
|
||||
|
||||
|
||||
|
||||
|
||||
----------- Feature List ----------
|
||||
|
||||
+Autodetect available devices (through /proc / /sys ?).
|
||||
win32 support for autodetection (what about different smartctl drivers?).
|
||||
+Autodetect available devices
|
||||
|
||||
+Select current device (from autodetected list; manually whitelist devices).
|
||||
|
||||
@@ -117,7 +104,7 @@ SCT Temperatures (do we use these?)
|
||||
This configures temperature logging interval (1 min by default) and clears the history.
|
||||
|
||||
|
||||
Tests:
|
||||
+Tests:
|
||||
Ability to detect a testing drive on boot, show its info with testing tab.
|
||||
|
||||
Run one-time Immediate Offline test (-t offline).
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_AUTO_CLEAR_FLAGS()
|
||||
# Clear user-specified CFLAGS / CXXFLAGS / LIBS / LDFLAGS if requested.
|
||||
|
||||
# You should call this macro before any of AC_PROG_C(XX) checks to
|
||||
# avoid checking with user-specified options.
|
||||
|
||||
AC_DEFUN([APP_AUTO_CLEAR_FLAGS], [
|
||||
|
||||
AC_ARG_ENABLE(user-flags, AS_HELP_STRING([--disable-user-flags],
|
||||
[ignore user-supplied compiler flags (default: user flags are enabled)]),
|
||||
[app_cv_compiler_user_flags=${enableval}], [app_cv_compiler_user_flags=yes])
|
||||
|
||||
AC_MSG_NOTICE([Enable user-specified compiler flags: $app_cv_compiler_user_flags])
|
||||
|
||||
# Reset user-supplied flags if requested.
|
||||
if test "x$app_cv_compiler_user_flags" = "xno"; then
|
||||
CFLAGS="";
|
||||
CXXFLAGS="";
|
||||
LIBS="";
|
||||
LDFLAGS="";
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_CHOOSE_GLD_READER([C|C++][, flags_prefix])
|
||||
# This macro detects whether GtkBuilder (from gtk >= 2.12) or libglade
|
||||
# are present. If the first parameter is C++, then gtkmm and libglademm
|
||||
# are searched for instead.
|
||||
# flags_prefixCFLAGS, flags_prefixCXXFLAGS and flags_prefixLIBS
|
||||
# will be initialized (or appended to) with the correct flags in case of libglade(mm).
|
||||
# app_cv_gld_reader will be set to none, libglade or gtkbuilder.
|
||||
|
||||
# ENABLE_LIBGLADE or ENABLE_GTKBUILDER will be exported to config.h
|
||||
|
||||
# You must call AX_COMPILER_VENDOR before using this macro.
|
||||
|
||||
AC_DEFUN([APP_CHOOSE_GLD_READER], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
# This is just in case
|
||||
# PKG_PROG_PKG_CONFIG()
|
||||
|
||||
# this variable will have values "none", "libglade" or "gtkbuilder".
|
||||
app_cv_gld_reader="none";
|
||||
|
||||
# in case libglade(mm) is found, these will contain the flags.
|
||||
app_cv_gld_reader_CFLAGS="";
|
||||
app_cv_gld_reader_CXXFLAGS="";
|
||||
app_cv_gld_reader_LIBS="";
|
||||
|
||||
app_cv_gld_reader_libglade_name="libglade";
|
||||
app_cv_gld_reader_libglade_pkg_name="libglade-2.0";
|
||||
app_cv_gld_reader_gtk_name="gtk";
|
||||
app_cv_gld_reader_gtk_pkg_name="gtk+-2.0";
|
||||
if test "x$1" = "xC++"; then
|
||||
app_cv_gld_reader_libglade_name="libglademm";
|
||||
app_cv_gld_reader_libglade_pkg_name="libglademm-2.4";
|
||||
app_cv_gld_reader_gtk_name="gtkmm";
|
||||
app_cv_gld_reader_gtk_pkg_name="gtkmm-2.4";
|
||||
fi
|
||||
|
||||
|
||||
# Manual control. AC_ARG_ENABLE doesn't get bash variables, so we have
|
||||
# to do it this way. If put inside a shell conditional, it still shows up in configure help.
|
||||
|
||||
AC_ARG_ENABLE(libglade, AS_HELP_STRING([--enable-libglade],
|
||||
[use libglade(mm) instead of GtkBuilder (default: auto)]),
|
||||
[with_libglade=${enableval}], [with_libglade=auto])
|
||||
|
||||
|
||||
# Try gtkbuilder first
|
||||
if test "x$with_libglade" = "xno" || test "x$with_libglade" = "xauto"; then
|
||||
PKG_CHECK_EXISTS([$app_cv_gld_reader_gtk_pkg_name >= 2.12.0],
|
||||
[app_cv_gld_reader="gtkbuilder"])
|
||||
fi
|
||||
if test "$with_libglade" = "no" && test "$app_cv_gld_reader" = "none"; then
|
||||
AC_MSG_ERROR([GtkBuilder support not found (you need $app_cv_gld_reader_gtk_name version 2.12 or higher). Try using $app_cv_gld_reader_libglade_name instead.])
|
||||
fi
|
||||
|
||||
# libglade specified, or auto and no gtkbuilder. gtkmm2.4-compatible libglademm is >= 2.4.0.
|
||||
# (not sure about libglade version).
|
||||
if test "x$app_cv_gld_reader" = "xnone"; then
|
||||
PKG_CHECK_MODULES([app_cv_gld_reader], [$app_cv_gld_reader_libglade_pkg_name >= 2.4.0],
|
||||
[app_cv_gld_reader="libglade"], [AC_MSG_WARN([$LIBGLADE_PKG_ERRORS])])
|
||||
fi
|
||||
|
||||
if test "x$with_libglade" = "xyes" && test "x$app_cv_gld_reader" = "xnone"; then
|
||||
AC_MSG_ERROR([$app_cv_gld_reader_libglade_name not found. Try building with GtkBuilder support (you need $app_cv_gld_reader_gtk_name version 2.12 or higher).])
|
||||
fi
|
||||
|
||||
# still not found.
|
||||
if test "$app_cv_gld_reader" = "none"; then
|
||||
AC_MSG_WARN([Neither GtkBuilder nor $app_cv_gld_reader_libglade_name found. The program will be unable to compile fully.])
|
||||
fi
|
||||
|
||||
|
||||
# pkg-config doesn't do CXXFLAGS, so do it manually.
|
||||
app_cv_gld_reader_CXXFLAGS="$app_cv_gld_reader_CFLAGS";
|
||||
|
||||
# if using libglademm, it doesn't make any sense to leave the flags for C.
|
||||
if test "x$1" = "xC++"; then
|
||||
app_cv_gld_reader_CFLAGS="";
|
||||
fi
|
||||
|
||||
|
||||
# export the flags
|
||||
if test "x$2" != "x"; then
|
||||
if test "x$$2[]CFLAGS" = "x"; then
|
||||
$2[]CFLAGS="$app_cv_gld_reader_CFLAGS";
|
||||
else
|
||||
$2[]CFLAGS="$$2[]CFLAGS $app_cv_gld_reader_CFLAGS";
|
||||
fi
|
||||
if test "x$$2[]CXXFLAGS" = "x"; then
|
||||
$2[]CXXFLAGS="$app_cv_gld_reader_CXXFLAGS";
|
||||
else
|
||||
$2[]CXXFLAGS="$$2[]CXXFLAGS $app_cv_gld_reader_CXXFLAGS";
|
||||
fi
|
||||
if test "x$$2[]LIBS" = "x"; then
|
||||
$2[]LIBS="$app_cv_gld_reader_LIBS";
|
||||
else
|
||||
$2[]LIBS="$$2[]LIBS $app_cv_gld_reader_LIBS";
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# export to automake.am-s
|
||||
AM_CONDITIONAL([ENABLE_LIBGLADE], [test "$app_cv_gld_reader" = "libglade"])
|
||||
AM_CONDITIONAL([ENABLE_GTKBUILDER], [test "$app_cv_gld_reader" = "gtkbuilder"])
|
||||
|
||||
|
||||
# export to config.h
|
||||
if test "$app_cv_gld_reader" = "libglade"; then
|
||||
AC_DEFINE(ENABLE_LIBGLADE, 1, [Use libglade(mm) instead of GtkBuilder])
|
||||
fi
|
||||
if test "$app_cv_gld_reader" = "gtkbuilder"; then
|
||||
AC_DEFINE(ENABLE_GTKBUILDER, 1, [Use GtkBuilder instead of libglademm])
|
||||
fi
|
||||
|
||||
# If we move this to the start, some messages get in between, so we have to have it here.
|
||||
AC_MSG_CHECKING([for glade file support:])
|
||||
|
||||
AC_MSG_RESULT([$app_cv_gld_reader])
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_COMPILER_OPTIONS([flags_prefix])
|
||||
# This macro enables various compiler flags (common warnings, optimization,
|
||||
# debug, etc...), controllable through configure options.
|
||||
# flags_prefixCFLAGS, flags_prefixCXXFLAGS and flags_prefixLDFLAGS
|
||||
# will be initialized (or appended to) with the results.
|
||||
|
||||
# DEBUG and DEBUG_BUILD will be exported to config.h in case of debug builds.
|
||||
|
||||
# You must call AX_COMPILER_VENDOR, APP_DETECT_OS_KERNEL([target], ...)
|
||||
# and APP_DETECT_OS_ENV([target], ...) before using this macro.
|
||||
|
||||
AC_DEFUN([APP_COMPILER_OPTIONS], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
AC_REQUIRE([APP_DETECT_OS_ENV])
|
||||
|
||||
app_cv_compiler_options_cflags="";
|
||||
app_cv_compiler_options_cxxflags="";
|
||||
app_cv_compiler_options_ldflags="";
|
||||
|
||||
|
||||
# ---- 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)]),
|
||||
[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.
|
||||
if test "x$app_cv_compiler_common_options" = "xyes" || test "x$app_cv_compiler_common_options" = "xauto"; then
|
||||
app_cv_compiler_common_options="$ax_cv_cxx_compiler_vendor";
|
||||
fi
|
||||
|
||||
if test "x$app_cv_compiler_common_options" = "xno"; then
|
||||
# for pretty message
|
||||
app_cv_compiler_common_options="none";
|
||||
fi
|
||||
AC_MSG_NOTICE([Enable common compiler flags for: $app_cv_compiler_common_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
|
||||
|
||||
if test "x$app_cv_target_os_env" = "xmingw" || test "x$app_cv_target_os_env" = "xcygwin"; then
|
||||
# mingw gcc options:
|
||||
# -mno-cygwin - generate non-cygwin executables in cygwin's mingw.
|
||||
# -mwindows - hide console window. possibly suppresses any std output / error.
|
||||
# -mms-bitfields - make structures compatible with msvc. recommended default for non-cygwin.
|
||||
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -mms-bitfields -mwindows"
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -mms-bitfields -mwindows"
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -mms-bitfields -mwindows"
|
||||
fi
|
||||
|
||||
# Note: Disabled -Wconversion, it was causing lots of silly warnings under x86-64.
|
||||
app_cv_compiler_tmp_var="-Wall -Wcast-align -Wcast-qual \
|
||||
-Wctor-dtor-privacy -Wfloat-equal -Wnon-virtual-dtor -Woverloaded-virtual \
|
||||
-Wpointer-arith -Wshadow -Wsign-compare -Wsign-promo -Wundef -Wwrite-strings";
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags $app_cv_compiler_tmp_var";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags $app_cv_compiler_tmp_var";
|
||||
|
||||
# intel / gnu environment
|
||||
elif test "x$app_cv_compiler_common_options" = "xintel" && test "x$app_cv_target_os_env" = "xgnu"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -w1";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags \
|
||||
-ftrapuv -fstack-security-check -early-template-check -static-libgcc -static-intel \
|
||||
-Wcomment -Wdeprecated -Wextra-tokens -Wformat -Wmissing-prototypes -Wnon-virtual-dtor \
|
||||
-Wpointer-arith -Wreturn-type -Wshadow -Wtrigraphs -Wuninitialized -w1";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -static-libgcc -static-intel";
|
||||
|
||||
# suncc
|
||||
elif test "x$app_cv_compiler_common_options" = "xsun"; then
|
||||
# Enable useful language extensions (e.g. __func__ in C++). Details at
|
||||
# http://docs.sun.com/app/docs/doc/819-5267/6n7c46drp?a=view
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags \
|
||||
+w -errtags -erroff=notemsource,notused -features=extensions";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags \
|
||||
+w -errtags -erroff=notemsource,notused -features=extensions";
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# ---- 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)]),
|
||||
[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.
|
||||
if test "x$app_cv_compiler_debug_options" = "xyes" || test "x$app_cv_compiler_debug_options" = "xauto"; then
|
||||
app_cv_compiler_debug_options="$ax_cv_cxx_compiler_vendor";
|
||||
fi
|
||||
|
||||
if test "x$app_cv_compiler_debug_options" = "xno"; then
|
||||
# for pretty message
|
||||
app_cv_compiler_debug_options="none";
|
||||
fi
|
||||
AC_MSG_NOTICE([Enable debug build flags for: $app_cv_compiler_debug_options])
|
||||
|
||||
|
||||
if test "x$app_cv_compiler_debug_options" != "xnone"; then
|
||||
|
||||
# Define DEBUG and DEBUG_BUILD for debug builds (through config.h).
|
||||
AC_DEFINE([DEBUG], [1], [Defined for debug builds])
|
||||
AC_DEFINE([DEBUG_BUILD], [1], [Defined for debug builds])
|
||||
|
||||
# gcc, mingw
|
||||
if test "x$app_cv_compiler_debug_options" = "xgnu"; 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";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g3 -O0";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g3 -O0";
|
||||
|
||||
# intel / gnu
|
||||
elif test "x$app_cv_compiler_debug_options" = "xintel" && test "x$app_cv_target_os_env" = "xgnu"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g3 -O0";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g3 -O0";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g3 -O0";
|
||||
|
||||
# suncc
|
||||
elif test "x$app_cv_compiler_debug_options" = "xsun"; then
|
||||
# There's no -O0, it's the default. Debug format is stabs by default, but can be switched
|
||||
# to dwarf by -xdebugformat=dwarf.
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -xs -g";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -xs -g";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -xs -g";
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# ---- 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)]),
|
||||
[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.
|
||||
if test "x$app_cv_compiler_optimize_options" = "xyes" || test "x$app_cv_compiler_optimize_options" = "xauto"; then
|
||||
app_cv_compiler_optimize_options="$ax_cv_cxx_compiler_vendor";
|
||||
fi
|
||||
|
||||
if test "x$app_cv_compiler_optimize_options" = "xno"; then
|
||||
# for pretty message
|
||||
app_cv_compiler_optimize_options="none";
|
||||
fi
|
||||
AC_MSG_NOTICE([Enable optimized build flags for: $app_cv_compiler_optimize_options])
|
||||
|
||||
|
||||
if test "x$app_cv_compiler_optimize_options" != "xnone"; then
|
||||
|
||||
# gcc, mingw
|
||||
if test "x$app_cv_compiler_optimize_options" = "xgnu"; then
|
||||
# -mtune=generic is since gcc 4.0 iirc
|
||||
if test "$app_cv_target_os_env" = "mingw" || test "$app_cv_target_os_env" = "cygwin"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s -march=i586";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s -march=i586";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s -march=i586";
|
||||
else
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s -mtune=generic";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s -mtune=generic";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s -mtune=generic";
|
||||
fi
|
||||
|
||||
# intel / gnu
|
||||
elif test "x$app_cv_compiler_optimize_options" = "xintel" && test "x$app_cv_target_os_env" = "xgnu"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -g0 -O3 -s";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -g0 -O3 -s";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -g0 -O3 -s";
|
||||
|
||||
# suncc
|
||||
elif test "x$app_cv_compiler_optimize_options" = "xsun"; then
|
||||
# There's no -O0, it's the default. Debug format is stabs by default, but can be switched
|
||||
# to dwarf by -xdebugformat=dwarf.
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -xO5";
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -xO5";
|
||||
app_cv_compiler_options_ldflags="$app_cv_compiler_options_ldflags -s";
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# ---- Compiler options for GCC pch support
|
||||
|
||||
AC_ARG_ENABLE(gcc-pch,
|
||||
AS_HELP_STRING([--enable-gcc-pch],[enable precompiled header support (pch make target) (GCC only) (default: disabled)
|
||||
(use "make gch" to speed up the compilation, but don't enable it if you don't intend to use it - it will slow things down)]),
|
||||
[app_cv_compiler_gcc_pch=${enableval}], [app_cv_compiler_gcc_pch=no])
|
||||
|
||||
AC_MSG_NOTICE([Enable GCC precompiled header usage: $app_cv_compiler_gcc_pch])
|
||||
|
||||
# Don't check the vendor here - it's disabled by default, so it's on the user.
|
||||
if test "x$app_cv_compiler_gcc_pch" = "xyes"; then
|
||||
app_cv_compiler_options_cflags="$app_cv_compiler_options_cflags -Winvalid-pch -DENABLE_PCH"
|
||||
app_cv_compiler_options_cxxflags="$app_cv_compiler_options_cxxflags -Winvalid-pch -DENABLE_PCH"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# ---- Export our variables
|
||||
|
||||
if test "x$$1[]CFLAGS" = "x"; then
|
||||
$1[]CFLAGS="$app_cv_compiler_options_cflags";
|
||||
else
|
||||
$1[]CFLAGS="$$1[]CFLAGS $app_cv_compiler_options_cflags";
|
||||
fi
|
||||
if test "x$$1[]CXXFLAGS" = "x"; then
|
||||
$1[]CXXFLAGS="$app_cv_compiler_options_cxxflags";
|
||||
else
|
||||
$1[]CXXFLAGS="$$1[]CXXFLAGS $app_cv_compiler_options_cxxflags";
|
||||
fi
|
||||
if test "x$$1[]LDFLAGS" = "x"; then
|
||||
$1[]LDFLAGS="$app_cv_compiler_options_ldflags";
|
||||
else
|
||||
$1[]LDFLAGS="$$1[]LDFLAGS $app_cv_compiler_options_ldflags";
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_NOTICE([Compiler-specific build options:])
|
||||
AC_MSG_NOTICE([CFLAGS: $app_cv_compiler_options_cflags])
|
||||
AC_MSG_NOTICE([CXXFLAGS: $app_cv_compiler_options_cxxflags])
|
||||
AC_MSG_NOTICE([LDFLAGS: $app_cv_compiler_options_ldflags])
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports overloading between
|
||||
# extern "C" function pointer and C++ function pointer. GCC and
|
||||
# Intel treat them equally, so no overloads are needed (or accepted)
|
||||
# there.
|
||||
|
||||
# SunCC accepts C++-to-C function pointer assignment in function
|
||||
# parameters, but not in constructor parameters. To make such
|
||||
# code work an additional C-function-pointer constructor must be
|
||||
# specified. Then the constructor itself can make the conversion
|
||||
# (with a compiler warning though).
|
||||
|
||||
# SunCC also disallows C-to-C++ function pointer specification
|
||||
# for template parameters (I don't remember the exact details).
|
||||
|
||||
|
||||
# If such support is found, HAVE_CXX_EXTERN_C_OVERLOAD is defined.
|
||||
|
||||
|
||||
AC_DEFUN([APP_CXX_EXTERN_C_OVERLOAD], [
|
||||
AC_CACHE_CHECK(whether $CXX accepts extern C function pointer overload, ac_cv_cxx_extern_c_overload, [
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
extern "C" { typedef void (*c_func_t)(void); }
|
||||
typedef void (*cpp_func_t)(void);
|
||||
void f1(c_func_t f) { }
|
||||
void f1(cpp_func_t f) { }
|
||||
]], [[]])],
|
||||
[ac_cv_cxx_extern_c_overload=yes], [ac_cv_cxx_extern_c_overload=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$ac_cv_cxx_extern_c_overload" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX_EXTERN_C_OVERLOAD, ,
|
||||
[Define if the C++ complier accepts extern C function pointer overload])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# Check whether C++ compiler supports C99 __func__.
|
||||
|
||||
AC_DEFUN([APP_CXX___FUNC__], [
|
||||
AC_CACHE_CHECK(whether $CXX recognizes __func__, app_cv_cxx___func__, [
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
[[const char* s = __func__;]])],
|
||||
[app_cv_cxx___func__=yes], [app_cv_cxx___func__=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___func__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___func__, ,
|
||||
[Define if the C++ complier supports __func__])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
# Check whether C++ compiler supports __FUNCTION__.
|
||||
|
||||
AC_DEFUN([APP_CXX___FUNCTION__], [
|
||||
AC_CACHE_CHECK(whether $CXX recognizes __FUNCTION__, app_cv_cxx___FUNCTION__, [
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
|
||||
[[const char* s = __FUNCTION__;]])],
|
||||
[app_cv_cxx___FUNCTION__=yes], [app_cv_cxx___FUNCTION__=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "x$app_cv_cxx___FUNCTION__" = "xyes"; then
|
||||
AC_DEFINE(HAVE_CXX___FUNCTION__, ,
|
||||
[Define if the C++ complier supports __FUNCTION__])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_DETECT_OS_KERNEL(triplet_name, define_macro_prefix)
|
||||
# Check target OS kernel.
|
||||
# triplet_name is target, host or build.
|
||||
# You must call AX_COMPILER_VENDOR before using this macro.
|
||||
|
||||
# If you call
|
||||
# APP_DETECT_OS_KERNEL([target], [CONFIG_KERNEL])
|
||||
# you will get CONFIG_KERNEL_LINUX C macro exported to config.h
|
||||
# (on gcc/linux).
|
||||
# If no define_macro_prefix is specified, no C macro prefix will be used.
|
||||
# app_cv_target_os_kernel will be set to kernel name (lowercase).
|
||||
# app_cv_target_os_kernel_macro will be set to kernel name (all caps).
|
||||
# TARGET_OS_KERNEL_LINUX automake conditional will be set to true.
|
||||
|
||||
# Note: Some operating systems / compilers have built-in defines.
|
||||
# For gcc, check with
|
||||
# $ gcc -dM -E - < /dev/null
|
||||
|
||||
AC_DEFUN([APP_DETECT_OS_KERNEL], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
AC_MSG_CHECKING([for $1 OS kernel])
|
||||
|
||||
app_cv_[]$1[]_os_kernel="";
|
||||
app_cv_[]$1[]_os_kernel_macro="";
|
||||
|
||||
# If vendor is not recognized, it's set to "unknown".
|
||||
# NOTE: This works only on target compilers!
|
||||
if test "x${ax_cv_cxx_compiler_vendor}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[ax_cv_cxx_compiler_vendor] not set.])
|
||||
fi
|
||||
|
||||
# "build" - the type of system on which the package is being configured and compiled.
|
||||
# "host" - the type of system on which the package runs. Specifying it enables the
|
||||
# cross-compilation mode. "target" defaults to this too.
|
||||
|
||||
if test "x$1" != "xbuild" && test "x$1" != "xhost" && test "x$1" != "xtarget"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[Triplet name must be build, host or target.]])
|
||||
fi
|
||||
|
||||
case "$$1" in
|
||||
*linux*)
|
||||
# gcc defines __linux__ on linux. Other defines include: __linux, __unix__, __gnu_linux__,
|
||||
# linux, unix, __i386__, i386.
|
||||
app_cv_[]$1[]_os_kernel="linux";
|
||||
app_cv_[]$1[]_os_kernel_macro="LINUX";
|
||||
;;
|
||||
|
||||
*mingw* | *cygwin*)
|
||||
# mingw defines _WIN32. msvc defines _WIN32 (built-in), and WIN32 via windows.h.
|
||||
# Other mingw defines include: __WINNT, __WINNT__, __WIN32__, __i386, _X86_,
|
||||
# i386, __i386__, WIN32, __MINGW32__, WINNT (all equal to 1).
|
||||
app_cv_[]$1[]_os_kernel="windows";
|
||||
app_cv_[]$1[]_os_kernel_macro="WINDOWS";
|
||||
;;
|
||||
|
||||
# This includes debian gnu/kfreebsd. Dragonfly is checked separately.
|
||||
*freebsd*)
|
||||
# gcc built-in defines (to check for freebsd kernel):
|
||||
# defined(__FreeBSD__) || defined(__FreeBSD_kernel__).
|
||||
# See http://glibc-bsd.alioth.debian.org/porting/PORTING .
|
||||
app_cv_[]$1[]_os_kernel="freebsd";
|
||||
app_cv_[]$1[]_os_kernel_macro="FREEBSD";
|
||||
;;
|
||||
|
||||
*dragonfly*)
|
||||
app_cv_[]$1[]_os_kernel="dragonfly";
|
||||
app_cv_[]$1[]_os_kernel_macro="DRAGONFLY";
|
||||
;;
|
||||
|
||||
*openbsd*)
|
||||
app_cv_[]$1[]_os_kernel="openbsd";
|
||||
app_cv_[]$1[]_os_kernel_macro="OPENBSD";
|
||||
;;
|
||||
|
||||
# This includes debian gnu/netbsd.
|
||||
*netbsd*)
|
||||
app_cv_[]$1[]_os_kernel="netbsd";
|
||||
app_cv_[]$1[]_os_kernel_macro="NETBSD";
|
||||
;;
|
||||
|
||||
*solaris*)
|
||||
app_cv_[]$1[]_os_kernel="solaris";
|
||||
app_cv_[]$1[]_os_kernel_macro="SOLARIS";
|
||||
;;
|
||||
|
||||
*darwin*)
|
||||
app_cv_[]$1[]_os_kernel="darwin";
|
||||
app_cv_[]$1[]_os_kernel_macro="DARWIN";
|
||||
;;
|
||||
|
||||
*qnx*)
|
||||
app_cv_[]$1[]_os_kernel="qnx";
|
||||
app_cv_[]$1[]_os_kernel_macro="QNX";
|
||||
;;
|
||||
|
||||
*)
|
||||
app_cv_[]$1[]_os_kernel="unknown";
|
||||
app_cv_[]$1[]_os_kernel_macro="UNKNOWN";
|
||||
;;
|
||||
esac
|
||||
|
||||
# Assign this - we may use this in configure itself.
|
||||
if test "x$2" != "x"; then
|
||||
app_cv_[]$1[]_os_kernel_macro="$2[]_${app_cv_[]$1[]_os_kernel_macro}";
|
||||
fi
|
||||
|
||||
|
||||
# config.h macros (yes, we need this many. otherwise config.h will be incorrect).
|
||||
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xlinux"; then
|
||||
AC_DEFINE($2[]LINUX, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xwindows"; then
|
||||
AC_DEFINE($2[]WINDOWS, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xfreebsd"; then
|
||||
AC_DEFINE($2[]FREEBSD, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xdragonfly"; then
|
||||
AC_DEFINE($2[]DRAGONFLY, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xopenbsd"; then
|
||||
AC_DEFINE($2[]OPENBSD, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xnetbsd"; then
|
||||
AC_DEFINE($2[]NETBSD, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xsolaris"; then
|
||||
AC_DEFINE($2[]SOLARIS, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xdarwin"; then
|
||||
AC_DEFINE($2[]DARWIN, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xqnx"; then
|
||||
AC_DEFINE($2[]QNX, 1, [$1 OS kernel])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_kernel}" = "xunknown"; then
|
||||
AC_DEFINE($2[]UNKNOWN, 1, [$1 OS kernel])
|
||||
fi
|
||||
|
||||
# Export to Makefile.am's.
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_LINUX, [test "x${app_cv_[]$1[]_os_kernel}" = "xlinux"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_WINDOWS, [test "x${app_cv_[]$1[]_os_kernel}" = "xwindows"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_FREEBSD, [test "x${app_cv_[]$1[]_os_kernel}" = "xfreebsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_DRAGONFLY, [test "x${app_cv_[]$1[]_os_kernel}" = "xdragonfly"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_OPENBSD, [test "x${app_cv_[]$1[]_os_kernel}" = "xopenbsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_NETBSD, [test "x${app_cv_[]$1[]_os_kernel}" = "xnetbsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_SOLARIS, [test "x${app_cv_[]$1[]_os_kernel}" = "xsolaris"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_DARWIN, [test "x${app_cv_[]$1[]_os_kernel}" = "xdarwin"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_QNX, [test "x${app_cv_[]$1[]_os_kernel}" = "xqnx"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_KERNEL_UNKNOWN, [test "x${app_cv_[]$1[]_os_kernel}" = "xunknown"])
|
||||
|
||||
AC_MSG_RESULT([${app_cv_[]$1[]_os_kernel}])
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
# APP_DETECT_OS_ENV(triplet_name, define_macro_prefix)
|
||||
# Check target OS userland environment (mainly glibc).
|
||||
# triplet_name is target, host or build.
|
||||
# You must call AX_COMPILER_VENDOR before using this macro.
|
||||
|
||||
# If you call
|
||||
# APP_DETECT_OS_ENV([target], [COMPILER], [CONFIG_OS_ENV])
|
||||
# you will get CONFIG_OS_ENV_LINUX C macro exported to config.h
|
||||
# (on gcc/linux).
|
||||
# If no define_macro_prefix is specified, no C macro prefix will be used.
|
||||
# app_cv_target_os_env will be set to env name (lowercase).
|
||||
# app_cv_target_os_env_macro will be set to env name (all caps).
|
||||
# TARGET_OS_ENV_LINUX automake conditional will be set to true.
|
||||
|
||||
AC_DEFUN([APP_DETECT_OS_ENV], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
AC_MSG_CHECKING([for $1 OS userland environment])
|
||||
|
||||
app_cv_[]$1[]_os_env="";
|
||||
app_cv_[]$1[]_os_env_macro="";
|
||||
|
||||
# If vendor is not recognized, it's set to "unknown".
|
||||
# NOTE: This works only on target compilers!
|
||||
if test "x${ax_cv_cxx_compiler_vendor}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[ax_cv_cxx_compiler_vendor] not set.])
|
||||
fi
|
||||
|
||||
# "build" - the type of system on which the package is being configured and compiled.
|
||||
# "host" - the type of system on which the package runs. Specifying it enables the
|
||||
# cross-compilation mode. "target" defaults to this too.
|
||||
|
||||
if test "x$1" != "xbuild" && test "x$1" != "xhost" && test "x$1" != "xtarget"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[Triplet name must be build, host or target.]])
|
||||
fi
|
||||
|
||||
case "$$1" in
|
||||
*cygwin*)
|
||||
app_cv_[]$1[]_os_env="cygwin";
|
||||
app_cv_[]$1[]_os_env_macro="CYGWIN";
|
||||
;;
|
||||
*mingw*)
|
||||
app_cv_[]$1[]_os_env="mingw";
|
||||
app_cv_[]$1[]_os_env_macro="MINGW";
|
||||
;;
|
||||
# This includes gnu/linux, debian gnu/kfreebsd, debian gnu/netbsd...
|
||||
*-gnu | gnu*)
|
||||
app_cv_[]$1[]_os_env="gnu";
|
||||
app_cv_[]$1[]_os_env_macro="GNU";
|
||||
;;
|
||||
# Freebsd libc
|
||||
*freebsd*)
|
||||
app_cv_[]$1[]_os_env="freebsd";
|
||||
app_cv_[]$1[]_os_env_macro="FREEBSD";
|
||||
;;
|
||||
*dragonfly*)
|
||||
app_cv_[]$1[]_os_env="dragonfly";
|
||||
app_cv_[]$1[]_os_env_macro="DRAGONFLY";
|
||||
;;
|
||||
*openbsd*)
|
||||
app_cv_[]$1[]_os_env="openbsd";
|
||||
app_cv_[]$1[]_os_env_macro="OPENBSD";
|
||||
;;
|
||||
*netbsd*)
|
||||
app_cv_[]$1[]_os_env="netbsd";
|
||||
app_cv_[]$1[]_os_env_macro="NETBSD";
|
||||
;;
|
||||
*solaris*)
|
||||
app_cv_[]$1[]_os_env="solaris";
|
||||
app_cv_[]$1[]_os_env_macro="SOLARIS";
|
||||
;;
|
||||
*darwin*)
|
||||
app_cv_[]$1[]_os_env="darwin";
|
||||
app_cv_[]$1[]_os_env_macro="DARWIN";
|
||||
;;
|
||||
*qnx*)
|
||||
app_cv_[]$1[]_os_env="qnx";
|
||||
app_cv_[]$1[]_os_env_macro="QNX";
|
||||
;;
|
||||
*)
|
||||
app_cv_[]$1[]_os_env="unknown";
|
||||
app_cv_[]$1[]_os_env_macro="UNKNOWN";
|
||||
;;
|
||||
esac
|
||||
|
||||
# Assign this even if not using flags - we may use this in configure itself.
|
||||
if test "x$2" != "x"; then
|
||||
app_cv_[]$1[]_os_env_macro="$2[]_${app_cv_[]$1[]_os_env_macro}";
|
||||
fi
|
||||
|
||||
|
||||
# config.h macros (yes, we need this many. otherwise config.h will be incorrect).
|
||||
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xcygwin"; then
|
||||
AC_DEFINE($2[]CYGWIN, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xmingw"; then
|
||||
AC_DEFINE($2[]MINGW, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xgnu"; then
|
||||
AC_DEFINE($2[]GNU, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xfreebsd"; then
|
||||
AC_DEFINE($2[]FREEBSD, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xdragonfly"; then
|
||||
AC_DEFINE($2[]DRAGONFLY, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xopenbsd"; then
|
||||
AC_DEFINE($2[]OPENBSD, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xnetbsd"; then
|
||||
AC_DEFINE($2[]NETBSD, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xsolaris"; then
|
||||
AC_DEFINE($2[]SOLARIS, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xdarwin"; then
|
||||
AC_DEFINE($2[]DARWIN, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xqnx"; then
|
||||
AC_DEFINE($2[]QNX, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
if test "x${app_cv_[]$1[]_os_env}" = "xunknown"; then
|
||||
AC_DEFINE($2[]UNKNOWN, 1, [$1 OS userspace environment])
|
||||
fi
|
||||
|
||||
# Export to Makefile.am's.
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_CYGWIN, [test "x${app_cv_[]$1[]_os_env}" = "xcygwin"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_MINGW, [test "x${app_cv_[]$1[]_os_env}" = "xmingw"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_GNU, [test "x${app_cv_[]$1[]_os_env}" = "xgnu"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_FREEBSD, [test "x${app_cv_[]$1[]_os_env}" = "xfreebsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_DRAGONFLY, [test "x${app_cv_[]$1[]_os_env}" = "xdragonfly"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_OPENBSD, [test "x${app_cv_[]$1[]_os_env}" = "xopenbsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_NETBSD, [test "x${app_cv_[]$1[]_os_env}" = "xnetbsd"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_SOLARIS, [test "x${app_cv_[]$1[]_os_env}" = "xsolaris"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_DARWIN, [test "x${app_cv_[]$1[]_os_env}" = "xdarwin"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_QNX, [test "x${app_cv_[]$1[]_os_env}" = "xqnx"])
|
||||
AM_CONDITIONAL(m4_toupper($1)[]_OS_ENV_UNKNOWN, [test "x${app_cv_[]$1[]_os_env}" = "xunknown"])
|
||||
|
||||
AC_MSG_RESULT([${app_cv_[]$1[]_os_env}])
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_GET_MT_FLAGS(flags_prefix[, action-if-not-found])
|
||||
# This macro detects compiler flags which are needed to compile a multi-threaded
|
||||
# (possibly pthreads-based) applications on target OS. flags_prefixCFLAGS,
|
||||
# flags_prefixCXXFLAGS and flags_prefixLIBS will be initialized (or appended to)
|
||||
# with the correct flags.
|
||||
|
||||
# You must call AX_COMPILER_VENDOR, APP_DETECT_OS_KERNEL([target], ...)
|
||||
# and APP_DETECT_OS_ENV([target], ...) before using this macro.
|
||||
|
||||
AC_DEFUN([APP_GET_MT_FLAGS], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
AC_REQUIRE([APP_DETECT_OS_KERNEL])
|
||||
AC_REQUIRE([APP_DETECT_OS_ENV])
|
||||
|
||||
AC_MSG_CHECKING([for target thread support flags])
|
||||
|
||||
app_cv_target_thread_cflags="";
|
||||
app_cv_target_thread_cxxflags="";
|
||||
app_cv_target_thread_libs="";
|
||||
app_cv_target_thread_found="no";
|
||||
|
||||
# If vendor is not recognized, it's set to "unknown".
|
||||
# NOTE: This works only on target compilers!
|
||||
if test "x${ax_cv_cxx_compiler_vendor}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[ax_cv_cxx_compiler_vendor] not set.])
|
||||
fi
|
||||
if test "x${app_cv_target_os_kernel}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[app_cv_target_os_kernel] not set.])
|
||||
fi
|
||||
if test "x${app_cv_target_os_env}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[app_cv_target_os_env] not set.])
|
||||
fi
|
||||
|
||||
|
||||
# Compilers use at least 3 defines to indicate thread-safe support to standard libs:
|
||||
# _THREAD_SAFE, _MT, _REENTRANT.
|
||||
# We use the ones that are required for detected platform.
|
||||
|
||||
case "$app_cv_target_os_kernel" in
|
||||
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
|
||||
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"
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# suncc needs -lpthread on posix but not solaris.
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt -lpthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
|
||||
fi
|
||||
;;
|
||||
|
||||
windows)
|
||||
# NOTE: Not sure about cygwin.
|
||||
# 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
|
||||
app_cv_target_thread_cflags="-mthreads -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-mthreads -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-mthreads"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
freebsd | dragonfly | netbsd | openbsd)
|
||||
# NOTE: Not sure about debian gnu/kfreebsd and gnu/netbsd.
|
||||
# Freebsd had -kthread, but it has been discontinued (afaik).
|
||||
# For freebsd -pthread already replaces libc with libc_r.
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
app_cv_target_thread_cflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthread -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-pthread"
|
||||
app_cv_target_thread_found="yes";
|
||||
fi
|
||||
;;
|
||||
|
||||
solaris)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# gnu documentation mentions -threads (and its aliases, -pthreads and -pthread)
|
||||
app_cv_target_thread_cflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_cxxflags="-pthreads -D_MT -D_THREAD_SAFE"
|
||||
app_cv_target_thread_libs="-pthreads"
|
||||
app_cv_target_thread_found="yes"
|
||||
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
# -mt defines _REENTRANT too. Don't use -lthread.
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/pthreads-5?a=view
|
||||
# http://docs.sun.com/app/docs/doc/816-5137/compile-74765?a=view
|
||||
# There are two threading libraries, selectable via different switches.
|
||||
app_cv_target_thread_cflags="-mt"
|
||||
app_cv_target_thread_cxxflags="-mt"
|
||||
app_cv_target_thread_libs="-mt"
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
darwin)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
# Darwin produces mt code by default, and -pthread is an error.
|
||||
# gcc/darwin defines __APPLE__. __UNIX__ is not defined.
|
||||
# -D_THREAD_SAFE
|
||||
app_cv_target_thread_found="yes"
|
||||
fi
|
||||
;;
|
||||
|
||||
qnx)
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; 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"
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
if test "$app_cv_target_thread_found" = "no"; then
|
||||
AC_MSG_WARN([Cannot detect compiler thread support. Set CFLAGS, CXXFLAGS and LIBS manually.])
|
||||
m4_ifvaln([$2],[$2])dnl
|
||||
|
||||
else
|
||||
AC_MSG_RESULT([CFLAGS: $app_cv_target_thread_cflags; CXXFLAGS: $app_cv_target_thread_cxxflags; LIBS: $app_cv_target_thread_libs])
|
||||
|
||||
if test "x$$1[]CFLAGS" = "x"; then
|
||||
$1[]CFLAGS="$app_cv_target_thread_cflags";
|
||||
else
|
||||
$1[]CFLAGS="$$1[]CFLAGS $app_cv_target_thread_cflags";
|
||||
fi
|
||||
if test "x$$1[]CXXFLAGS" = "x"; then
|
||||
$1[]CXXFLAGS="$app_cv_target_thread_cxxflags";
|
||||
else
|
||||
$1[]CXXFLAGS="$$1[]CXXFLAGS $app_cv_target_thread_cxxflags";
|
||||
fi
|
||||
if test "x$$1[]LIBS" = "x"; then
|
||||
$1[]LIBS="$app_cv_target_thread_libs";
|
||||
else
|
||||
$1[]LIBS="$$1[]LIBS $app_cv_target_thread_libs";
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
|
||||
# APP_USE_SYSTEM_EXTENSIONS([flags_prefix])
|
||||
# This macro detects compiler flags which are needed to enable
|
||||
# system-specific library extensions. For example, on GNU platforms
|
||||
# it's -D_GNU_SOURCE, on solaris it's -D__EXTENSIONS__, etc...
|
||||
# Basically, it's the same as AC_USE_SYSTEM_EXTENSIONS,
|
||||
# but uses compiler flag approach instead of config.h.
|
||||
|
||||
# You must call AX_COMPILER_VENDOR
|
||||
# and APP_DETECT_OS_ENV([target], ...) before using this macro.
|
||||
|
||||
# More info:
|
||||
# http://www.gnu.org/software/autoconf/manual/autoconf.html#Posix-Variants
|
||||
# http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
# http://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.predefined
|
||||
# http://docs.sun.com/app/docs/doc/817-3946/6mjgmt4o8?l=en&a=view
|
||||
|
||||
AC_DEFUN([APP_USE_SYSTEM_EXTENSIONS], [
|
||||
# These requirements check compile-time presence, not that they were called
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
AC_REQUIRE([APP_DETECT_OS_ENV])
|
||||
|
||||
AC_MSG_CHECKING([for target system extension flags])
|
||||
|
||||
app_cv_target_extension_cflags="";
|
||||
app_cv_target_extension_cxxflags="";
|
||||
app_cv_target_extension_libs="";
|
||||
|
||||
|
||||
# If vendor is not recognized, it's set to "unknown".
|
||||
# NOTE: This works only on target compilers!
|
||||
if test "x${ax_cv_cxx_compiler_vendor}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[ax_cv_cxx_compiler_vendor] not set.])
|
||||
fi
|
||||
if test "x${app_cv_target_os_kernel}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[app_cv_target_os_kernel] not set.])
|
||||
fi
|
||||
if test "x${app_cv_target_os_env}" = "x"; then
|
||||
# msg_result is needed to print the checking... message.
|
||||
AC_MSG_RESULT([error])
|
||||
AC_MSG_ERROR([[app_cv_target_os_env] not set.])
|
||||
fi
|
||||
|
||||
|
||||
case "$app_cv_target_os_env" in
|
||||
gnu)
|
||||
# glibc all-extensions macro: _GNU_SOURCE.
|
||||
# gcc automatically defines it in later versions.
|
||||
# suncc needs the flag explicitly.
|
||||
# http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
app_cv_target_extension_cflags="-D_GNU_SOURCE"
|
||||
app_cv_target_extension_cxxflags="-D_GNU_SOURCE"
|
||||
;;
|
||||
|
||||
solaris)
|
||||
# The problem with solaris is that it has too many incompatible
|
||||
# feature test macros, and there is no enable-all macro. Autoconf
|
||||
# mistakenly assumes that __EXTENSIONS__ is the one, but
|
||||
# it should be defined _in addition_ to feature test macros.
|
||||
# To support some posix macros, additional link objects are also required.
|
||||
# http://docs.sun.com/app/docs/doc/816-5175/standards-5?a=view
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
AC_MSG_RESULT([CFLAGS: $app_cv_target_extension_cflags; CXXFLAGS: $app_cv_target_extension_cxxflags; LIBS: $app_cv_target_extension_libs])
|
||||
|
||||
if test "x$$1[]CFLAGS" = "x"; then
|
||||
$1[]CFLAGS="$app_cv_target_extension_cflags";
|
||||
else
|
||||
$1[]CFLAGS="$$1[]CFLAGS $app_cv_target_extension_cflags";
|
||||
fi
|
||||
if test "x$$1[]CXXFLAGS" = "x"; then
|
||||
$1[]CXXFLAGS="$app_cv_target_extension_cxxflags";
|
||||
else
|
||||
$1[]CXXFLAGS="$$1[]CXXFLAGS $app_cv_target_extension_cxxflags";
|
||||
fi
|
||||
if test "x$$1[]LIBS" = "x"; then
|
||||
$1[]LIBS="$app_cv_target_extension_libs";
|
||||
else
|
||||
$1[]LIBS="$$1[]LIBS $app_cv_target_extension_libs";
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
stamp="../gsmartcontrol-`date +%F`"
|
||||
echo $stamp
|
||||
@@ -1,13 +1,16 @@
|
||||
|
||||
AC_INIT([GSmartControl], [0.8.0rc3], [], [gsmartcontrol])
|
||||
AC_INIT([GSmartControl], [0.8.0rc4], [], [gsmartcontrol])
|
||||
|
||||
AC_CONFIG_SRCDIR([configure.ac])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
# disable portability warnings because of pattern rules in src/res.
|
||||
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 -Wall,no-portability])
|
||||
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 -Wall])
|
||||
|
||||
|
||||
# Clear *FLAGS, LIBS, LDFLAGS if requested through configure option.
|
||||
APP_AUTO_CLEAR_FLAGS()
|
||||
|
||||
# C compiler, C preprocessor
|
||||
AC_PROG_CC
|
||||
@@ -33,37 +36,36 @@ AC_CHECK_TOOL(RANLIB, ranlib)
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Various compiler features
|
||||
# ------------- Detect compiler, OS, environment. Enable system features.
|
||||
|
||||
|
||||
# detect compiler vendor (sets $ax_cv_cxx_compiler_vendor)
|
||||
AX_COMPILER_VENDOR
|
||||
|
||||
# detect RTTI (defines HAVE_RTTI)
|
||||
AC_CXX_RTTI
|
||||
# Detect target OS kernel and userspace and export to config.h
|
||||
# (also define automake conditionals).
|
||||
APP_DETECT_OS_KERNEL([target], [CONFIG_KERNEL_])
|
||||
APP_DETECT_OS_ENV([target], [CONFIG_OS_ENV_])
|
||||
|
||||
# detect exception support (defines HAVE_EXCEPTIONS)
|
||||
AC_CXX_EXCEPTIONS
|
||||
# Detect common (warning, debug, optimize) compiler flags and
|
||||
# export them to C(XX)FLAGS, LDFLAGS.
|
||||
# We don't use prefix because this way the flags will be used for tests,
|
||||
# which is important for some compatibility flags (e.g. __func__ visibility, etc...).
|
||||
APP_COMPILER_OPTIONS([])
|
||||
|
||||
# detect abi::__cxa_demangle (defines HAVE_GCC_ABI_DEMANGLE)
|
||||
AX_CXX_GCC_ABI_DEMANGLE
|
||||
# Thread support for known configurations.
|
||||
APP_GET_MT_FLAGS([])
|
||||
|
||||
# detect __gnu_cxx::__verbose_terminate_handler (defines HAVE_VERBOSE_TERMINATE_HANDLER.)
|
||||
AC_CXX_VERBOSE_TERMINATE_HANDLER
|
||||
# Enable _GNU_SOURCE, etc...
|
||||
APP_USE_SYSTEM_EXTENSIONS([])
|
||||
|
||||
# detect __func__ support (defines HAVE_CXX__FUNC)
|
||||
AC_CXX_VAR_FUNC
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Portability stuff
|
||||
|
||||
# arrange large file support (define _FILE_OFFSET_BITS 64, etc...)
|
||||
# Arrange large file support (define _FILE_OFFSET_BITS 64, etc...)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
|
||||
|
||||
# ------------- Correct incomplete standard libraries
|
||||
|
||||
# define int8_t and friends if the standard doesn't have them
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_UINT8_T
|
||||
@@ -79,6 +81,33 @@ AC_TYPE_UINTMAX_T
|
||||
AC_TYPE_LONG_LONG_INT
|
||||
AC_TYPE_UNSIGNED_LONG_LONG_INT
|
||||
|
||||
|
||||
|
||||
# ------------- Language / Standard Library checks
|
||||
|
||||
# detect RTTI (defines HAVE_RTTI)
|
||||
AC_CXX_RTTI
|
||||
|
||||
# detect exception support (defines HAVE_EXCEPTIONS)
|
||||
AC_CXX_EXCEPTIONS
|
||||
|
||||
# detect abi::__cxa_demangle (defines HAVE_GCC_ABI_DEMANGLE)
|
||||
AX_CXX_GCC_ABI_DEMANGLE
|
||||
|
||||
# detect __gnu_cxx::__verbose_terminate_handler (defines HAVE_VERBOSE_TERMINATE_HANDLER.)
|
||||
AC_CXX_VERBOSE_TERMINATE_HANDLER
|
||||
|
||||
# detect __func__ support (defines HAVE_CXX___func__)
|
||||
APP_CXX___FUNC__
|
||||
|
||||
# detect __FUNCTION__ support (defines HAVE_CXX___FUNCTION__)
|
||||
APP_CXX___FUNCTION__
|
||||
|
||||
# detect if the compiler accepts extern "C" function pointer overloads
|
||||
# (defines HAVE_CXX_EXTERN_C_OVERLOAD)
|
||||
APP_CXX_EXTERN_C_OVERLOAD
|
||||
|
||||
|
||||
# This may be needed for pch support
|
||||
AC_CHECK_HEADERS([stdc++.h])
|
||||
|
||||
@@ -87,9 +116,9 @@ AC_CHECK_FUNCS([strtoll _strtoi64], [break])
|
||||
|
||||
# Non-C99 systems don't have strtof and strtold. some have strtodf for strtof,
|
||||
# but let's ignore it. Note: They may be supported by system libc,
|
||||
# but unsupported by headers (e.g. sun studio on linux). In that case,
|
||||
# but not enabled by default (e.g. by glibc feature macros). In that case,
|
||||
# defining them still leads to undefined symbols at link time, so we don't do it.
|
||||
# header / link check:
|
||||
# Header check is the best way to determine availability:
|
||||
AC_CHECK_DECLS([strtof, strtold], [], [], [[#include <stdlib.h>]])
|
||||
# link check only:
|
||||
# AC_CHECK_FUNCS([strtof strtold])
|
||||
@@ -100,39 +129,10 @@ AC_CHECK_DECLS([strtof, strtold], [], [], [[#include <stdlib.h>]])
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# "build" - the type of system on which the package is being configured and compiled.
|
||||
ac_windows_build="no"
|
||||
ac_linux_build="no"
|
||||
case "${host}" in
|
||||
*mingw*)
|
||||
ac_windows_build="yes"
|
||||
;;
|
||||
*linux*)
|
||||
ac_linux_build="yes"
|
||||
;;
|
||||
esac
|
||||
# Non-standard feature checks
|
||||
|
||||
# export to Makefile.am-s
|
||||
AM_CONDITIONAL([WINDOWS_BUILD], [test "$ac_windows_build" = "yes"])
|
||||
AM_CONDITIONAL([LINUX_BUILD], [test "$ac_linux_build" = "yes"])
|
||||
|
||||
|
||||
# "host" - the type of system on which the package runs. Specifying it enables the
|
||||
# cross-compilation mode. "target" defaults to this too.
|
||||
ac_windows_target="no"
|
||||
ac_linux_target="no"
|
||||
case "${target}" in
|
||||
*mingw*)
|
||||
ac_windows_target="yes"
|
||||
;;
|
||||
*linux*)
|
||||
ac_linux_target="yes"
|
||||
;;
|
||||
esac
|
||||
|
||||
# export to Makefile.am-s
|
||||
AM_CONDITIONAL([WINDOWS_TARGET], [test "$ac_windows_target" = "yes"])
|
||||
AM_CONDITIONAL([LINUX_TARGET], [test "$ac_linux_target" = "yes"])
|
||||
# getrawpartition() for netbsd and openbsd in -lutil.
|
||||
AC_CHECK_LIB(util, getrawpartition, [ LIBS="$LIBS -lutil" ])
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
@@ -140,124 +140,11 @@ AM_CONDITIONAL([LINUX_TARGET], [test "$ac_linux_target" = "yes"])
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
COMPILER_CXXFLAGS=""
|
||||
COMPILER_LDFLAGS=""
|
||||
# reset original user-supplied *FLAGS
|
||||
RESET_ORIGINAL="no"
|
||||
|
||||
|
||||
AC_ARG_ENABLE(default-gcc-options,
|
||||
AS_HELP_STRING([--enable-default-gcc-options],[enable default compilation options (warnings, mostly) (GCC only) (default: disabled)]),
|
||||
[default_gcc_options=${enableval}], [default_gcc_options=no])
|
||||
|
||||
if test "$default_gcc_options" = "yes"; then
|
||||
if test "$ac_windows_target" = "yes"; then
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -mms-bitfields -mwindows"
|
||||
COMPILER_LDFLAGS="$COMPILER_CXXFLAGS -mms-bitfields"
|
||||
fi
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS \
|
||||
-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"
|
||||
RESET_ORIGINAL="yes";
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(gcc-debug,
|
||||
AS_HELP_STRING([--enable-gcc-debug],[enable debug build (GCC only) (default: disabled)]),
|
||||
[gcc_debug=${enableval}], [gcc_debug=no])
|
||||
|
||||
if test "$gcc_debug" = "yes"; then
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -g3 -O0 -DDEBUG -DDEBUG_BUILD"
|
||||
COMPILER_LDFLAGS="$COMPILER_LDFLAGS -g3 -O0"
|
||||
RESET_ORIGINAL="yes";
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(gcc-optimize,
|
||||
AS_HELP_STRING([--enable-gcc-optimize],[enable optimized build (GCC only) (default: disabled)]),
|
||||
[gcc_optimize=${enableval}], [gcc_optimize=no])
|
||||
|
||||
if test "$gcc_optimize" = "yes"; then
|
||||
# Note: Do NOT put CPU flags here - they make the program non-portable.
|
||||
if test "$ac_windows_target" = "yes"; then
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -g0 -O3 -s"
|
||||
COMPILER_LDFLAGS="$COMPILER_LDFLAGS -s"
|
||||
else
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -g0 -O3 -s -mtune=generic"
|
||||
COMPILER_LDFLAGS="$COMPILER_LDFLAGS -s -mtune=generic"
|
||||
fi
|
||||
RESET_ORIGINAL="yes";
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(gcc_pch,
|
||||
AS_HELP_STRING([--enable-gcc-pch],[enable precompiled header support (pch make target) (GCC only) (default: disabled)
|
||||
(use "make gch" to speed up the compilation)]),
|
||||
[gcc_pch=${enableval}], [gcc_pch=no])
|
||||
|
||||
if test "$gcc_pch" = "yes"; then
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -Winvalid-pch -DENABLE_PCH"
|
||||
fi
|
||||
|
||||
|
||||
# define LINUX for linux target
|
||||
if test "$ac_linux_target" = "yes"; then
|
||||
COMPILER_CXXFLAGS="$COMPILER_CXXFLAGS -DLINUX"
|
||||
fi
|
||||
|
||||
|
||||
# Reset user-supplied flags if one of the above options is present.
|
||||
# We append COMPILER_* counterparts in the end, to override any
|
||||
# previous options.
|
||||
if test "$RESET_ORIGINAL" = "yes"; then
|
||||
CFLAGS=""
|
||||
CXXFLAGS=""
|
||||
LIBS=""
|
||||
LDFLAGS=""
|
||||
fi
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Enable compiler thread switches for known platforms.
|
||||
|
||||
AC_MSG_NOTICE([checking thread support flags...])
|
||||
|
||||
THREAD_CFLAGS=""
|
||||
THREAD_LIBS=""
|
||||
THREAD_FOUND="no"
|
||||
|
||||
if test "$ac_windows_target" = "yes"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu"; then
|
||||
THREAD_CFLAGS="-mthreads -D_THREAD_SAFE"
|
||||
THREAD_LIBS="-mthreads"
|
||||
THREAD_FOUND="yes"
|
||||
fi
|
||||
|
||||
elif test "$ac_linux_target" = "yes"; then
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel"; then
|
||||
THREAD_CFLAGS="-pthread -D_MT -D_THREAD_SAFE"
|
||||
THREAD_LIBS="-pthread"
|
||||
THREAD_FOUND="yes"
|
||||
elif test "$ax_cv_cxx_compiler_vendor" = "sun"; then
|
||||
THREAD_CFLAGS="-mt"
|
||||
THREAD_LIBS="-mt"
|
||||
THREAD_FOUND="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$THREAD_FOUND" = "no"; then
|
||||
AC_MSG_NOTICE([Cannot detect compiler thread support. Set CXXFLAGS and LDFLAGS manually.])
|
||||
|
||||
else
|
||||
AC_MSG_NOTICE([CFLAGS: $THREAD_CFLAGS; LIBS: $THREAD_LIBS])
|
||||
CXXFLAGS="$CXXFLAGS $THREAD_CFLAGS"
|
||||
LIBS="$LIBS $THREAD_LIBS"
|
||||
fi
|
||||
# enable / disable compilation of tests
|
||||
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests],
|
||||
[enable compilation of test programs (default: no)]), [with_tests=${enableval}], [with_tests=no])
|
||||
# export to automake.am-s
|
||||
AM_CONDITIONAL([ENABLE_TESTS], [test "$with_tests" = "yes"])
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
@@ -272,8 +159,8 @@ pkg_modules="gtkmm-2.4 >= 2.6.0 gthread-2.0 >= 2.0"
|
||||
gtkmm_found="no"
|
||||
|
||||
PKG_CHECK_MODULES([GTKMM], [$pkg_modules], [
|
||||
AC_DEFINE([ENABLE_GLIB], [], [Whether GLib is installed])
|
||||
AC_DEFINE([ENABLE_GLIBMM], [], [Whether GLibmm is installed])
|
||||
AC_DEFINE([ENABLE_GLIB], [1], [Whether GLib is installed])
|
||||
AC_DEFINE([ENABLE_GLIBMM], [1], [Whether GLibmm is installed])
|
||||
gtkmm_found="yes"
|
||||
], [
|
||||
AC_MSG_WARN([$GTKMM_PKG_ERRORS])
|
||||
@@ -290,68 +177,15 @@ PKG_CHECK_MODULES([GTKMM], [$pkg_modules], [
|
||||
CXXFLAGS="$GTKMM_CFLAGS $CXXFLAGS"
|
||||
LIBS="$GTKMM_LIBS $LIBS"
|
||||
|
||||
# needed for in-code checks (AC_DEFINE() takes care of these above, no need of them here)
|
||||
# CXXFLAGS="$CXXFLAGS -DENABLE_GLIB -DENABLE_GLIBMM"
|
||||
|
||||
# Detect libglade / gtkbuilder support
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
APP_CHOOSE_GLD_READER([C++], [LIBGLADE_])
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
gld_found=no; # equals to "gtkbuilder" or "libglademm" after tests
|
||||
|
||||
#if test "gtkmm_found" = "yes"; then
|
||||
|
||||
# Check whether we should use Gtk::Builder (gtkmm >= 2.12) or libglademm.
|
||||
AC_ARG_ENABLE(libglademm, AS_HELP_STRING([--enable-libglademm],
|
||||
[use libglademm instead of GtkBuilder (default: auto)]), [with_libglademm=${enableval}], [with_libglademm=auto])
|
||||
|
||||
|
||||
# try gtkbuilder first
|
||||
if test "$with_libglademm" = "no" || test "$with_libglademm" = "auto"; then
|
||||
PKG_CHECK_EXISTS([gtkmm-2.4 >= 2.12.0], [gld_found=gtkbuilder])
|
||||
fi
|
||||
if test "$with_libglademm" = "no" && test "$gld_found" = "no"; then
|
||||
AC_MSG_ERROR([GtkBuilder support not found (you need gtkmm version 2.12 or higher). Try using libglademm instead.])
|
||||
fi
|
||||
|
||||
# libglade specified, or auto and no gtkbuilder. gtkmm2.4-compatible libglade is >= 2.4.0.
|
||||
if test "$gld_found" = "no"; then
|
||||
PKG_CHECK_MODULES([LIBGLADEMM], [libglademm-2.4 >= 2.4.0], [gld_found="libglademm"],
|
||||
[AC_MSG_WARN([$LIBGLADEMM_PKG_ERRORS])])
|
||||
fi
|
||||
if test "$with_libglademm" = "yes" && test "$gld_found" = "no"; then
|
||||
AC_MSG_ERROR([Libglademm not found. Try building with GtkBuilder support (you need gtkmm version 2.12 or higher).])
|
||||
fi
|
||||
|
||||
# still not found.
|
||||
if test "$gld_found" = "no"; then
|
||||
AC_MSG_WARN([Neither GtkBuilder nor libglademm found. The program will be unable to compile fully.])
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_NOTICE([Glade file support through: $gld_found])
|
||||
|
||||
# merge libglademm flags
|
||||
if test "$gld_found" = "libglademm"; then
|
||||
CXXFLAGS="$LIBGLADEMM_CFLAGS $CXXFLAGS"
|
||||
LIBS="$LIBGLADEMM_LIBS $LIBS"
|
||||
fi
|
||||
|
||||
#fi
|
||||
|
||||
|
||||
# export to automake.am-s
|
||||
AM_CONDITIONAL([ENABLE_LIBGLADEMM], [test "$gld_found" = "libglademm"])
|
||||
AM_CONDITIONAL([ENABLE_GTKBUILDER], [test "$gld_found" = "gtkbuilder"])
|
||||
|
||||
# export to config.h
|
||||
if test "$gld_found" = "libglademm"; then
|
||||
AC_DEFINE(ENABLE_LIBGLADEMM, 1, [Use libglademm instead of GtkBuilder])
|
||||
fi
|
||||
if test "$gld_found" = "gtkbuilder"; then
|
||||
AC_DEFINE(ENABLE_GTKBUILDER, 1, [Use GtkBuilder instead of libglademm])
|
||||
if test "$app_cv_gld_reader" = "libglade"; then
|
||||
CFLAGS="$CFLAGS $LIBGLADE_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $LIBGLADE_CXXFLAGS"
|
||||
LIBS="$LIBS $LIBGLADE_LIBS"
|
||||
fi
|
||||
|
||||
|
||||
@@ -360,25 +194,27 @@ fi
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
pkg_modules="libpcre"
|
||||
PCRE_CFLAGS="";
|
||||
PCRE_LIBS="";
|
||||
|
||||
PKG_CHECK_MODULES(PCRE, [$pkg_modules])
|
||||
# try pkg-config first
|
||||
PKG_CHECK_MODULES(PCRE, [libpcre], [pcre_found=yes], [pcre_found=no])
|
||||
|
||||
#CFLAGS="$PCRE_CFLAGS $CFLAGS"
|
||||
CXXFLAGS="$PCRE_CFLAGS $CXXFLAGS"
|
||||
LIBS="$PCRE_LIBS $LIBS"
|
||||
# if not found, try pcre-config (solaris had it but not pkg-config).
|
||||
if test "$pcre_found" = "no"; then
|
||||
AC_PATH_PROG(pcre_config_binary, [pcre-config])
|
||||
if test "x$pcre_config_binary" != "x"; then
|
||||
PCRE_CFLAGS="`pcre-config --cflags`"
|
||||
PCRE_LIBS="`pcre-config --libs`"
|
||||
else
|
||||
# AC_MSG_ERROR([Could not find pcre through pkg-config and pcre-config. Make sure the pcre libraries are installed])
|
||||
AC_MSG_ERROR([$PCRE_PKG_ERRORS])
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# enable / disable compilation of tests
|
||||
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests],
|
||||
[enable compilation of test programs (default: no)]), [with_tests=${enableval}], [with_tests=no])
|
||||
# export to automake.am-s
|
||||
AM_CONDITIONAL([ENABLE_TESTS], [test "$with_tests" = "yes"])
|
||||
CFLAGS="$CFLAGS $PCRE_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PCRE_CFLAGS"
|
||||
LIBS="$LIBS $PCRE_LIBS"
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
@@ -401,7 +237,7 @@ RES_DIST="" # only files in "res" directory, EXTRA_DIST
|
||||
RES_TARGETS="" # entry for each file in makefile
|
||||
|
||||
RES_GLD_EXT="glade"
|
||||
if test "$gld_found" = "gtkbuilder"; then
|
||||
if test "$app_cv_gld_reader" = "gtkbuilder"; then
|
||||
RES_GLD_EXT="ui"
|
||||
fi
|
||||
|
||||
@@ -468,7 +304,8 @@ _AM_SUBST_NOTMAKE([RES_TARGETS])
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Export some configure variables as defines for the source code
|
||||
# Export some configure variables as defines for the source code.
|
||||
# Note: Autoconf manual says that AC_DEFINE won't work here.
|
||||
|
||||
ADDITIONAL_FLAGS="-DPACKAGE_PKGDATA_DIR=\"\\\"\$(pkgdatadir)\\\"\" \
|
||||
-DPACKAGE_SYSCONF_DIR=\"\\\"\$(sysconfdir)\\\"\" \
|
||||
@@ -478,10 +315,6 @@ ADDITIONAL_FLAGS="-DPACKAGE_PKGDATA_DIR=\"\\\"\$(pkgdatadir)\\\"\" \
|
||||
CXXFLAGS="$CXXFLAGS $ADDITIONAL_FLAGS"
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# Top src dir should always be in include path, before other includes.
|
||||
# Add global configuration file. Note: It must be searched in top_builddir
|
||||
# first (that's why -I is the first flag), for precompiled headers to work.
|
||||
@@ -489,15 +322,20 @@ CXXFLAGS="$CXXFLAGS $ADDITIONAL_FLAGS"
|
||||
# Add pcrecpp too, because its files use #<file> on each other.
|
||||
ADDITIONAL_INCLUDES="-I\$(top_builddir) -I\$(top_srcdir)/src -I\$(top_srcdir)/src/pcrecpp"
|
||||
|
||||
# -include doesn't work with sun and pgi, but works with intel and gcc.
|
||||
# we don't whitelist intel/gcc, because there are some gcc-frontend-based
|
||||
# compilers we don't want to break (pathscale, gccfss (gcc frontend / sun backend), etc...).
|
||||
if test "$ax_cv_cxx_compiler_vendor" != "sun" && test "$ax_cv_cxx_compiler_vendor" != "portland"; then
|
||||
# -include works with gcc, intel and pathscale, but doesn't work with sun and pgi.
|
||||
# Note: some gcc-frontend-based compilers may have to be added here
|
||||
# (e.g. gccfss (gcc frontend / sun backend), etc...).
|
||||
if test "$ax_cv_cxx_compiler_vendor" = "gnu" || test "$ax_cv_cxx_compiler_vendor" = "intel" \
|
||||
|| test "$ax_cv_cxx_compiler_vendor" = "pathscale"; then
|
||||
# This auto-includes this file when compiling any file. Benefits include pch support.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -include global_macros.h"
|
||||
else # sun, pgi, others...
|
||||
# This forces the file to be included manually.
|
||||
ADDITIONAL_INCLUDES="$ADDITIONAL_INCLUDES -DHZ_NO_COMPILER_AUTOINCLUDE"
|
||||
fi
|
||||
|
||||
#CFLAGS="$ADDITIONAL_INCLUDES $CFLAGS"
|
||||
# our flags must be before all the others
|
||||
#CFLAGS="$ADDITIONAL_INCLUDES $CFLAGS"
|
||||
CXXFLAGS="$ADDITIONAL_INCLUDES $CXXFLAGS"
|
||||
|
||||
|
||||
@@ -506,23 +344,12 @@ CXXFLAGS="$ADDITIONAL_INCLUDES $CXXFLAGS"
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Append compiler flags to CXXFLAGS, so that they override
|
||||
# whatever the user has set.
|
||||
CXXFLAGS="$CXXFLAGS $COMPILER_CXXFLAGS"
|
||||
LIBS="$LIBS $COMPILER_LDFLAGS"
|
||||
# final setup
|
||||
|
||||
# This macro should be defined by ./configure automatically.
|
||||
# However, sometimes it's not (e.g. win32, why?), so we define it manually.
|
||||
CXXFLAGS="$CXXFLAGS -DHAVE_CONFIG_H"
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# final setup
|
||||
|
||||
#CFLAGS="$CFLAGS $USER_INCLUDES"
|
||||
#CXXFLAGS="$CXXFLAGS $USER_INCLUDES"
|
||||
#LIBS="$LIBS $USER_LDFLAGS"
|
||||
@@ -535,6 +362,8 @@ AC_SUBST(LIBS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -551,11 +380,13 @@ AC_SUBST(LDFLAGS)
|
||||
|
||||
|
||||
|
||||
# print'em out for debug purposes
|
||||
# print them out for debug purposes
|
||||
|
||||
AC_MSG_NOTICE([
|
||||
CXXFLAGS:
|
||||
$CXXFLAGS
|
||||
LDFLAGS:
|
||||
$LDFLAGS
|
||||
LIBS:
|
||||
$LIBS
|
||||
])
|
||||
@@ -566,19 +397,27 @@ $LIBS
|
||||
AC_SUBST(AUTODIRS)
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
AC_CONFIG_FILES([ data/gsmartcontrol_gnome.desktop data/gsmartcontrol_kde.desktop \
|
||||
data/gsmartcontrol_other.desktop \
|
||||
gsmartcontrol.spec version compilation_flags ])
|
||||
|
||||
|
||||
AC_CONFIG_FILES([data/gsmartcontrol_root.sh], [chmod +x data/gsmartcontrol_root.sh])
|
||||
|
||||
|
||||
# these are all the makefiles to generate
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile src/applib/Makefile src/res/Makefile src/hz/Makefile \
|
||||
src/libdebug/Makefile src/pcrecpp/Makefile src/rconfig/Makefile src/rmn/Makefile \
|
||||
data/Makefile data/16/Makefile data/22/Makefile data/24/Makefile data/32/Makefile \
|
||||
data/48/Makefile data/64/Makefile data/128/Makefile])
|
||||
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
|
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: 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 |
@@ -34,3 +34,7 @@ pixmaps_DATA = 48/gsmartcontrol.png
|
||||
|
||||
EXTRA_DIST = $(appdata_DATA) $(pixmaps_DATA)
|
||||
|
||||
|
||||
bin_SCRIPTS = gsmartcontrol_root.sh
|
||||
CLEANFILES = $(bin_SCRIPTS)
|
||||
|
||||
@@ -7,8 +7,7 @@ OnlyShowIn=GNOME;
|
||||
Version=1.0
|
||||
Type=Application
|
||||
|
||||
Categories=System;GTK;
|
||||
# Categories=Settings;HardwareSettings;
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
@@ -21,6 +20,8 @@ Comment=Monitor and control SMART data on hard disks
|
||||
# An absolute file path is also supported.
|
||||
Icon=gsmartcontrol
|
||||
|
||||
# Run with root permissions. Some desktop files used gksu,
|
||||
# but it doesn't seem available on my system.
|
||||
Exec=gnomesu -c "@prefix@/bin/gsmartcontrol"
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" gnome
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
@@ -7,8 +7,7 @@ OnlyShowIn=KDE;
|
||||
Version=1.0
|
||||
Type=Application
|
||||
|
||||
Categories=System;GTK;
|
||||
# Categories=Settings;HardwareSettings;
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
@@ -26,4 +25,7 @@ Icon=gsmartcontrol
|
||||
#X-KDE-SubstituteUID=true
|
||||
#X-KDE-RootOnly=true
|
||||
|
||||
Exec=kdesu "@prefix@/bin/gsmartcontrol"
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" kde
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
@@ -7,8 +7,7 @@ NotShowIn=GNOME;KDE;
|
||||
Version=1.0
|
||||
Type=Application
|
||||
|
||||
Categories=System;GTK;
|
||||
# Categories=Settings;HardwareSettings;
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
@@ -21,8 +20,8 @@ Comment=Monitor and control SMART data on hard disks
|
||||
# An absolute file path is also supported.
|
||||
Icon=gsmartcontrol
|
||||
|
||||
# Run with root permissions using gnomesu (from libgnomesu).
|
||||
# There is also kdesu (kdebase3-runtime, kdebase4-runtime), in different paths.
|
||||
# There is also xdg-su, which doesn't work at all on my machine.
|
||||
Exec=gnomesu -c "@prefix@/bin/gsmartcontrol"
|
||||
# Exec=kdesu -u root "@prefix@/bin/gsmartcontrol"
|
||||
# Run with root permissions.
|
||||
Exec="@prefix@/bin/gsmartcontrol_root.sh" other
|
||||
|
||||
# Build service rpmlint gives errors without this
|
||||
X-SuSE-translate=false
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
# Run gsmartcontrol with root, asking for root password first.
|
||||
|
||||
EXEC_BIN="@prefix@/bin/gsmartcontrol";
|
||||
prog_name="gsmartcontrol"
|
||||
|
||||
DESKTOP="$1";
|
||||
|
||||
# This works for --help too
|
||||
if [ "$DESKTOP" = "" ]; then
|
||||
DESKTOP="other"; # default
|
||||
|
||||
elif [ "$DESKTOP" != "kde" ] && [ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
|
||||
echo "Usage: $0 <desktop_name> [<${prog_name}_options>]";
|
||||
echo "Desktop name may be kde, gnome, other.";
|
||||
exit 1;
|
||||
fi
|
||||
shift; # remove $1
|
||||
|
||||
|
||||
# They're basically the same, only the order is different.
|
||||
# sux requires xterm to ask for the password.
|
||||
# xdg-su is basically like this script, except worse :)
|
||||
gnome_sus="gnomesu gksu kdesu xdg-su sux";
|
||||
kde_sus="kdesu gnomesu gksu xdg-su sux";
|
||||
other_sus="$gnome_sus";
|
||||
|
||||
|
||||
candidates="";
|
||||
found_su=""
|
||||
|
||||
if [ "$DESKTOP" = "gnome" ]; then
|
||||
candidates="$gnome_sus";
|
||||
elif [ "$DESKTOP" = "kde" ]; then
|
||||
candidates="$kde_sus";
|
||||
elif [ "$DESKTOP" = "other" ]; then
|
||||
candidates="$other_sus";
|
||||
fi
|
||||
|
||||
for subin in $candidates; do
|
||||
which $subin &>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
found_su="$subin";
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found_su" = "" ]; then
|
||||
xmessage "Error launching ${prog_name}: No suitable su mechanism found.
|
||||
Try installing gnomesu, kdesu or sux first.";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# echo $found_su;
|
||||
|
||||
# gnomesu -c 'gsmartcontrol --no-scan'
|
||||
# kdesu -c 'gsmartcontrol --no-scan'
|
||||
# xterm -e sux -c 'gsmartcontrol --no-scan' # sux asks for password in a terminal
|
||||
|
||||
full_cmd=""
|
||||
if [ "$found_su" = "sux" ]; then
|
||||
full_cmd="xterm -e sux -c '$EXEC_BIN $@'"
|
||||
|
||||
elif [ "$found_su" = "gksu" ]; then
|
||||
full_cmd="$found_su '$EXEC_BIN $@'"
|
||||
|
||||
else # gnomesu, kdesu, xdg-su
|
||||
full_cmd="$found_su -c '$EXEC_BIN $@'"
|
||||
fi
|
||||
|
||||
|
||||
eval $full_cmd
|
||||
|
||||
|
||||
|
||||
|
||||
|
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,10 +1,14 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# Copyright:
|
||||
# (C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
# License: See LICENSE_zlib.txt file
|
||||
############################################################################
|
||||
|
||||
# We use #!/bin/bash of #!/bin/sh because freebsd (tested with 6.3) in its
|
||||
# infinite wisdom has csh-like /bin/sh (even though the SUS says it
|
||||
# must be bourne-compatible).
|
||||
|
||||
|
||||
if [ "$1" == "" ] | [ "$2" == "" ] | [ "$3" == "" ]; then
|
||||
echo "Usage: $0 <input_file> <cpp_file> <symbol_name>";
|
||||
@@ -66,7 +66,7 @@
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<envvars/>
|
||||
<configargs>--enable-default-gcc-options --enable-gcc-optimize --enable-gcc-pch --enable-tests</configargs>
|
||||
<configargs>--disable-user-flags --enable-optimize-options --enable-tests</configargs>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
@@ -76,7 +76,7 @@
|
||||
<f77flags/>
|
||||
</optimized>
|
||||
<debuggy>
|
||||
<configargs>--enable-default-gcc-options --enable-gcc-debug --enable-tests</configargs>
|
||||
<configargs>--disable-user-flags --enable-debug-options --enable-tests</configargs>
|
||||
<builddir>debuggy</builddir>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
@@ -94,24 +94,24 @@
|
||||
</debuggy>
|
||||
<icc>
|
||||
<envvars/>
|
||||
<configargs>--disable-default-gcc-options --enable-tests</configargs>
|
||||
<configargs>--disable-user-flags --enable-tests</configargs>
|
||||
<builddir>icc</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags>-s -static-libgcc -static-intel</ldflags>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>icc</ccompilerbinary>
|
||||
<cxxcompilerbinary>icpc</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags>-w1</cflags>
|
||||
<cxxflags>-g0 -O3 -m32 -ftrapuv -fstack-security-check -early-template-check -static-libgcc -static-intel -Wcomment -Wdeprecated -Wextra-tokens -Wformat -Wmissing-prototypes -Wnon-virtual-dtor -Wpointer-arith -Wreturn-type -Wshadow -Wtrigraphs -Wuninitialized -w1</cxxflags>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</icc>
|
||||
<win32>
|
||||
<envvars/>
|
||||
<configargs>--enable-default-gcc-options --enable-gcc-optimize --enable-gcc-pch --enable-tests --target=i386-mingw32msvc --host=i386-mingw32msvc --build=i686-linux PKG_CONFIG_PATH=/target/lib/pkgconfig PKG_CONFIG_LIBDIR=/target/lib PATH="/opt/cross-tools/bin:/target/bin:$PATH"</configargs>
|
||||
<configargs>--disable-user-flags --enable-debug-options --enable-tests --target=i386-mingw32msvc --host=i386-mingw32msvc --build=i686-linux PKG_CONFIG_PATH=/target/lib/pkgconfig PKG_CONFIG_LIBDIR=/target/lib PATH="/opt/cross-tools/bin:/target/bin:$PATH"</configargs>
|
||||
<builddir>win32</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
@@ -119,8 +119,8 @@
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
<ccompilerbinary>"i386-mingw32msvc-gcc -mms-bitfields"</ccompilerbinary>
|
||||
<cxxcompilerbinary>"i386-mingw32msvc-g++ -mms-bitfields"</cxxcompilerbinary>
|
||||
<ccompilerbinary>i386-mingw32msvc-gcc</ccompilerbinary>
|
||||
<cxxcompilerbinary>i386-mingw32msvc-g++</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
@@ -130,7 +130,7 @@
|
||||
<envvars>
|
||||
<envvar value="/opt/sun/sunstudio12/bin:$PATH" name="PATH" />
|
||||
</envvars>
|
||||
<configargs>--disable-default-gcc-options --enable-tests</configargs>
|
||||
<configargs>--enable-tests</configargs>
|
||||
<builddir>suncc</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
@@ -141,8 +141,8 @@
|
||||
<ccompilerbinary>suncc</ccompilerbinary>
|
||||
<cxxcompilerbinary>sunCC</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags>-DDEBUG -DDEBUG_BUILD</cflags>
|
||||
<cxxflags>+w -errtags -erroff=notemsource,notused -features=extensions -DHZ_FORCE_GLOBAL_MACROS -DDEBUG -DDEBUG_BUILD -DGLIBMM_HAVE_SUN_REVERSE_ITERATOR -DSIGC_HAVE_SUN_REVERSE_ITERATOR</cxxflags>
|
||||
<cflags>-errwarn=%all</cflags>
|
||||
<cxxflags>-DGLIBMM_HAVE_SUN_REVERSE_ITERATOR -DSIGC_HAVE_SUN_REVERSE_ITERATOR</cxxflags>
|
||||
<f77flags/>
|
||||
</suncc>
|
||||
<portland>
|
||||
@@ -151,7 +151,7 @@
|
||||
<builddir>portland</builddir>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ldflags>-s</ldflags>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevg77options</f77compiler>
|
||||
@@ -159,7 +159,7 @@
|
||||
<cxxcompilerbinary>pgCC</cxxcompilerbinary>
|
||||
<f77compilerbinary/>
|
||||
<cflags>-Minform=warn -Bstatic_pgi</cflags>
|
||||
<cxxflags>-Minform=warn -Bstatic_pgi -noswitcherror -define_macro=HZ_FORCE_GLOBAL_MACROS</cxxflags>
|
||||
<cxxflags>-Minform=warn -Bstatic_pgi -noswitcherror -define_macro=HZ_NO_COMPILER_AUTOINCLUDE</cxxflags>
|
||||
<f77flags/>
|
||||
</portland>
|
||||
</configurations>
|
||||
@@ -10,6 +10,12 @@ Source: gsmartcontrol-%{version}.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
Summary: GSmartControl - Hard Disk Health Inspection Tool
|
||||
|
||||
# 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))
|
||||
@@ -17,10 +23,10 @@ Summary: GSmartControl - Hard Disk Health Inspection Tool
|
||||
# For non-specified distributions we don't specify any dependencies to avoid errors.
|
||||
|
||||
|
||||
# SUSE, OpenSUSE. SLES also defines the correct suse_version.
|
||||
# SUSE / OpenSUSE. SLES also defines the correct suse_version.
|
||||
%if 0%{?suse_version}
|
||||
|
||||
%if %suse_version >= 1030
|
||||
%if 0%{?%suse_version} >= 1030
|
||||
Requires: smartmontools, pcre, gtkmm2 >= 2.12.0
|
||||
BuildRequires: gcc-c++ libstdc++-devel pcre-devel, gtkmm2-devel >= 2.12.0
|
||||
%else
|
||||
@@ -83,7 +89,7 @@ if [ "$numprocs" = "0" ]; then
|
||||
fi
|
||||
|
||||
make -j$numprocs
|
||||
#make
|
||||
# make
|
||||
|
||||
|
||||
%install
|
||||
@@ -99,13 +105,13 @@ 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
|
||||
|
||||
%{_datadir}/gsmartcontrol
|
||||
%{_datadir}/gsmartcontrol/*
|
||||
%{_datadir}/applications/*
|
||||
# %{_datadir}/gsmartcontrol/*
|
||||
%{_datadir}/applications/*.desktop
|
||||
%{_datadir}/icons/*
|
||||
%{_datadir}/pixmaps/*
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
See NEWS file.
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
|
||||
|
||||
AC_DEFUN([AC_CXX_VAR_FUNC],
|
||||
[AC_CACHE_CHECK(whether $CXX recognizes __func__,
|
||||
ac_cv_cxx_var_func,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[const char* s = __func__;]])],[ac_cv_cxx_var_func=yes],[ac_cv_cxx_var_func=no])
|
||||
AC_LANG_POP([])
|
||||
])
|
||||
if test "$ac_cv_cxx_var_func" = yes; then
|
||||
AC_DEFINE(HAVE_CXX__FUNC,,[Define if the C++ complier supports __func__])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
@@ -1,408 +0,0 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <ios> // std::boolalpha
|
||||
// #include <glibmm/fileutils.h> // Dir
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets()
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_dir.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
|
||||
#include "app_pcrecpp.h"
|
||||
#include "storage_detector.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
// inline std::string detect_drives_linux_sys_block(std::vector<StorageDeviceRefPtr>& drives)
|
||||
// {
|
||||
// hz::Dir dir("/sys/block");
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// Linux 2.6 with udev. Scan /dev/disk/by-id - the directory entries there
|
||||
// are symlinks to respective /dev devices. Some devices have multiple
|
||||
// links pointing to them, so unique filter is needed.
|
||||
/*
|
||||
Sample listing:
|
||||
------------------------------------------------------------
|
||||
# ls -1 /dev/disk/by-id
|
||||
ata-ST31000340AS_9QJ0FFG7
|
||||
ata-ST31000340AS_9QJ0FFG7-part1
|
||||
ata-ST31000340AS_9QJ0FFG7-part2
|
||||
ata-ST3500630AS_9QG0R38D
|
||||
ata-ST3500630AS_9QG0R38D-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part2
|
||||
scsi-SATA_ST3500630AS_9QG0R38D
|
||||
scsi-SATA_ST3500630AS_9QG0R38D-part1
|
||||
*/
|
||||
inline std::string detect_drives_linux_udev_byid(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through device scan directory...\n");
|
||||
|
||||
std::string dev_dir; // this defaults to "/dev/disk/by-id"
|
||||
if (!rconfig::get_data("system/linux_udev_byid_path", dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory path is not set.\n");
|
||||
return "Device scan directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.entry_list(all_devices, false)) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
blacklist.push_back("/-part[0-9]+$/");
|
||||
|
||||
// filter-out the ones with "partN" in them
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// those are usually relative links, so find out where they are pointing to.
|
||||
std::string link_dest;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
path.compress(); // compress in case there are ../-s.
|
||||
}
|
||||
|
||||
// skip number-ended devices, in case we couldn't filter out the scan directory correctly
|
||||
// (it's user-settable after all).
|
||||
// if (app_pcre_match("/[0-9]+$/", path.str()))
|
||||
// continue;
|
||||
|
||||
if (std::find(devices.begin(), devices.end(), path.str()) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path.str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Procfs files don't support SEEK_END or ftello() (I think). Anyway, they can't
|
||||
// be read through hz::File::get_contents, so use this function instead.
|
||||
inline bool read_proc_partitions_file(hz::File& file, std::vector<std::string>& lines)
|
||||
{
|
||||
if (!file.open("rb")) // closed automatically
|
||||
return false; // the error message is in File itself.
|
||||
|
||||
FILE* fp = file.get_handle();
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char line[256];
|
||||
while (std::fgets(line, sizeof(line), fp) != NULL) {
|
||||
if (*line != '\0')
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Linux (tested with 2.4 and 2.6) /proc/partitions. Parses the file, appends /dev to each entry.
|
||||
// Note that file format changed from 2.4 to 2.6 (some statistics fields moved to another file).
|
||||
/*
|
||||
Sample 1 (2.4, devfs, with statistics):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
||||
|
||||
3 0 60051600 ide/host0/bus0/target0/lun0/disc 72159 136746 1668720 467190 383039 658435 8342136 1659840 -429 17038808 22703194
|
||||
3 1 1638598 ide/host0/bus0/target0/lun0/part1 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 2 1028160 ide/host0/bus0/target0/lun0/part2 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3092512 ide/host0/bus0/target0/lun0/part3 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 4 1 ide/host0/bus0/target0/lun0/part4 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 5 514048 ide/host0/bus0/target0/lun0/part5 1458 7877 74680 9070 2140 18285 166272 42490 0 10100 52000
|
||||
------------------------------------------------------------
|
||||
Sample 2 (2.6):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
1 0 4096 ram0
|
||||
8 0 156290904 sda
|
||||
8 1 39070048 sda1
|
||||
8 2 7560 sda2
|
||||
8 3 1 sda3
|
||||
------------------------------------------------------------
|
||||
Sample 3 (2.6 on nokia n8xx, spaces may be missing):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
31 0 128 mtdblock0
|
||||
31 1 384 mtdblock1
|
||||
31 2 2048 mtdblock2
|
||||
31 3 2048 mtdblock3
|
||||
31 4 257536 mtdblock4
|
||||
254 0 3932160 mmcblk0
|
||||
254 1 3928064 mmcblk0p1
|
||||
254 8 1966080 mmcblk1
|
||||
254 9 2007032 mmcblk1p1
|
||||
*/
|
||||
inline std::string detect_drives_linux_proc_partitions(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through partitions file...\n");
|
||||
|
||||
std::string parts_file;
|
||||
if (!rconfig::get_data("system/linux_proc_partitions_path", parts_file) || parts_file.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file path is not set.\n");
|
||||
return "Partitions file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(parts_file);
|
||||
// std::string contents;
|
||||
std::vector<std::string> lines;
|
||||
// if (!f.get_contents(contents)) {
|
||||
if (!read_proc_partitions_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Partitions file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
// debug_out_dump("app", DBG_FUNC_MSG << "Dumping partitions file:\n" << contents << "\n");
|
||||
|
||||
// hz::string_split(contents, '\n', lines, true);
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
// fixme: not sure about how partitions are visible with twa0.
|
||||
blacklist.push_back("/d[a-z][0-9]+$/"); // sda1, hdb2 - partitions. twa0 and twe1 are drives, not partitions.
|
||||
blacklist.push_back("/ram[0-9]+$/");
|
||||
blacklist.push_back("/loop[0-9]*$/");
|
||||
blacklist.push_back("/part[0-9]+$/");
|
||||
blacklist.push_back("/p[0-9]+$/");
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < lines.size(); ++i) {
|
||||
std::string line = hz::string_trim_copy(lines[i]);
|
||||
if (line.empty() || app_pcre_match("/^major/", line)) // file header
|
||||
continue;
|
||||
|
||||
std::string dev;
|
||||
if (!app_pcre_match("/^[ \\t]*[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+([^ \\t\\n]+)/", line, &dev) || dev.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse line \"" << line << "\".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, dev)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
std::string path = "/dev/" + dev;
|
||||
if (std::find(devices.begin(), devices.end(), path) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path);
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// FreeBSD, etc... .
|
||||
// Linux devices are not listed because /proc/partitions should always exist there.
|
||||
|
||||
inline std::string detect_drives_dev(std::vector<std::string>& devices)
|
||||
{
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline std::string detect_drives_win32(std::vector<std::string>& devices)
|
||||
{
|
||||
|
||||
return std::string();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Starting drive detection.\n");
|
||||
|
||||
std::vector<std::string> devices;
|
||||
std::string error_msg;
|
||||
bool found = false;
|
||||
|
||||
// Try each one and move to next if it fails.
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_udev_byid(devices); // linux udev
|
||||
// we check for devices vector emptiness because it could be a dummy directory
|
||||
// with no files, so treat it as an error.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_proc_partitions(devices); // linux /proc/partitions as fallback.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (!found) {
|
||||
error_msg = detect_drives_dev(devices); // bsd, etc... . scans /dev.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (!found) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot detect drives: None of the drive detection methods returned any drives.\n");
|
||||
return error_msg; // last error message should be ok.
|
||||
}
|
||||
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter = devices.begin(); iter != devices.end(); ++iter) {
|
||||
std::string dev = *iter;
|
||||
|
||||
// try to match against patterns
|
||||
// for (unsigned int i = 0; i < match_patterns_.size(); i++) {
|
||||
// try to match against general filter
|
||||
// if (!app_pcre_match(match_patterns_[i], dev))
|
||||
// continue;
|
||||
|
||||
// matched, check the blacklist
|
||||
bool blacked = false;
|
||||
for (unsigned int j = 0; j < blacklist_patterns_.size(); j++) {
|
||||
if (app_pcre_match(blacklist_patterns_[j], dev)) { // matched the blacklist too
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StorageDeviceRefPtr drive(new StorageDevice(dev));
|
||||
debug_out_info("app", "Found device: \"" << drive->get_device() << "\".\n");
|
||||
|
||||
if (!blacked) {
|
||||
drives.push_back(drive);
|
||||
// break; // no need to match other patters, go to next device
|
||||
|
||||
} else { // blacklisted
|
||||
debug_out_info("app", "Device \"" << drive->get_device() << "\" is blacklisted, ignoring.\n");
|
||||
// break; // go to next device
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Drive detection finished.\n");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>& drives,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex, bool return_first_error)
|
||||
{
|
||||
fetch_data_errors_.clear();
|
||||
fetch_data_error_outputs_.clear();
|
||||
|
||||
for (unsigned int i = 0; i < drives.size(); ++i) {
|
||||
StorageDeviceRefPtr drive = drives[i];
|
||||
debug_out_info("app", "Retrieving basic information about the device...\n");
|
||||
|
||||
smartctl_ex->set_running_msg("Running %s on " + drive->get_device() + "...");
|
||||
|
||||
// don't show any errors here - we don't want a screen flood.
|
||||
// no need for gui-based executors here, we already show the message in
|
||||
// iconview background (if called from main window)
|
||||
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
|
||||
// normally we skip drives with errors - possibly scsi, etc...
|
||||
if (return_first_error && !error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
// use original executor error if present (permits matches by our users).
|
||||
// if (!smartctl_ex->get_error_msg().empty())
|
||||
// error_msg = smartctl_ex->get_error_msg();
|
||||
|
||||
fetch_data_errors_.push_back(error_msg);
|
||||
fetch_data_error_outputs_.push_back(smartctl_ex->get_stdout_str());
|
||||
}
|
||||
|
||||
debug_out_dump("app", "Device information for " << drive->get_device() << ":\n"
|
||||
<< "\tModel: " << drive->get_model_name() << "\n"
|
||||
<< "\tType: " << StorageDevice::get_type_name(drive->get_type()) << "\n"
|
||||
<< "\tSMART status: " << StorageDevice::get_status_name(drive->get_smart_status()) << "\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::detect_and_fetch_basic_data(std::vector<StorageDeviceRefPtr>& put_drives_here,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
{
|
||||
std::string error_msg = detect(put_drives_here);
|
||||
|
||||
if (error_msg.empty())
|
||||
fetch_basic_data(put_drives_here, smartctl_ex, false); // ignore its errors, there may be plenty of them.
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
AM_CPPFLAGS = $(all_includes)
|
||||
METASOURCES = AUTO
|
||||
|
||||
|
||||
bin_PROGRAMS = gsmartcontrol
|
||||
|
||||
SUBDIRS = libdebug hz rmn rconfig pcrecpp applib res
|
||||
@@ -25,6 +25,8 @@ smartctl_parser_test_SOURCES = smartctl_parser_test.cpp
|
||||
smartctl_parser_test_LDADD = libapplib.a \
|
||||
$(top_builddir)/src/pcrecpp/libpcrecpp.a $(top_builddir)/src/libdebug/libdebug.a
|
||||
|
||||
spawn_test_SOURCES = spawn_test.cpp
|
||||
|
||||
# Build them first
|
||||
SUBDIRS=../libdebug ../pcrecpp
|
||||
|
||||
@@ -33,7 +35,7 @@ SUBDIRS=../libdebug ../pcrecpp
|
||||
noinst_PROGRAMS =
|
||||
if ENABLE_TESTS
|
||||
noinst_PROGRAMS += smartctl_executor_test smartctl_parser_test \
|
||||
storage_detector_test
|
||||
storage_detector_test spawn_test
|
||||
endif
|
||||
|
||||
tests: $(noinst_PROGRAMS)
|
||||
@@ -10,7 +10,9 @@
|
||||
#include <string>
|
||||
#include <gtkmm/window.h>
|
||||
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#include "hz/hz_config.h" // feature test macros (ENABLE_*)
|
||||
|
||||
#if defined ENABLE_LIBGLADE
|
||||
#include <libglademm.h>
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
#include <gtkmm/builder.h>
|
||||
@@ -42,7 +44,7 @@
|
||||
// Or, if you're using compiled-in buffers, it will make them available.
|
||||
|
||||
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#if defined ENABLE_LIBGLADE
|
||||
|
||||
#define APP_UI_RES_DATA_INIT(res_name) \
|
||||
HZ_RES_DATA_INIT_NAMED(res_name##_ui, #res_name ".glade", UIResDataBase); \
|
||||
@@ -51,7 +53,7 @@
|
||||
{ \
|
||||
UIResDataBase::root_name = #res_name; /* we need original name here, not with _ui */ \
|
||||
} \
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
@@ -63,7 +65,7 @@
|
||||
{ \
|
||||
UIResDataBase::root_name = #res_name; /* we need original name here, not with _ui */ \
|
||||
} \
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#else // none, just avoid errors
|
||||
@@ -75,14 +77,14 @@
|
||||
{ \
|
||||
UIResDataBase::root_name = #res_name; /* we need original name here, not with _ui */ \
|
||||
} \
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#if defined ENABLE_LIBGLADE
|
||||
|
||||
typedef Glib::RefPtr<Gnome::Glade::Xml> app_ui_res_ref_t;
|
||||
|
||||
@@ -215,7 +217,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
|
||||
typedef hz::InstanceManager<Child, MultiInstance> instance_class;
|
||||
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#if defined ENABLE_LIBGLADE
|
||||
friend class Gnome::Glade::Xml; // allow construction through libglade
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
friend class Gtk::Builder; // allow construction through gtkbuilder
|
||||
@@ -230,7 +232,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
return hz::InstanceManager<Child, MultiInstance>::get_single_instance();
|
||||
|
||||
std::string error;
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#if defined ENABLE_LIBGLADE
|
||||
app_ui_res_ref_t ui;
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
app_ui_res_ref_t ui = Gtk::Builder::create();
|
||||
@@ -297,7 +299,7 @@ class AppUIResWidget : public WidgetType, public hz::InstanceManager<Child, Mult
|
||||
|
||||
Glib::Object* lookup_object(const Glib::ustring& name)
|
||||
{
|
||||
#if defined ENABLE_LIBGLADEMM
|
||||
#if defined ENABLE_LIBGLADE
|
||||
return static_cast<Glib::Object*>(lookup_widget(name)); // all glade objects are widgets, it's an upcast
|
||||
#elif defined ENABLE_GTKBUILDER
|
||||
return ref_ui_->get_object(name).operator->(); // silly RefPtr doesn't have get().
|
||||
@@ -8,19 +8,16 @@
|
||||
#include <cerrno> // errno (not std::errno, it may be a macro)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h> // close()
|
||||
// #include <io.h> // close()
|
||||
#else
|
||||
#include <sys/wait.h> // waitpid()'s W* macros
|
||||
#include <unistd.h> // close()
|
||||
// #include <unistd.h> // close()
|
||||
#endif
|
||||
|
||||
#include <glibmm/shell.h>
|
||||
#include <glibmm/miscutils.h> // get_current_dir()
|
||||
#include <glibmm/convert.h>
|
||||
|
||||
#include "hz/tls.h"
|
||||
#include "hz/tls_policy_glib.h"
|
||||
#include "hz/debug.h"
|
||||
#include "hz/string_num.h" // hz::number_to_string()
|
||||
|
||||
#include "cmdex.h"
|
||||
|
||||
@@ -41,40 +38,40 @@ extern "C" {
|
||||
|
||||
// NOTE: These functions are called in a separate threads!
|
||||
|
||||
inline void command_executor_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data)
|
||||
inline void cmdex_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer data)
|
||||
{
|
||||
Cmdex::on_child_watch_handler(arg_pid, waitpid_status, data);
|
||||
}
|
||||
|
||||
|
||||
inline gboolean command_executor_on_channel_io_stdout_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stdout_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_as_available(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stdout);
|
||||
}
|
||||
|
||||
inline gboolean command_executor_on_channel_io_stderr_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stderr_as_available(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_as_available(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stderr);
|
||||
}
|
||||
|
||||
|
||||
inline gboolean command_executor_on_channel_io_stdout_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stdout_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_buffered(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stdout);
|
||||
}
|
||||
|
||||
inline gboolean command_executor_on_channel_io_stderr_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
inline gboolean cmdex_on_channel_io_stderr_buffered(GIOChannel* source, GIOCondition cond, gpointer data)
|
||||
{
|
||||
return Cmdex::on_channel_io_buffered(source, cond, static_cast<Cmdex*>(data), Cmdex::channel_type_stderr);
|
||||
}
|
||||
|
||||
|
||||
inline void command_executor_on_buffered_source_destroy(gpointer data);
|
||||
inline void cmdex_on_buffered_source_destroy(gpointer data);
|
||||
|
||||
|
||||
|
||||
// this is executed in another thread!
|
||||
inline gboolean command_executor_on_term_timeout(gpointer data)
|
||||
inline gboolean cmdex_on_term_timeout(gpointer data)
|
||||
{
|
||||
DBG_FUNCTION_ENTER_MSG;
|
||||
Cmdex* self = static_cast<Cmdex*>(data);
|
||||
@@ -84,7 +81,7 @@ extern "C" {
|
||||
|
||||
|
||||
// this is executed in another thread!
|
||||
inline gboolean command_executor_on_kill_timeout(gpointer data)
|
||||
inline gboolean cmdex_on_kill_timeout(gpointer data)
|
||||
{
|
||||
DBG_FUNCTION_ENTER_MSG;
|
||||
Cmdex* self = static_cast<Cmdex*>(data);
|
||||
@@ -104,114 +101,135 @@ bool Cmdex::execute()
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
|
||||
if (this->running || this->stopped_cleanup_needed(false))
|
||||
if (this->running_ || this->stopped_cleanup_needed(false))
|
||||
return false;
|
||||
|
||||
cleanup_members();
|
||||
clear_errors(false); // don't lock
|
||||
str_stdout.clear();
|
||||
str_stderr.clear();
|
||||
str_stdout_.clear();
|
||||
str_stderr_.clear();
|
||||
|
||||
|
||||
std::string cmd = command_exec + " " + command_args;
|
||||
std::deque<std::string> child_argv;
|
||||
std::string cmd = command_exec_ + " " + command_args_;
|
||||
|
||||
try {
|
||||
child_argv = Glib::shell_parse_argv(cmd);
|
||||
}
|
||||
catch (Glib::ShellError& e) {
|
||||
push_error(Error<Glib::ShellError>("gshell", ErrorLevel::error, e, e.what()), false);
|
||||
|
||||
// Make command vector
|
||||
|
||||
int argcp = 0; // number of args
|
||||
gchar** argvp = 0; // args vector
|
||||
GError* shell_error = 0;
|
||||
if (!g_shell_parse_argv(cmd.c_str(), &argcp, &argvp, &shell_error)) {
|
||||
push_error(Error<void>("gshell", ErrorLevel::error, shell_error->message), false);
|
||||
g_error_free(shell_error);
|
||||
|
||||
g_strfreev(argvp);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Reset the locale - otherwise it may mangle the output.
|
||||
bool old_lang_set = false;
|
||||
std::string old_lang = Glib::getenv("LANG", old_lang_set);
|
||||
|
||||
// TODO: make this controllable.
|
||||
const gchar* old_lang_gchar = g_getenv("LANG");
|
||||
bool old_lang_set = (old_lang_gchar);
|
||||
std::string old_lang = (old_lang_gchar ? old_lang_gchar : "");
|
||||
if (old_lang_set)
|
||||
Glib::setenv("LANG", "C");
|
||||
g_setenv("LANG", "C", true);
|
||||
|
||||
try {
|
||||
// execute the command
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Executing \"" << cmd << "\".\n");
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Executing \"" << cmd << "\".\n");
|
||||
|
||||
|
||||
|
||||
// Execute the command
|
||||
|
||||
gchar* curr_dir = g_get_current_dir();
|
||||
GError* spawn_error = 0;
|
||||
|
||||
if (!g_spawn_async_with_pipes(curr_dir, argvp, NULL,
|
||||
GSpawnFlags(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD),
|
||||
NULL, NULL, // child setup function
|
||||
&this->pid_, 0, &fd_stdout_, &fd_stderr_, &spawn_error)) {
|
||||
|
||||
push_error(Error<void>("gspawn", ErrorLevel::error, spawn_error->message), false);
|
||||
g_error_free(spawn_error);
|
||||
|
||||
g_free(curr_dir);
|
||||
g_strfreev(argvp);
|
||||
|
||||
Glib::spawn_async_with_pipes(Glib::get_current_dir(), child_argv,
|
||||
Glib::SPAWN_SEARCH_PATH | Glib::SPAWN_DO_NOT_REAP_CHILD,
|
||||
sigc::slot<void>(), &this->pid,
|
||||
0, &fd_stdout, &fd_stderr);
|
||||
}
|
||||
catch (Glib::SpawnError& e) {
|
||||
push_error(Error<Glib::SpawnError>("gspawn", ErrorLevel::error, e, e.what()), false);
|
||||
if (old_lang_set)
|
||||
Glib::setenv("LANG", old_lang);
|
||||
g_setenv("LANG", old_lang.c_str(), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_free(curr_dir);
|
||||
g_strfreev(argvp);
|
||||
|
||||
if (old_lang_set)
|
||||
Glib::setenv("LANG", old_lang);
|
||||
g_setenv("LANG", old_lang.c_str(), true);
|
||||
|
||||
|
||||
this->timer.start(); // start the timer
|
||||
g_timer_start(timer_); // start the timer
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
channel_stdout = Glib::IOChannel::create_from_win32_fd(fd_stdout);
|
||||
channel_stderr = Glib::IOChannel::create_from_win32_fd(fd_stderr);
|
||||
channel_stdout_ = g_io_channel_win32_new_fd(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_win32_new_fd(fd_stderr_);
|
||||
#else
|
||||
channel_stdout = Glib::IOChannel::create_from_fd(fd_stdout);
|
||||
channel_stderr = Glib::IOChannel::create_from_fd(fd_stderr);
|
||||
channel_stdout_ = g_io_channel_unix_new(fd_stdout_);
|
||||
channel_stderr_ = g_io_channel_unix_new(fd_stderr_);
|
||||
#endif
|
||||
|
||||
// The internal encoding is always UTF8. To read command output correctly, use
|
||||
// "" for binary data, or set io encoding to current locale.
|
||||
// If using locales, call Glib::locale_to_utf8() or Glib::convert() afterwards.
|
||||
// If using locales, call g_locale_to_utf8() or g_convert() afterwards.
|
||||
|
||||
// std::string charset;
|
||||
// Glib::get_charset(charset);
|
||||
try {
|
||||
channel_stdout->set_encoding(""); // binary IO
|
||||
channel_stderr->set_encoding(""); // binary IO
|
||||
// blocking writes if the pipe is full helps for small-pipe systems (see man 7 pipe).
|
||||
GIOFlags channel_flags = GIOFlags(~G_IO_FLAG_NONBLOCK);
|
||||
|
||||
// blocking writes if the pipe is full helps for small-pipe systems (see man 7 pipe).
|
||||
Glib::IOFlags flags = ~Glib::IO_FLAG_NONBLOCK;
|
||||
channel_stdout->set_flags(flags);
|
||||
channel_stderr->set_flags(flags);
|
||||
|
||||
channel_stdout->set_buffer_size(channel_stdout_buffer_size);
|
||||
channel_stderr->set_buffer_size(channel_stderr_buffer_size);
|
||||
// Note about GError's here:
|
||||
// What do we do? The command is already running, so let's ignore these
|
||||
// errors - it's better to get a slightly mangled buffer than to abort the
|
||||
// command in the mid-run.
|
||||
if (channel_stdout_) {
|
||||
// Since we invoke shutdown() manually before unref(), this would cause
|
||||
// a double-shutdown.
|
||||
// g_io_channel_set_close_on_unref(channel_stdout_, true); // close() on fd
|
||||
g_io_channel_set_encoding(channel_stdout_, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stdout_, channel_flags, 0);
|
||||
g_io_channel_set_buffer_size(channel_stdout_, channel_stdout_buffer_size_);
|
||||
}
|
||||
catch (Glib::IOChannelError& e) {
|
||||
// What do we do? The command is already running, so let's ignore these
|
||||
// errors - it's better to get a slightly mangled buffer than to abort the
|
||||
// command in the mid-run.
|
||||
if (channel_stderr_) {
|
||||
// g_io_channel_set_close_on_unref(channel_stderr_, true); // close() on fd
|
||||
g_io_channel_set_encoding(channel_stderr_, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stderr_, channel_flags, 0);
|
||||
g_io_channel_set_buffer_size(channel_stderr_, channel_stderr_buffer_size_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Note: glib callbacks _are_ invoked in separate threads,
|
||||
// so proper locking is necessary.
|
||||
// This is different from gtk callbacks, which are directly invoked from main loop
|
||||
// in the same thread.
|
||||
|
||||
// this doesn't really work
|
||||
// Glib::signal_io().connect(sigc::bind(sigc::ptr_fun(&io_handler), this), channel_stdout, cond);
|
||||
|
||||
GIOCondition cond = GIOCondition(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL);
|
||||
gint io_thread_priority = G_PRIORITY_HIGH; // channel reader callback thread must read enough so that the loss is minimal
|
||||
|
||||
if (this->stdout_make_str_as_available) {
|
||||
this->event_source_id_stdout = g_io_add_watch_full(channel_stdout->gobj(), io_thread_priority, cond,
|
||||
&command_executor_on_channel_io_stdout_as_available, this, NULL);
|
||||
if (this->stdout_make_str_as_available_) {
|
||||
this->event_source_id_stdout_ = g_io_add_watch_full(channel_stdout_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stdout_as_available, this, NULL);
|
||||
} else {
|
||||
this->event_source_id_stdout = g_io_add_watch_full(channel_stdout->gobj(), io_thread_priority, cond,
|
||||
&command_executor_on_channel_io_stdout_buffered, this, command_executor_on_buffered_source_destroy);
|
||||
this->event_source_id_stdout_ = g_io_add_watch_full(channel_stdout_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stdout_buffered, this, cmdex_on_buffered_source_destroy);
|
||||
}
|
||||
|
||||
if (this->stderr_make_str_as_available) {
|
||||
this->event_source_id_stderr = g_io_add_watch_full(channel_stderr->gobj(), io_thread_priority, cond,
|
||||
&command_executor_on_channel_io_stderr_as_available, this, NULL);
|
||||
if (this->stderr_make_str_as_available_) {
|
||||
this->event_source_id_stderr_ = g_io_add_watch_full(channel_stderr_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stderr_as_available, this, NULL);
|
||||
} else {
|
||||
this->event_source_id_stderr = g_io_add_watch_full(channel_stderr->gobj(), io_thread_priority, cond,
|
||||
&command_executor_on_channel_io_stderr_buffered, this, command_executor_on_buffered_source_destroy);
|
||||
this->event_source_id_stderr_ = g_io_add_watch_full(channel_stderr_, io_thread_priority, cond,
|
||||
&cmdex_on_channel_io_stderr_buffered, this, cmdex_on_buffered_source_destroy);
|
||||
}
|
||||
|
||||
|
||||
@@ -220,11 +238,11 @@ bool Cmdex::execute()
|
||||
// The watch function is protected by mutex and won't be called before execute() exits.
|
||||
// This is AFTER the channels so that it doesn't get called before the channels are attached (is this needed?).
|
||||
// (the child stops being a zombie as soon as wait*() exits and this handler is called).
|
||||
g_child_watch_add(static_cast<GPid>(this->pid), &command_executor_child_watch_handler, this);
|
||||
g_child_watch_add(this->pid_, &cmdex_child_watch_handler, this);
|
||||
|
||||
|
||||
|
||||
this->running = true; // process is running now.
|
||||
this->running_ = true; // process is running now.
|
||||
// actually, it may be already stopped, but the watcher function is blocked
|
||||
// until we exit, so the actions are serialized.
|
||||
|
||||
@@ -239,15 +257,15 @@ bool Cmdex::try_stop(hz::signal_t sig)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
|
||||
if (!this->running || this->pid <= 0)
|
||||
if (!this->running_ || this->pid_ <= 0)
|
||||
return false;
|
||||
|
||||
// other variants: SIGHUP(1) (terminal closed), SIGINT(2) (Ctrl-C),
|
||||
// SIGKILL(9) (kill).
|
||||
// Note that SIGKILL cannot be trapped by any process.
|
||||
|
||||
if (process_signal_send(this->pid, sig) == 0) { // success
|
||||
this->kill_signal_sent = static_cast<int>(sig); // just the number to compare later.
|
||||
if (process_signal_send(this->pid_, sig) == 0) { // success
|
||||
this->kill_signal_sent_ = static_cast<int>(sig); // just the number to compare later.
|
||||
return true; // the rest is done by a handler
|
||||
}
|
||||
|
||||
@@ -265,16 +283,16 @@ void Cmdex::set_stop_timeouts(int term_timeout_msec, int kill_timeout_msec)
|
||||
DBG_ASSERT(term_timeout_msec == 0 || kill_timeout_msec == 0 || kill_timeout_msec > term_timeout_msec);
|
||||
ScopedLock locker(object_mutex_); // member access / serialization lock
|
||||
|
||||
if (!this->running) // process not running
|
||||
if (!this->running_) // process not running
|
||||
return;
|
||||
|
||||
unset_stop_timeouts(false);
|
||||
|
||||
if (term_timeout_msec != 0)
|
||||
event_source_id_term = g_timeout_add(term_timeout_msec, &command_executor_on_term_timeout, this);
|
||||
event_source_id_term = g_timeout_add(term_timeout_msec, &cmdex_on_term_timeout, this);
|
||||
|
||||
if (kill_timeout_msec != 0)
|
||||
event_source_id_kill = g_timeout_add(kill_timeout_msec, &command_executor_on_kill_timeout, this);
|
||||
event_source_id_kill = g_timeout_add(kill_timeout_msec, &cmdex_on_kill_timeout, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -307,7 +325,7 @@ void Cmdex::stopped_cleanup()
|
||||
// DBG_FUNCTION_ENTER_MSG;
|
||||
ScopedLock locker(object_mutex_); // member access / serialization lock
|
||||
|
||||
if (this->running || !this->stopped_cleanup_needed(false)) // huh?
|
||||
if (this->running_ || !this->stopped_cleanup_needed(false)) // huh?
|
||||
return;
|
||||
|
||||
// remove stop timeout callbacks
|
||||
@@ -315,22 +333,23 @@ void Cmdex::stopped_cleanup()
|
||||
|
||||
|
||||
// various statuses (see waitpid (2)):
|
||||
if (WIFEXITED(waitpid_status)) { // exited normally
|
||||
int exit_status = WEXITSTATUS(waitpid_status);
|
||||
if (WIFEXITED(waitpid_status_)) { // exited normally
|
||||
int exit_status = WEXITSTATUS(waitpid_status_);
|
||||
|
||||
if (exit_status != 0) {
|
||||
// translate the exit_code into a message
|
||||
Glib::ustring msg = signal_exit_status_translator.emit(exit_status);
|
||||
std::string msg = (translator_func_ ? translator_func_(exit_status, translator_func_data_)
|
||||
: "[no translator function, exit code: " + hz::number_to_string(exit_status));
|
||||
push_error(Error<int>("exit", ErrorLevel::warn, exit_status, msg), false);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (WIFSIGNALED(waitpid_status)) { // exited by signal
|
||||
int sig_num = WTERMSIG(waitpid_status);
|
||||
if (WIFSIGNALED(waitpid_status_)) { // exited by signal
|
||||
int sig_num = WTERMSIG(waitpid_status_);
|
||||
|
||||
// If it's not our signal, treat as error.
|
||||
// Note: they will never match under win32
|
||||
if (sig_num != this->kill_signal_sent) {
|
||||
if (sig_num != this->kill_signal_sent_) {
|
||||
push_error(Error<int>("signal", ErrorLevel::error, sig_num), false);
|
||||
} else { // it's our signal, treat as warning
|
||||
push_error(Error<int>("signal", ErrorLevel::warn, sig_num), false);
|
||||
@@ -338,11 +357,11 @@ void Cmdex::stopped_cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
Glib::spawn_close_pid(this->pid); // needed to avoid zombies
|
||||
g_spawn_close_pid(this->pid_); // needed to avoid zombies
|
||||
|
||||
cleanup_members();
|
||||
|
||||
this->running = false;
|
||||
this->running_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -357,41 +376,45 @@ void Cmdex::on_child_watch_handler(GPid arg_pid, int waitpid_status, gpointer da
|
||||
|
||||
self->lock();
|
||||
|
||||
self->timer.stop(); // stop the timer
|
||||
g_timer_stop(self->timer_); // stop the timer
|
||||
|
||||
// wait until the IO channels are closed
|
||||
// while (!(self->event_source_stdout_closed && self->event_source_stderr_closed)) {
|
||||
// self->unlock();
|
||||
// Glib::usleep(75*1000); // 75ms
|
||||
// g_usleep(75*1000); // 75ms
|
||||
// self->lock();
|
||||
// }
|
||||
|
||||
self->waitpid_status = waitpid_status;
|
||||
self->child_watch_handler_called = true;
|
||||
self->running = false; // process is not running anymore
|
||||
self->waitpid_status_ = waitpid_status;
|
||||
self->child_watch_handler_called_ = true;
|
||||
self->running_ = false; // process is not running anymore
|
||||
|
||||
|
||||
// Remove fd IO callbacks. They may actually be removed already.
|
||||
// This will force calling the iochannel callback (they may not be called
|
||||
// otherwise at all if there was no output).
|
||||
if (self->event_source_id_stdout) {
|
||||
GSource* source_stdout = g_main_context_find_source_by_id(NULL, self->event_source_id_stdout);
|
||||
if (self->event_source_id_stdout_) {
|
||||
GSource* source_stdout = g_main_context_find_source_by_id(NULL, self->event_source_id_stdout_);
|
||||
if (source_stdout)
|
||||
g_source_destroy(source_stdout);
|
||||
}
|
||||
|
||||
if (self->event_source_id_stderr) {
|
||||
GSource* source_stderr = g_main_context_find_source_by_id(NULL, self->event_source_id_stderr);
|
||||
if (self->event_source_id_stderr_) {
|
||||
GSource* source_stderr = g_main_context_find_source_by_id(NULL, self->event_source_id_stderr_);
|
||||
if (source_stderr)
|
||||
g_source_destroy(source_stderr);
|
||||
}
|
||||
|
||||
// Cose std pipes
|
||||
close(self->fd_stdout);
|
||||
close(self->fd_stderr);
|
||||
// Close std pipes.
|
||||
// The channel closes them now.
|
||||
// close(self->fd_stdout_);
|
||||
// close(self->fd_stderr_);
|
||||
|
||||
|
||||
self->signal_exited.emit(); // ALL slots are called in non-main thread!
|
||||
// Note: This callback is called in non-main thread!
|
||||
if (self->exited_callback_)
|
||||
self->exited_callback_(self->exited_callback_data_);
|
||||
|
||||
|
||||
self->unlock();
|
||||
// DBG_FUNCTION_EXIT_MSG;
|
||||
@@ -421,45 +444,42 @@ gboolean Cmdex::on_channel_io_as_available(GIOChannel* source,
|
||||
// read the bytes one by one. without this, a buffered iochannel hangs while waiting for data.
|
||||
// we don't use unbuffered iochannels - they may lose data on program exit.
|
||||
const gsize count = 1;
|
||||
char buf[count] = {0};
|
||||
gchar buf[count] = {0};
|
||||
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
|
||||
Glib::RefPtr<Glib::IOChannel> channel;
|
||||
GIOChannel* channel = 0;
|
||||
std::string* output_str = 0;
|
||||
if (type == channel_type_stdout) {
|
||||
channel = self->channel_stdout;
|
||||
output_str = &self->str_stdout;
|
||||
channel = self->channel_stdout_;
|
||||
output_str = &self->str_stdout_;
|
||||
} else if (type == channel_type_stderr) {
|
||||
channel = self->channel_stderr;
|
||||
output_str = &self->str_stderr;
|
||||
channel = self->channel_stderr_;
|
||||
output_str = &self->str_stderr_;
|
||||
}
|
||||
|
||||
|
||||
try { // read() may throw something
|
||||
|
||||
// while there's anything to read, read it
|
||||
do {
|
||||
gsize bytes_read = 0;
|
||||
Glib::IOStatus status = channel->read(buf, count, bytes_read);
|
||||
if (bytes_read)
|
||||
output_str->append(buf, bytes_read);
|
||||
// while there's anything to read, read it
|
||||
do {
|
||||
GError* channel_error = 0;
|
||||
gsize bytes_read = 0;
|
||||
GIOStatus status = g_io_channel_read_chars(channel, buf, count, &bytes_read, &channel_error);
|
||||
if (bytes_read)
|
||||
output_str->append(buf, bytes_read);
|
||||
|
||||
// IO_STATUS_NORMAL and IO_STATUS_AGAIN (resource unavailable) are continuable.
|
||||
if (status == Glib::IO_STATUS_ERROR || status == Glib::IO_STATUS_EOF) {
|
||||
continue_events = false;
|
||||
break;
|
||||
}
|
||||
} while (channel->get_buffer_condition() & Glib::IO_IN);
|
||||
if (channel_error) {
|
||||
self->push_error(Error<void>("giochannel", ErrorLevel::error, channel_error->message), false);
|
||||
break; // stop on next invocation (is this correct?)
|
||||
}
|
||||
|
||||
// IO_STATUS_NORMAL and IO_STATUS_AGAIN (resource unavailable) are continuable.
|
||||
if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
|
||||
continue_events = false;
|
||||
break;
|
||||
}
|
||||
} while (g_io_channel_get_buffer_condition(channel) & G_IO_IN);
|
||||
|
||||
}
|
||||
catch (Glib::IOChannelError& e) {
|
||||
self->push_error(Error<Glib::IOChannelError>("giochannel", ErrorLevel::error, e, e.what()), false);
|
||||
}
|
||||
catch (Glib::ConvertError& e) { // no conversion in binary mode, shouldn't happen
|
||||
self->push_error(Error<void>("custom", ErrorLevel::error,
|
||||
"Cmdex::on_channel_io_as_available(): Glib::ConvertError thrown."), false);
|
||||
}
|
||||
|
||||
// false if the source should be removed, true otherwise.
|
||||
return continue_events;
|
||||
@@ -487,7 +507,7 @@ namespace {
|
||||
// This callback is executed from in the same thread as on_channel_io_buffered,
|
||||
// so we get the same variable (tests show cleared s_final_str, but is this really
|
||||
// so? this function is executed during on_child_watch_handler (if spawn-terminated)).
|
||||
inline void command_executor_on_buffered_source_destroy(gpointer data)
|
||||
inline void cmdex_on_buffered_source_destroy(gpointer data)
|
||||
{
|
||||
// DBG_FUNCTION_ENTER_MSG;
|
||||
s_final_str.reset(); // .reset(), not ->clear - we don't want memory leaks in stopped threads.
|
||||
@@ -520,57 +540,45 @@ gboolean Cmdex::on_channel_io_buffered(GIOChannel* source,
|
||||
const gsize count = 1;
|
||||
static char buf[count] = {0};
|
||||
|
||||
// Glib::RefPtr<Glib::IOChannel> channel = Glib::wrap(source); // this segfaults on large data (?)
|
||||
|
||||
// while there's anything to read, read it
|
||||
GError* error = 0;
|
||||
do {
|
||||
GError* channel_error = 0;
|
||||
gsize bytes_read = 0;
|
||||
GIOStatus status = g_io_channel_read_chars(source, buf, count, &bytes_read, &error);
|
||||
GIOStatus status = g_io_channel_read_chars(source, buf, count, &bytes_read, &channel_error);
|
||||
if (bytes_read)
|
||||
s_final_str->append(buf, bytes_read);
|
||||
|
||||
if (channel_error) {
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
self->push_error(Error<void>("giochannel", ErrorLevel::error, channel_error->message), false);
|
||||
break; // stop on next invocation (is this correct?)
|
||||
}
|
||||
|
||||
// IO_STATUS_NORMAL and IO_STATUS_AGAIN (resource unavailable) are continuable.
|
||||
if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
|
||||
continue_events = false;
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
|
||||
} while (g_io_channel_get_buffer_condition(source) & G_IO_IN);
|
||||
|
||||
if (!continue_events || error) { // these conditions need locking
|
||||
|
||||
if (!continue_events) { // need locking
|
||||
Cmdex::ScopedLock locker(self->object_mutex_);
|
||||
|
||||
if (error) {
|
||||
try {
|
||||
Glib::Error::throw_exception(error); // convert GError to exception for easy storage.
|
||||
}
|
||||
catch (Glib::IOChannelError& e) {
|
||||
self->push_error(Error<Glib::IOChannelError>("giochannel", ErrorLevel::error, e, e.what()), false);
|
||||
}
|
||||
catch (Glib::ConvertError& e) { // no conversion in binary mode, shouldn't happen
|
||||
self->push_error(Error<void>("custom", ErrorLevel::error,
|
||||
"Cmdex::on_channel_io_buffered(): Glib::ConvertError thrown."), false);
|
||||
}
|
||||
if (type == channel_type_stdout) {
|
||||
// set the source to be closed (the actual closing is done when we return false).
|
||||
// this is needed for the caller to wait until all the channels are stopped.
|
||||
self->str_stdout_ = *s_final_str;
|
||||
|
||||
} else if (type == channel_type_stderr) {
|
||||
self->str_stderr_ = *s_final_str;
|
||||
}
|
||||
|
||||
if (!continue_events) {
|
||||
if (type == channel_type_stdout) {
|
||||
// set the source to be closed (the actual closing is done when we return false).
|
||||
// this is needed for the caller to wait until all the channels are stopped.
|
||||
self->str_stdout = *s_final_str;
|
||||
|
||||
} else if (type == channel_type_stderr) {
|
||||
self->str_stderr = *s_final_str;
|
||||
}
|
||||
|
||||
// glib may re-use this thread, so do a TLS cleanup.
|
||||
// also, manual cleanup is needed for policies which don't support automatic one.
|
||||
// source_destroy callback already does this, but it won't hurt.
|
||||
s_final_str.reset(); // this will delete the previous contents.
|
||||
}
|
||||
// glib may re-use this thread, so do a TLS cleanup.
|
||||
// also, manual cleanup is needed for policies which don't support automatic one.
|
||||
// source_destroy callback already does this, but it won't hurt.
|
||||
s_final_str.reset(); // this will delete the previous contents.
|
||||
}
|
||||
|
||||
// DBG_FUNCTION_EXIT_MSG;
|
||||
@@ -8,12 +8,7 @@
|
||||
#define APP_CMDEX_H
|
||||
|
||||
#include <string>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <glibmm/iochannel.h>
|
||||
#include <glibmm/thread.h>
|
||||
#include <glibmm/timer.h> // Timer
|
||||
#include <glibmm/spawn.h> // Pid
|
||||
#include <glib.h> // G*, g_*
|
||||
#include <glib.h>
|
||||
|
||||
#include "hz/process_signal.h" // hz::SIGNAL_*, hz::process_signal_send (cpp), win32's W* (cpp)
|
||||
#include "hz/error_holder.h"
|
||||
@@ -41,7 +36,7 @@ from the _main_ thread.
|
||||
|
||||
// inheriting from sigc::trackable automatically disconnects this class's
|
||||
// slots upon destruction.
|
||||
class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable {
|
||||
class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib> {
|
||||
|
||||
public:
|
||||
|
||||
@@ -51,24 +46,26 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
typedef hz::ErrorHolder<hz::SyncPolicyGlib>::ErrorScopedLock ScopedLock;
|
||||
typedef hz::ErrorHolder<hz::SyncPolicyGlib>::ErrorLockPolicy LockPolicy;
|
||||
|
||||
typedef std::string (*exit_status_translator_func_t)(int, void*);
|
||||
typedef void (*exited_callback_func_t)(void*);
|
||||
|
||||
|
||||
Cmdex(
|
||||
//const sigc::slot<Glib::ustring, int>& slot_exit_status_translator,
|
||||
const sigc::slot<void>& slot_exited = sigc::slot<void>()
|
||||
// exit_status_translator_func_t translator_func,
|
||||
exited_callback_func_t exited_cb = NULL, void* exited_cb_data = NULL
|
||||
)
|
||||
: object_mutex_(error_object_mutex_),
|
||||
running(false), kill_signal_sent(0), child_watch_handler_called(false),
|
||||
pid(0), waitpid_status(0),
|
||||
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_buffer_size(100 * 1024), channel_stderr_buffer_size(10 * 1024), // 100K and 10K
|
||||
event_source_id_stdout(0), event_source_id_stderr(0),
|
||||
stdout_make_str_as_available(false), stderr_make_str_as_available(true)
|
||||
{
|
||||
// signal_exit_status_translator.connect(slot_exit_status_translator);
|
||||
if (!slot_exited.empty())
|
||||
signal_exited.connect(slot_exited);
|
||||
}
|
||||
fd_stdout_(0), fd_stderr_(0), channel_stdout_(0), channel_stderr_(0),
|
||||
channel_stdout_buffer_size_(100 * 1024), channel_stderr_buffer_size_(10 * 1024), // 100K and 10K
|
||||
event_source_id_stdout_(0), event_source_id_stderr_(0),
|
||||
stdout_make_str_as_available_(false), stderr_make_str_as_available_(true),
|
||||
translator_func_(0), translator_func_data_(0),
|
||||
exited_callback_(exited_cb), exited_callback_data_(exited_cb_data)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
@@ -79,14 +76,19 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
// 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.
|
||||
void set_command(const std::string& command_exec_, const std::string& command_args_)
|
||||
void set_command(const std::string& command_exec, const std::string& command_args)
|
||||
{
|
||||
command_exec = command_exec_;
|
||||
command_args = command_args_;
|
||||
command_exec_ = command_exec;
|
||||
command_args_ = command_args;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +132,7 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
bool stopped_cleanup_needed(bool do_lock = true)
|
||||
{
|
||||
ScopedLock locker(object_mutex_, do_lock);
|
||||
return (child_watch_handler_called);
|
||||
return (child_watch_handler_called_);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +142,7 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
bool is_running() const
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
return running;
|
||||
return running_;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,9 +164,9 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
if (stdout_buffer_size)
|
||||
channel_stdout_buffer_size = stdout_buffer_size; // 100K by default
|
||||
channel_stdout_buffer_size_ = stdout_buffer_size; // 100K by default
|
||||
if (stderr_buffer_size)
|
||||
channel_stderr_buffer_size = stderr_buffer_size; // 10K by default
|
||||
channel_stderr_buffer_size_ = stderr_buffer_size; // 10K by default
|
||||
}
|
||||
|
||||
|
||||
@@ -179,25 +181,25 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
void set_str_available(bool stdout_str_as_available = false, bool stderr_str_as_available = true)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
stdout_make_str_as_available = stdout_str_as_available;
|
||||
stderr_make_str_as_available = stderr_str_as_available;
|
||||
stdout_make_str_as_available_ = stdout_str_as_available;
|
||||
stderr_make_str_as_available_ = stderr_str_as_available;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If stdout_make_str_as_available is false, call this after stopped_cleanup(),
|
||||
// If stdout_make_str_as_available_ is false, call this after stopped_cleanup(),
|
||||
// before next execute(). If it's true, you may call this before the command has
|
||||
// stopped, but it will decrease performance significantly.
|
||||
std::string get_stdout_str(bool clear_existing = false)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
// debug_out_dump("app", str_stdout);
|
||||
// debug_out_dump("app", str_stdout_);
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stdout;
|
||||
str_stdout.clear();
|
||||
std::string ret = str_stdout_;
|
||||
str_stdout_.clear();
|
||||
return ret;
|
||||
}
|
||||
return str_stdout;
|
||||
return str_stdout_;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,33 +208,42 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
if (clear_existing) {
|
||||
std::string ret = str_stderr;
|
||||
str_stderr.clear();
|
||||
std::string ret = str_stderr_;
|
||||
str_stderr_.clear();
|
||||
return ret;
|
||||
}
|
||||
return str_stderr;
|
||||
return str_stderr_;
|
||||
}
|
||||
|
||||
|
||||
// Return execution time, in seconds. Call after execute().
|
||||
double get_execution_time()
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
gulong microsec = 0;
|
||||
return g_timer_elapsed(timer_, µsec);
|
||||
}
|
||||
|
||||
|
||||
// don't return sigc::connection - it's better for thread-safety this way.
|
||||
// this will disconnect earlier slots. Call before execute().
|
||||
void set_exit_status_translator(const sigc::slot<Glib::ustring, int>& slot_exit_status_translator)
|
||||
void set_exit_status_translator(exit_status_translator_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
signal_exit_status_translator.slots().erase(signal_exit_status_translator.slots().begin(), signal_exit_status_translator.slots().end());
|
||||
signal_exit_status_translator.connect(slot_exit_status_translator);
|
||||
translator_func_ = func;
|
||||
translator_func_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
// Returns sigc::connection; you must use lock() / unlock() before modifying it.
|
||||
// NOTE: The slot will be called in non-main thread! (the call is enclosed
|
||||
// NOTE: The callback will be called in non-main thread! (the call is enclosed
|
||||
// in lock/unlock).
|
||||
// Don't use this unless absolutely necessary, use stopped_cleanup_needed()
|
||||
// polling instead.
|
||||
sigc::connection connect_signal_exited(const sigc::slot<void>& slot_exited)
|
||||
void set_exited_callback(exited_callback_func_t func, void* user_data)
|
||||
{
|
||||
ScopedLock locker(object_mutex_);
|
||||
return signal_exited.connect(slot_exited);
|
||||
exited_callback_ = func;
|
||||
exited_callback_data_ = user_data;
|
||||
}
|
||||
|
||||
|
||||
@@ -291,16 +302,25 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
void cleanup_members()
|
||||
{
|
||||
// ScopedLock locker(object_mutex_);
|
||||
kill_signal_sent = 0;
|
||||
child_watch_handler_called = false;
|
||||
pid = 0;
|
||||
waitpid_status = 0;
|
||||
channel_stdout.clear();
|
||||
channel_stderr.clear();
|
||||
event_source_id_stdout = 0;
|
||||
event_source_id_stderr = 0;
|
||||
fd_stdout = 0;
|
||||
fd_stderr = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -308,51 +328,53 @@ class Cmdex : public hz::ErrorHolder<hz::SyncPolicyGlib>, public sigc::trackable
|
||||
|
||||
|
||||
// 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().
|
||||
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().
|
||||
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().
|
||||
|
||||
Glib::Pid pid; // int in Unix, pointer in win32
|
||||
int waitpid_status; // after the command is stopped, before cleanup, this will be available.
|
||||
GPid pid_; // int in Unix, pointer in win32
|
||||
int waitpid_status_; // after the command is stopped, before cleanup, this will be available.
|
||||
|
||||
|
||||
Glib::Timer timer; // keep track of elapsed time since command execution. not used by this class, but may be handy.
|
||||
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;
|
||||
int fd_stdout_;
|
||||
int fd_stderr_;
|
||||
|
||||
Glib::RefPtr<Glib::IOChannel> channel_stdout;
|
||||
Glib::RefPtr<Glib::IOChannel> channel_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 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;
|
||||
int event_source_id_stdout_;
|
||||
int event_source_id_stderr_;
|
||||
|
||||
int stdout_make_str_as_available; // NOT affected by cleanup().
|
||||
int stderr_make_str_as_available; // NOT affected by cleanup().
|
||||
int stdout_make_str_as_available_; // NOT affected by cleanup().
|
||||
int stderr_make_str_as_available_; // NOT affected by cleanup().
|
||||
|
||||
std::string str_stdout; // NOT affected by cleanup().
|
||||
std::string str_stderr; // NOT affected by cleanup().
|
||||
std::string str_stdout_; // NOT affected by cleanup().
|
||||
std::string str_stderr_; // NOT affected by cleanup().
|
||||
|
||||
|
||||
// signals
|
||||
|
||||
// convert command exit status to message string
|
||||
sigc::signal<Glib::ustring, int> signal_exit_status_translator; // NOT affected by cleanup().
|
||||
|
||||
// command exited signal
|
||||
sigc::signal<void> signal_exited; // NOT affected by cleanup().
|
||||
exit_status_translator_func_t translator_func_; // NOT affected by cleanup().
|
||||
void* translator_func_data_;
|
||||
|
||||
// "command exited" signal callback.
|
||||
// NOTE: This will be called in separate thread!
|
||||
exited_callback_func_t exited_callback_; // NOT affected by cleanup().
|
||||
void* exited_callback_data_;
|
||||
|
||||
|
||||
};
|
||||
@@ -4,7 +4,7 @@
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <glibmm/timer.h> // usleep()
|
||||
#include <glib.h> // g_usleep()
|
||||
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
@@ -93,7 +93,7 @@ bool CmdexSync::execute()
|
||||
g_main_context_iteration(NULL, false);
|
||||
}
|
||||
|
||||
Glib::usleep(50*1000); // 50 msec. avoids 100% CPU usage.
|
||||
g_usleep(50*1000); // 50 msec. avoids 100% CPU usage.
|
||||
}
|
||||
|
||||
// command exited, do a cleanup.
|
||||
@@ -8,7 +8,7 @@
|
||||
#define APP_CMDEX_SYNC_H
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <glibmm/ustring.h> // ustring
|
||||
#include <string>
|
||||
|
||||
#include "hz/error.h"
|
||||
#include "hz/intrusive_ptr.h"
|
||||
@@ -196,9 +196,9 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
return cmdex_.get_stderr_str(clear_existing);
|
||||
}
|
||||
|
||||
void set_exit_status_translator(const sigc::slot<Glib::ustring, int>& slot_exit_status_translator)
|
||||
void set_exit_status_translator(Cmdex::exit_status_translator_func_t func, void* user_data)
|
||||
{
|
||||
cmdex_.set_exit_status_translator(slot_exit_status_translator);
|
||||
cmdex_.set_exit_status_translator(func, user_data);
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
return error_msg_;
|
||||
}
|
||||
|
||||
void set_running_msg(const Glib::ustring& msg)
|
||||
void set_running_msg(const std::string& msg)
|
||||
{
|
||||
running_msg_ = msg;
|
||||
}
|
||||
@@ -264,7 +264,7 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
}
|
||||
|
||||
|
||||
Glib::ustring get_running_msg() const
|
||||
std::string get_running_msg() const
|
||||
{
|
||||
return running_msg_;
|
||||
}
|
||||
@@ -282,7 +282,7 @@ class CmdexSync : public hz::intrusive_ptr_referenced, public sigc::trackable {
|
||||
std::string command_name_;
|
||||
std::string command_args_;
|
||||
|
||||
Glib::ustring running_msg_; // message to show in the dialogs, etc...
|
||||
std::string running_msg_; // message to show in the dialogs, etc...
|
||||
|
||||
int forced_kill_timeout_msec;
|
||||
|
||||
@@ -103,7 +103,7 @@ std::string SelfTest::start(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
return "Invalid test specified";
|
||||
|
||||
std::string output;
|
||||
std::string error_msg = drive_->execute_smartctl("--test=" + test_param, smartctl_ex, output);
|
||||
std::string error_msg = drive_->execute_smartctl("-t " + test_param, smartctl_ex, output); // --test=
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -163,7 +163,7 @@ std::string SelfTest::force_stop(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
|
||||
// To abort non-captive short, long and conveyance tests, use "--abort".
|
||||
std::string output;
|
||||
std::string error_msg = drive_->execute_smartctl("--abort", smartctl_ex, output);
|
||||
std::string error_msg = drive_->execute_smartctl("-X", smartctl_ex, output); // --abort
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -202,8 +202,8 @@ std::string SelfTest::update(hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
return "Invalid drive given.";
|
||||
|
||||
std::string output;
|
||||
// std::string error_msg = drive_->execute_smartctl("--log=selftest", smartctl_ex, output);
|
||||
std::string error_msg = drive_->execute_smartctl("--capabilities", smartctl_ex, output);
|
||||
// std::string error_msg = drive_->execute_smartctl("-l selftest", smartctl_ex, output); // --log=
|
||||
std::string error_msg = drive_->execute_smartctl("-c", smartctl_ex, output); // --capabilities
|
||||
|
||||
if (!error_msg.empty()) // checks for empty output too
|
||||
return error_msg;
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <glibmm/timer.h>
|
||||
|
||||
#include "hz/intrusive_ptr.h"
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
#ifndef SMARTCTL_EXECUTOR_H
|
||||
#define SMARTCTL_EXECUTOR_H
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
|
||||
#include "cmdex.h"
|
||||
#include "cmdex_sync.h"
|
||||
|
||||
|
||||
|
||||
// Executor inherits from sigc::trackable
|
||||
template<class ExecutorSync>
|
||||
class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
|
||||
@@ -42,8 +39,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
|
||||
void construct()
|
||||
{
|
||||
ExecutorSync::cmdex_.set_exit_status_translator(sigc::mem_fun(this,
|
||||
&SmartctlExecutorGeneric::translate_exit_status));
|
||||
ExecutorSync::cmdex_.set_exit_status_translator(&SmartctlExecutorGeneric::translate_exit_status, NULL);
|
||||
this->set_error_header("An error occurred while executing smartctl:\n\n");
|
||||
}
|
||||
|
||||
@@ -60,7 +56,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
};
|
||||
|
||||
|
||||
Glib::ustring translate_exit_status(int status)
|
||||
static std::string translate_exit_status(int status, void* user_data)
|
||||
{
|
||||
const char* table[] = {
|
||||
"Command line did not parse.",
|
||||
@@ -73,7 +69,7 @@ class SmartctlExecutorGeneric : public ExecutorSync {
|
||||
"The device self-test log contains records of errors."
|
||||
};
|
||||
|
||||
Glib::ustring str;
|
||||
std::string str;
|
||||
|
||||
// check every bit
|
||||
for (unsigned int i = 0; i <= 7; i++) {
|
||||
@@ -1,13 +1,14 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: Public Domain
|
||||
License: See LICENSE_whatever.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <gtkmm/main.h>
|
||||
|
||||
#include "smartctl_executor_gui.h"
|
||||
// #include "smartctl_executor_gui.h"
|
||||
#include "smartctl_executor.h"
|
||||
|
||||
|
||||
|
||||
@@ -16,12 +17,14 @@ int main(int argc, char** argv)
|
||||
Glib::thread_init();
|
||||
Gtk::Main m(argc, argv);
|
||||
|
||||
// NOTE: Don't use long options (e.g. --info). Use short ones (e.g. -i),
|
||||
// because long options may be unsupported on some platforms.
|
||||
|
||||
// SmartctlExecutor ex("smartctl", "--info /dev/sda");
|
||||
// SmartctlExecutor ex("smartctl", "-i /dev/sda");
|
||||
// SmartctlExecutorGui ex("ls", "-l --color=no -R /dev");
|
||||
// SmartctlExecutorGui ex("lsa", "-1 --color=no /sys/block");
|
||||
SmartctlExecutorGui ex("../../../0test_binary.sh", "");
|
||||
// SmartctlExecutor ex("../../../0test_binary.sh", "");
|
||||
// SmartctlExecutorGui ex("../../../0test_binary.sh", "");
|
||||
SmartctlExecutor ex("../../../0test_binary.sh", "");
|
||||
|
||||
ex.execute();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: Public Domain
|
||||
License: See LICENSE_whatever.txt
|
||||
***************************************************************************/
|
||||
|
||||
#undef HZ_USE_LIBDEBUG
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_whatever.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <glibmm.h>
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Glib::thread_init();
|
||||
|
||||
GPid pid;
|
||||
int fd_stdout = 0, fd_stderr = 0;
|
||||
|
||||
|
||||
std::string cmd = "iexplore";
|
||||
// std::vector<std::string> child_argv = Glib::shell_parse_argv(cmd);
|
||||
|
||||
gchar* curr_dir = g_get_current_dir();
|
||||
|
||||
|
||||
int argcp = 0; // number of args
|
||||
gchar** argvp = 0; // args vector
|
||||
GError* shell_error = 0;
|
||||
g_shell_parse_argv(cmd.c_str(), &argcp, &argvp, &shell_error);
|
||||
|
||||
|
||||
GError* spawn_error = 0;
|
||||
|
||||
g_spawn_async_with_pipes(curr_dir, argvp, NULL,
|
||||
GSpawnFlags(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD),
|
||||
NULL, NULL, // child setup function
|
||||
&pid, 0, &fd_stdout, &fd_stderr, &spawn_error);
|
||||
|
||||
g_free(curr_dir);
|
||||
|
||||
g_strfreev(argvp);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
GIOChannel* channel_stdout = g_io_channel_win32_new_fd(fd_stdout);
|
||||
GIOChannel* channel_stderr = g_io_channel_win32_new_fd(fd_stderr);
|
||||
#else
|
||||
GIOChannel* channel_stdout = g_io_channel_unix_new(fd_stdout);
|
||||
GIOChannel* channel_stderr = g_io_channel_unix_new(fd_stderr);
|
||||
#endif
|
||||
|
||||
// blocking writes if the pipe is full helps for small-pipe systems (see man 7 pipe).
|
||||
GIOFlags flags = GIOFlags(~G_IO_FLAG_NONBLOCK);
|
||||
|
||||
if (channel_stdout) {
|
||||
g_io_channel_set_encoding(channel_stdout, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stdout, flags, 0);
|
||||
g_io_channel_set_buffer_size(channel_stdout, 10000);
|
||||
}
|
||||
|
||||
if (channel_stderr) {
|
||||
g_io_channel_set_encoding(channel_stderr, NULL, 0); // binary IO
|
||||
g_io_channel_set_flags(channel_stderr, flags, 0);
|
||||
g_io_channel_set_buffer_size(channel_stderr, 10000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
g_main_loop_run(g_main_loop_new(NULL, false));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,696 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: See LICENSE_gsmartcontrol.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include "hz/hz_config.h" // CONFIG_*
|
||||
|
||||
#include <ios> // std::boolalpha
|
||||
// #include <glibmm/fileutils.h> // Dir
|
||||
#include <algorithm> // std::find
|
||||
#include <cstdio> // std::fgets()
|
||||
#include <cerrno> // ENXIO
|
||||
|
||||
#if defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
#include <util.h> // getrawpartition()
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_KERNEL_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs_dir.h"
|
||||
#include "hz/fs_file.h"
|
||||
#include "hz/string_sprintf.h"
|
||||
#include "hz/local_algo.h" // hz::shell_sort()
|
||||
#include "rconfig/rconfig_mini.h"
|
||||
|
||||
#include "app_pcrecpp.h"
|
||||
#include "smartctl_executor.h"
|
||||
#include "storage_detector.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
// Note: Since 3ware RAID controllers need additional flags on most (all?) OSes,
|
||||
// and they may ignore the actual devices names, I have no idea how to support them.
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
|
||||
// Linux 2.6 with udev. Scan /dev/disk/by-id - the directory entries there
|
||||
// are symlinks to respective /dev devices. Some devices have multiple
|
||||
// links pointing to them, so unique filter is needed.
|
||||
/*
|
||||
Sample listing:
|
||||
------------------------------------------------------------
|
||||
# ls -1 /dev/disk/by-id
|
||||
ata-ST31000340AS_9QJ0FFG7
|
||||
ata-ST31000340AS_9QJ0FFG7-part1
|
||||
ata-ST31000340AS_9QJ0FFG7-part2
|
||||
ata-ST3500630AS_9QG0R38D
|
||||
ata-ST3500630AS_9QG0R38D-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part1
|
||||
scsi-SATA_ST31000340AS_9QJ0FFG7-part2
|
||||
scsi-SATA_ST3500630AS_9QG0R38D
|
||||
scsi-SATA_ST3500630AS_9QG0R38D-part1
|
||||
*/
|
||||
inline std::string detect_drives_linux_udev_byid(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through device scan directory /dev/disk/by-id...\n");
|
||||
|
||||
std::string dev_dir; // this defaults to "/dev/disk/by-id"
|
||||
if (!rconfig::get_data("system/linux_udev_byid_path", dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory path is not set.\n");
|
||||
return "Device scan directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.entry_list(all_devices, false)) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device scan directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
blacklist.push_back("/-part[0-9]+$/");
|
||||
|
||||
// filter-out the ones with "partN" in them
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// those are usually relative links, so find out where they are pointing to.
|
||||
std::string link_dest;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
path.compress(); // compress in case there are ../-s.
|
||||
}
|
||||
|
||||
// skip number-ended devices, in case we couldn't filter out the scan directory correctly
|
||||
// (it's user-settable after all).
|
||||
// if (app_pcre_match("/[0-9]+$/", path.str()))
|
||||
// continue;
|
||||
|
||||
if (std::find(devices.begin(), devices.end(), path.str()) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path.str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Procfs files don't support SEEK_END or ftello() (I think). Anyway, they can't
|
||||
// be read through hz::File::get_contents, so use this function instead.
|
||||
inline bool read_proc_partitions_file(hz::File& file, std::vector<std::string>& lines)
|
||||
{
|
||||
if (!file.open("rb")) // closed automatically
|
||||
return false; // the error message is in File itself.
|
||||
|
||||
FILE* fp = file.get_handle();
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
char line[256];
|
||||
while (std::fgets(line, sizeof(line), fp) != NULL) {
|
||||
if (*line != '\0')
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Linux (tested with 2.4 and 2.6) /proc/partitions. Parses the file, appends /dev to each entry.
|
||||
// Note that file format changed from 2.4 to 2.6 (some statistics fields moved to another file).
|
||||
// No /proc/partitions on at least freebsd, solaris and osx, afaik.
|
||||
/*
|
||||
Sample 1 (2.4, devfs, with statistics):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
|
||||
|
||||
3 0 60051600 ide/host0/bus0/target0/lun0/disc 72159 136746 1668720 467190 383039 658435 8342136 1659840 -429 17038808 22703194
|
||||
3 1 1638598 ide/host0/bus0/target0/lun0/part1 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 2 1028160 ide/host0/bus0/target0/lun0/part2 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3092512 ide/host0/bus0/target0/lun0/part3 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 4 1 ide/host0/bus0/target0/lun0/part4 0 0 0 0 0 0 0 0 0 0 0
|
||||
3 5 514048 ide/host0/bus0/target0/lun0/part5 1458 7877 74680 9070 2140 18285 166272 42490 0 10100 52000
|
||||
------------------------------------------------------------
|
||||
Sample 2 (2.6):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
1 0 4096 ram0
|
||||
8 0 156290904 sda
|
||||
8 1 39070048 sda1
|
||||
8 2 7560 sda2
|
||||
8 3 1 sda3
|
||||
------------------------------------------------------------
|
||||
Sample 3 (2.6 on nokia n8xx, spaces may be missing):
|
||||
------------------------------------------------------------
|
||||
# cat /proc/partitions
|
||||
major minor #blocks name
|
||||
|
||||
31 0 128 mtdblock0
|
||||
31 1 384 mtdblock1
|
||||
31 2 2048 mtdblock2
|
||||
31 3 2048 mtdblock3
|
||||
31 4 257536 mtdblock4
|
||||
254 0 3932160 mmcblk0
|
||||
254 1 3928064 mmcblk0p1
|
||||
254 8 1966080 mmcblk1
|
||||
254 9 2007032 mmcblk1p1
|
||||
*/
|
||||
inline std::string detect_drives_linux_proc_partitions(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /proc/partitions...\n");
|
||||
|
||||
std::string parts_file;
|
||||
if (!rconfig::get_data("system/linux_proc_partitions_path", parts_file) || parts_file.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file path is not set.\n");
|
||||
return "Partitions file path is not set.";
|
||||
}
|
||||
|
||||
hz::File file(parts_file);
|
||||
// std::string contents;
|
||||
std::vector<std::string> lines;
|
||||
// if (!f.get_contents(contents)) {
|
||||
if (!read_proc_partitions_file(file, lines)) { // this outputs to debug too
|
||||
std::string error_msg = file.get_error_utf8(); // save before calling other file functions
|
||||
if (!file.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Partitions file doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Partitions file exists but cannot be read.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
// debug_out_dump("app", DBG_FUNC_MSG << "Dumping partitions file:\n" << contents << "\n");
|
||||
|
||||
// hz::string_split(contents, '\n', lines, true);
|
||||
|
||||
std::vector<std::string> blacklist;
|
||||
// fixme: not sure about how partitions are visible with twa0.
|
||||
blacklist.push_back("/d[a-z][0-9]+$/"); // sda1, hdb2 - partitions. twa0 and twe1 are drives, not partitions.
|
||||
blacklist.push_back("/ram[0-9]+$/"); // ramdisks?
|
||||
blacklist.push_back("/loop[0-9]*$/"); // not sure if loop devices go there, but anyway...
|
||||
blacklist.push_back("/part[0-9]+$/"); // devfs had them
|
||||
blacklist.push_back("/p[0-9]+$/"); // partitions are usually marked this way
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < lines.size(); ++i) {
|
||||
std::string line = hz::string_trim_copy(lines[i]);
|
||||
if (line.empty() || app_pcre_match("/^major/", line)) // file header
|
||||
continue;
|
||||
|
||||
std::string dev;
|
||||
if (!app_pcre_match("/^[ \\t]*[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+[^ \\t\\n]+[ \\t]+([^ \\t\\n]+)/", line, &dev) || dev.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot parse line \"" << line << "\".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// platform blacklist
|
||||
bool blacked = false;
|
||||
for (std::vector<std::string>::const_iterator iter = blacklist.begin(); iter != blacklist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, dev)) {
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blacked)
|
||||
continue;
|
||||
|
||||
std::string path = "/dev/" + dev;
|
||||
if (std::find(devices.begin(), devices.end(), path) == devices.end()) // there may be duplicates
|
||||
devices.push_back(path);
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_WINDOWS
|
||||
|
||||
|
||||
// smartctl accepts various variants, but \\.\PhysicalDriveN
|
||||
// seems to be the most native and acceptable.
|
||||
|
||||
inline std::string detect_drives_win32(std::vector<std::string>& devices)
|
||||
{
|
||||
for (int drive_num = 0; ; ++drive_num) {
|
||||
// If the drive is openable, then it's there.
|
||||
// NOTE: Administrative privileges are required to open it.
|
||||
std::string name = hz::string_sprintf("\\\\.\\PhysicalDrive%d", drive_num);
|
||||
HANDLE h = CreateFile(name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
// The numbers seem to be continuous, so break on first invalid.
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
CloseHandle (h);
|
||||
|
||||
// smartctl uses /dev/pdN for \\.\PhysicalDrive N.
|
||||
devices.push_back(hz::string_sprintf("/dev/pd%d", drive_num));
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else // FreeBSD, Solaris, etc... .
|
||||
|
||||
|
||||
inline std::string detect_drives_dev(std::vector<std::string>& devices)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Detecting through /dev...\n");
|
||||
|
||||
std::string sdev_config_path;
|
||||
#ifdef CONFIG_KERNEL_SOLARIS
|
||||
sdev_config_path = "system/solaris_dev_path";
|
||||
#else // other unixes
|
||||
sdev_config_path = "system/unix_sdev_path";
|
||||
#endif
|
||||
|
||||
std::string dev_dir; // defaults to /dev for freebsd, /dev/rdsk for solaris.
|
||||
if (!rconfig::get_data(sdev_config_path, dev_dir) || dev_dir.empty()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory path is not set.\n");
|
||||
return "Device directory path is not set.";
|
||||
}
|
||||
|
||||
hz::Dir dir(dev_dir);
|
||||
|
||||
std::vector<std::string> all_devices;
|
||||
if (!dir.entry_list(all_devices, false, hz::DirSortNone())) { // this outputs to debug too.
|
||||
std::string error_msg = dir.get_error_utf8();
|
||||
if (!dir.exists()) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Device directory doesn't exist.\n");
|
||||
} else {
|
||||
debug_out_error("app", DBG_FUNC_MSG << "Cannot list directory entries.\n");
|
||||
}
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
// platform whitelist
|
||||
std::vector<std::string> whitelist;
|
||||
|
||||
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY
|
||||
// FreeBSD example device names:
|
||||
// * /dev/ad0 - ide disk 0. /dev/ad0a - non-slice dos partition 1.
|
||||
// * /dev/da1s1e - scsi disk 1 (second disk), slice 1 (aka dos partition 1),
|
||||
// bsd partition e (multiple bsd partitions may be inside one dos partition).
|
||||
// * /dev/acd0 - first cdrom. /dev/acd0c - ?.
|
||||
// Info: http://www.freebsd.org/doc/en/books/handbook/disks-naming.html
|
||||
|
||||
// Of two machines I had access to, freebsd 6.3 had only real devices,
|
||||
// while freebsd 4.10 had lots of dummy ones (ad1, ad2, ad3, da0, da1, da2, da3, sa0, ...).
|
||||
|
||||
whitelist.push_back("/^ad[0-9]+$/"); // adN without suffix - fbsd ide
|
||||
whitelist.push_back("/^da[0-9]+$/"); // daN without suffix - fbsd scsi, usb
|
||||
// whitelist.push_back("/ ^sa[0-9]+$/"); // saN without suffix - fbsd scsi tape
|
||||
// whitelist.push_back("/^ast[0-9]+$/"); // astN without suffix - fbsd ide tape
|
||||
whitelist.push_back("/^aacd[0-9]+$/"); // fbsd adaptec raid
|
||||
whitelist.push_back("/^mlxd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^mlyd[0-9]+$/"); // fbsd mylex raid
|
||||
whitelist.push_back("/^amrd[0-9]+$/"); // fbsd AMI raid
|
||||
whitelist.push_back("/^idad[0-9]+$/"); // fbsd compaq raid
|
||||
whitelist.push_back("/^twed[0-9]+$/"); // fbsd 3ware raid
|
||||
// these are checked by smartctl, but they are not mentioned in freebsd docs:
|
||||
whitelist.push_back("/^tw[ae][0-9]+$/"); // fbsd 3ware raid
|
||||
// unused: acd - ide cdrom, cd - scsi cdrom, mcd - mitsumi cdrom, scd - sony cdrom,
|
||||
// fd - floppy, fla - diskonchip flash.
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_SOLARIS
|
||||
|
||||
// /dev/rdsk contains "raw" physical char devices, as opposed to
|
||||
// "filesystem" block devices in /dev/dsk. smartctl needs rdsk.
|
||||
|
||||
// x86:
|
||||
|
||||
// /dev/rdsk/c0t0d0p0:1
|
||||
// Where c0 is the controller number.
|
||||
// t0 is the target (SCSI ID number) (omit for ATAPI)
|
||||
// d0 is always 0 for SCSI, the drive # for ATAPI
|
||||
// p0 is the partition (p0 is the entire disk, or p1 - p4)
|
||||
// :1 is the logical drive (c - z or 1 - 24) (that is, logical partitions inside extended partition)
|
||||
|
||||
// /dev/rdsk/c0d0p2:1
|
||||
// where p2 means the extended partition (type 0x05) is partition 2 (out of 1-4) and
|
||||
// ":1" is the 2nd extended partition (:0 would be the first extended partition). -- not sure about this!
|
||||
|
||||
// p0 whole physical disk
|
||||
// p1 - p4 Four primary fdisk partitions
|
||||
// p5 - p30 26 logical drives in extended DOS partition (not implemented by Solaris)
|
||||
// s0 - s15 16 slices in the Solaris FDISK partition (SPARC has only 8)
|
||||
// On Solaris, by convention, s2 is the whole Solaris partition.
|
||||
|
||||
// SPARC: There are no *p* devices on sparc afaik, only slices. By convention,
|
||||
// s2 is used as a "whole" disk there (but not with EFI partitions!).
|
||||
// So, c0d0s2 is the whole disk there.
|
||||
// x86 has both c0d0s2 and c0d0p2, where s2 is a whole solaris partition.
|
||||
|
||||
// NOTE: It seems that smartctl searches for s0 (aka root partition) in the end. I'm not sure
|
||||
// what implications this has for x86, but we replicate this behaviour.
|
||||
|
||||
// Note: Cdroms are ATAPI, so they pose as SCSI, as opposed to IDE hds.
|
||||
|
||||
// TODO: No idea how to implement /dev/rmt (scsi tape devices),
|
||||
// I have no files in that directory.
|
||||
|
||||
whitelist.push_back("/^c[0-9]+(?:t[0-9]+)?d[0-9]+s0$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
|
||||
// OpenBSD / NetBSD have /dev/wdNc for IDE/ATA, /dev/sdNc for SCSI disk,
|
||||
// /dev/stNc for scsi tape. N is [0-9]+. "c" means "whole disk" (not sure about
|
||||
// different architectures though). There are no "sdN" devices, only "sdNP".
|
||||
// Another manual says that wd0d would be a whole disk, while wd0c is its
|
||||
// bsd part only (on x86) (only on netbsd?). Anyway, getrawpartition() gives
|
||||
// us the letter we need.
|
||||
// There is no additional level of names for BSD subpartitions (unlike freebsd).
|
||||
// cd0a is cdrom.
|
||||
// Dummy devices are present.
|
||||
|
||||
// Note: This detection may take a while (probably due to open() check).
|
||||
|
||||
char whole_part = 'a' + getrawpartition(); // from bsd's util.h
|
||||
|
||||
whitelist.push_back(hz::string_sprintf("/^wd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^sd[0-9]+%c$/", whole_part));
|
||||
whitelist.push_back(hz::string_sprintf("/^st[0-9]+%c$/", whole_part));
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_DARWIN
|
||||
|
||||
// Darwin has /dev/disk0, /dev/disk0s1, etc...
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^disk[0-9]+$/");
|
||||
|
||||
|
||||
|
||||
#elif defined CONFIG_KERNEL_QNX
|
||||
|
||||
// QNX has /dev/hd0, /dev/hd0t78 (partition?).
|
||||
// Afaik, IDE and SCSI have the same prefix. fd for floppy, cd for cdrom.
|
||||
// Not sure about the tapes.
|
||||
// Only real devices are present, so no need for additional checks.
|
||||
|
||||
whitelist.push_back("/^hd[0-9]+$/");
|
||||
|
||||
|
||||
#endif // unix platforms
|
||||
|
||||
|
||||
std::vector<std::string> matched_devices;
|
||||
|
||||
for (unsigned int i = 0; i < all_devices.size(); ++i) {
|
||||
std::string entry = all_devices[i];
|
||||
if (entry == "." || entry == "..")
|
||||
continue;
|
||||
|
||||
bool matched = false;
|
||||
for (std::vector<std::string>::const_iterator iter = whitelist.begin(); iter != whitelist.end(); ++iter) {
|
||||
if (app_pcre_match(*iter, entry)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
hz::FsPath path = dev_dir + hz::DIR_SEPARATOR_S + all_devices[i];
|
||||
|
||||
// In case these are links, trace them to originals.
|
||||
// We don't replace /dev files with real devices - it leads to really bad paths (pci ids for solaris, etc...).
|
||||
std::string link_dest;
|
||||
hz::FsPath real_dev_path;
|
||||
if (path.get_link_destination(link_dest)) {
|
||||
real_dev_path = (hz::path_is_absolute(link_dest) ? link_dest : (dev_dir + hz::DIR_SEPARATOR_S + link_dest));
|
||||
real_dev_path.compress(); // compress in case there are ../-s.
|
||||
|
||||
// solaris has dangling links for non-existant devices, so filter them out.
|
||||
if (!real_dev_path.exists())
|
||||
continue;
|
||||
}
|
||||
|
||||
matched_devices.push_back(path.str());
|
||||
}
|
||||
|
||||
|
||||
// List ones who need dummy device filtering
|
||||
#if defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY \
|
||||
|| defined CONFIG_KERNEL_OPENBSD || defined CONFIG_KERNEL_NETBSD
|
||||
// Since we may have encountered dummy devices, we should check
|
||||
// if they really exist. Unfortunately, this involves opening them, which
|
||||
// is not good with some media (e.g. it may hang on audio cd (freebsd, maybe others), etc...).
|
||||
// That's why we don't whitelist cd devices. Let's hope usb and others are
|
||||
// ok with this. Dummy devices give errno ENXIO (6, Device not configured) on *bsd.
|
||||
// In Linux ENXIO is (6, No such device or address).
|
||||
|
||||
// Don't do this on solaris - we can't distinguish between cdroms and hds there.
|
||||
|
||||
// If there are less than 4 devices, they are probably not dummy (newer freebsd).
|
||||
bool open_needed = (matched_devices.size() >= 4);
|
||||
if (open_needed) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", will try to filter non-existent ones out.\n");
|
||||
} else {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Number of matched devices is "
|
||||
<< matched_devices.size() << ", no need for filtering them out.\n");
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < matched_devices.size(); ++i) {
|
||||
hz::File dev_file(matched_devices[i]);
|
||||
|
||||
// we check errno because OS may deny us for some other reason on valid devices.
|
||||
if (open_needed && !dev_file.open("rb") && dev_file.get_errno() == ENXIO) {
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" failed to open, ignoring.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (open_needed)
|
||||
debug_out_dump("app", DBG_FUNC_MSG << "Device \"" << dev_file.str() << "\" opened successfully, adding to device list.\n");
|
||||
|
||||
devices.push_back(dev_file.str());
|
||||
}
|
||||
|
||||
#else // not *BSD
|
||||
for (unsigned int i = 0; i < matched_devices.size(); ++i) {
|
||||
devices.push_back(matched_devices[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
hz::shell_sort(devices.begin(), devices.end());
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
#endif // platforms
|
||||
|
||||
|
||||
|
||||
} // anon. ns
|
||||
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::detect(std::vector<StorageDeviceRefPtr>& drives)
|
||||
{
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Starting drive detection.\n");
|
||||
|
||||
std::vector<std::string> devices;
|
||||
std::string error_msg;
|
||||
bool found = false;
|
||||
|
||||
// Try each one and move to next if it fails.
|
||||
|
||||
#if defined CONFIG_KERNEL_LINUX
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_udev_byid(devices); // linux udev
|
||||
// we check for devices vector emptiness because it could be a dummy directory
|
||||
// with no files, so treat it as an error.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_linux_proc_partitions(devices); // linux /proc/partitions as fallback.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined CONFIG_KERNEL_WINDOWS
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_win32(devices); // win32
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else // freebsd, etc...
|
||||
|
||||
if (!found) {
|
||||
error_msg = detect_drives_dev(devices); // bsd, etc... . scans /dev.
|
||||
if (error_msg.empty() && !devices.empty()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!found) {
|
||||
debug_out_warn("app", DBG_FUNC_MSG << "Cannot detect drives: None of the drive detection methods returned any drives.\n");
|
||||
return error_msg; // last error message should be ok.
|
||||
}
|
||||
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter = devices.begin(); iter != devices.end(); ++iter) {
|
||||
std::string dev = *iter;
|
||||
|
||||
// try to match against patterns
|
||||
// for (unsigned int i = 0; i < match_patterns_.size(); i++) {
|
||||
// try to match against general filter
|
||||
// if (!app_pcre_match(match_patterns_[i], dev))
|
||||
// continue;
|
||||
|
||||
// matched, check the blacklist
|
||||
bool blacked = false;
|
||||
for (unsigned int j = 0; j < blacklist_patterns_.size(); j++) {
|
||||
if (app_pcre_match(blacklist_patterns_[j], dev)) { // matched the blacklist too
|
||||
blacked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StorageDeviceRefPtr drive(new StorageDevice(dev));
|
||||
debug_out_info("app", "Found device: \"" << drive->get_device() << "\".\n");
|
||||
|
||||
if (!blacked) {
|
||||
drives.push_back(drive);
|
||||
// break; // no need to match other patters, go to next device
|
||||
|
||||
} else { // blacklisted
|
||||
debug_out_info("app", "Device \"" << drive->get_device() << "\" is blacklisted, ignoring.\n");
|
||||
// break; // go to next device
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Drive detection finished.\n");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::fetch_basic_data(std::vector<StorageDeviceRefPtr>& drives,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex, bool return_first_error)
|
||||
{
|
||||
fetch_data_errors_.clear();
|
||||
fetch_data_error_outputs_.clear();
|
||||
|
||||
|
||||
// If it doesn't exist, create a default one. Even though it will be auto-created later,
|
||||
// we need it here to get its errors afterwards.
|
||||
if (!smartctl_ex)
|
||||
smartctl_ex = new SmartctlExecutor(); // will be auto-deleted
|
||||
|
||||
for (unsigned int i = 0; i < drives.size(); ++i) {
|
||||
StorageDeviceRefPtr drive = drives[i];
|
||||
debug_out_info("app", "Retrieving basic information about the device...\n");
|
||||
|
||||
smartctl_ex->set_running_msg("Running %s on " + drive->get_device() + "...");
|
||||
|
||||
// don't show any errors here - we don't want a screen flood.
|
||||
// no need for gui-based executors here, we already show the message in
|
||||
// iconview background (if called from main window)
|
||||
std::string error_msg = drive->fetch_basic_data_and_parse(smartctl_ex);
|
||||
|
||||
// normally we skip drives with errors - possibly scsi, etc...
|
||||
if (return_first_error && !error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
// use original executor error if present (permits matches by our users).
|
||||
// if (!smartctl_ex->get_error_msg().empty())
|
||||
// error_msg = smartctl_ex->get_error_msg();
|
||||
|
||||
fetch_data_errors_.push_back(error_msg);
|
||||
fetch_data_error_outputs_.push_back(smartctl_ex->get_stdout_str());
|
||||
}
|
||||
|
||||
debug_out_dump("app", "Device information for " << drive->get_device() << ":\n"
|
||||
<< "\tModel: " << drive->get_model_name() << "\n"
|
||||
<< "\tType: " << StorageDevice::get_type_name(drive->get_type()) << "\n"
|
||||
<< "\tSMART status: " << StorageDevice::get_status_name(drive->get_smart_status()) << "\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string StorageDetector::detect_and_fetch_basic_data(std::vector<StorageDeviceRefPtr>& put_drives_here,
|
||||
hz::intrusive_ptr<CmdexSync> smartctl_ex)
|
||||
{
|
||||
std::string error_msg = detect(put_drives_here);
|
||||
|
||||
if (error_msg.empty())
|
||||
fetch_basic_data(put_drives_here, smartctl_ex, false); // ignore its errors, there may be plenty of them.
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
/**************************************************************************
|
||||
Copyright:
|
||||
(C) 2008 Alexander Shaduri <ashaduri 'at' gmail.com>
|
||||
License: Public Domain
|
||||
License: See LICENSE_whatever.txt
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "storage_device.h"
|
||||
#include "storage_detector.h"
|
||||
|
||||
#include "gsc_settings.h" // in src directory
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// These settings contain device search paths, smartctl binary, etc...
|
||||
init_default_settings();
|
||||
|
||||
std::vector<StorageDeviceRefPtr> drives;
|
||||
// std::vector<std::string> match_patterns;
|
||||
std::vector<std::string> blacklist_patterns; // additional parameters
|
||||
@@ -29,7 +29,7 @@ std::string StorageDevice::fetch_basic_data_and_parse(hz::intrusive_ptr<CmdexSyn
|
||||
std::string output;
|
||||
// We don't use "--all" - it may cause really screwed up the output (tests, etc...).
|
||||
// This looks just like "--info" only on non-smart devices.
|
||||
std::string error_msg = execute_smartctl("--info --health --capabilities", smartctl_ex, output);
|
||||
std::string error_msg = execute_smartctl("-i -H -c", smartctl_ex, output); // --info --health --capabilities
|
||||
if (!error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
@@ -52,9 +52,9 @@ std::string StorageDevice::parse_basic_data(bool emit_signal)
|
||||
|
||||
std::string version = SmartctlParser::parse_version(this->info_output_);
|
||||
if (version.empty()) // is this smartctl data at all?
|
||||
return "Cannot extract smartctl version information.";
|
||||
return "Cannot get smartctl version information.";
|
||||
|
||||
// detect type. note: we can't distinguish between sata and scsi.
|
||||
// detect type. note: we can't distinguish between sata and scsi (on linux, for -d ata switch).
|
||||
if (app_pcre_match("/this device: CD\\/DVD/mi", info_output_)) {
|
||||
this->set_type(type_cddvd);
|
||||
|
||||
@@ -72,7 +72,8 @@ std::string StorageDevice::parse_basic_data(bool emit_signal)
|
||||
|
||||
// Don't put complete messages here - they change across smartctl versions.
|
||||
if (app_pcre_match("/^SMART support is:[ \\t]*Unavailable/mi", info_output_) // cdroms output this
|
||||
|| app_pcre_match("/Device does not support SMART/mi", info_output_)) { // usb flash drives output this
|
||||
|| app_pcre_match("/Device does not support SMART/mi", info_output_) // usb flash drives, non-smart hds
|
||||
|| app_pcre_match("/Device Read Identity Failed \\(not an ATA\\/ATAPI device\\)/mi", info_output_)) { // solaris scsi, unsupported by smartctl
|
||||
smart_supported_ = false;
|
||||
smart_enabled_ = false;
|
||||
|
||||
@@ -135,7 +136,7 @@ std::string StorageDevice::fetch_data_and_parse(hz::intrusive_ptr<CmdexSync> sma
|
||||
this->clear_fetched(); // clear everything fetched before, including outputs
|
||||
|
||||
std::string output;
|
||||
std::string error_msg = execute_smartctl("--all", smartctl_ex, output);
|
||||
std::string error_msg = execute_smartctl("-a", smartctl_ex, output); // --all
|
||||
if (!error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
@@ -210,7 +211,8 @@ A mandatory SMART command failed: exiting. To continue, add one or more '-T perm
|
||||
*/
|
||||
|
||||
std::string output;
|
||||
std::string error_msg = execute_smartctl((b ? "--smart=on --saveauto=on" : "--smart=off"), smartctl_ex, output);
|
||||
// --smart=on --saveauto=on, --smart=off
|
||||
std::string error_msg = execute_smartctl((b ? "-s on -S on" : "-s off"), smartctl_ex, output);
|
||||
if (!error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
@@ -245,7 +247,8 @@ SMART Automatic Offline Testing Disabled.
|
||||
A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.
|
||||
*/
|
||||
std::string output;
|
||||
std::string error_msg = execute_smartctl((b ? "--offlineauto=on" : "--offlineauto=off"), smartctl_ex, output);
|
||||
// --offlineauto=on, --offlineauto=off
|
||||
std::string error_msg = execute_smartctl((b ? "-o on" : "-o off"), smartctl_ex, output);
|
||||
if (!error_msg.empty())
|
||||
return error_msg;
|
||||
|
||||
@@ -30,7 +30,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced {
|
||||
// to display the correct icon
|
||||
enum type_t {
|
||||
type_unknown, // unknown. will be autodetected by smartctl
|
||||
type_cddvd, // unsupported by smartctl
|
||||
type_cddvd // unsupported by smartctl
|
||||
// type_pata, // old pata
|
||||
|
||||
// we can't differentiate between these.
|
||||
@@ -55,7 +55,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced {
|
||||
status_enabled, // smart, aodc
|
||||
status_disabled, // smart, aodc
|
||||
status_unsupported, // smart, aodc
|
||||
status_unknown, // aodc - supported but unknown if it's enabled or not.
|
||||
status_unknown // aodc - supported but unknown if it's enabled or not.
|
||||
};
|
||||
|
||||
static std::string get_status_name(status_t status, bool use_yesno = false)
|
||||
@@ -45,7 +45,7 @@ class StorageAttribute {
|
||||
enum attr_t {
|
||||
attr_type_unknown,
|
||||
attr_type_prefail, // reported: Pre-fail
|
||||
attr_type_oldage, // reported: Old_age
|
||||
attr_type_oldage // reported: Old_age
|
||||
};
|
||||
|
||||
static std::string get_attr_type_name(attr_t a)
|
||||
@@ -62,7 +62,7 @@ class StorageAttribute {
|
||||
enum update_t {
|
||||
update_type_unknown,
|
||||
update_type_always, // reported: Always
|
||||
update_type_offline, // reported: Offline
|
||||
update_type_offline // reported: Offline
|
||||
};
|
||||
|
||||
static std::string get_update_type_name(update_t a)
|
||||
@@ -80,7 +80,7 @@ class StorageAttribute {
|
||||
fail_time_unknown,
|
||||
fail_time_none, // reported: -
|
||||
fail_time_past, // reported: In_the_past
|
||||
fail_time_now, // reported: FAILING_NOW
|
||||
fail_time_now // reported: FAILING_NOW
|
||||
};
|
||||
|
||||
static std::string get_fail_time_name(fail_time_t a)
|
||||
@@ -245,7 +245,7 @@ class StorageProperty {
|
||||
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
|
||||
value_type_selftest_entry // for "selftest_log" subsection
|
||||
};
|
||||
|
||||
static std::string get_value_type_name(value_type_t type)
|
||||
@@ -270,7 +270,7 @@ class StorageProperty {
|
||||
section_unknown, // use when searching in all sections
|
||||
section_info, // Short info (--info)
|
||||
section_data, // SMART DATA
|
||||
section_internal, // internal application-specific data
|
||||
section_internal // internal application-specific data
|
||||
};
|
||||
|
||||
static std::string get_section_name(section_t s)
|
||||
@@ -293,7 +293,7 @@ class StorageProperty {
|
||||
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
|
||||
subsection_selective_selftest_log // Selective self-test log and settings
|
||||
};
|
||||
|
||||
static std::string get_subsection_name(subsection_t s)
|
||||
@@ -315,7 +315,7 @@ class StorageProperty {
|
||||
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
|
||||
warning_alert // smart warning is raised by pre-fail attribute, and similar errors
|
||||
};
|
||||
|
||||
|
||||