[PATCH] remove unused code
by Nikola Pajkovsky
code is run in abrt-action-save-package-data.cpp
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
src/daemon/Daemon.cpp | 10 ----------
1 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp
index 2564a82..8ab9991 100644
--- a/src/daemon/Daemon.cpp
+++ b/src/daemon/Daemon.cpp
@@ -269,12 +269,6 @@ static gboolean cron_activation_reshedule_cb(gpointer data)
static int SetUpMW()
{
- set_string_t::iterator it_k = g_settings_setOpenGPGPublicKeys.begin();
- for (; it_k != g_settings_setOpenGPGPublicKeys.end(); it_k++)
- {
- VERB1 log("Loading GPG key '%s'", it_k->c_str());
- rpm_load_gpgkey(it_k->c_str());
- }
VERB1 log("Adding actions or reporters");
vector_pair_string_string_t::iterator it_ar = g_settings_vectorActionsAndReporters.begin();
for (; it_ar != g_settings_vectorActionsAndReporters.end(); it_ar++)
@@ -987,9 +981,6 @@ int main(int argc, char** argv)
error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
xmlrpc_env_clean(&env);
- VERB1 log("Initializing rpm library");
- rpm_init();
-
VERB1 log("Creating glib main loop");
pMainloop = g_main_loop_new(NULL, FALSE);
@@ -1099,7 +1090,6 @@ int main(int argc, char** argv)
*/
xmlrpc_client_teardown_global_const();
dumpsocket_shutdown();
- rpm_destroy();
if (pidfile_created)
unlink(VAR_RUN_PIDFILE);
if (lockfile_created)
--
1.7.1
13 years, 7 months
[PATCH] move package/component/description generation to a separate program (abrt-action-save-package-data)
by Denys Vlasenko
This patch splits off abrtd's package/component/description
generation into a separate tool:
# abrt-action-save-package-data -z
abrt-action-save-package-data: invalid option -- 'z'
Usage: abrt-action-save-package-data -d DIR [-vs]
Query package database and save package name, component,
and description
Options:
-d DIR Crash dump directory
-v Verbose
-s Log to syslog
This also allows for debugging and regression testing of
abrt-action-save-package-data - it can be simply run
from command-line.
Also it provides a better fault isolation - crash in
abrt-action-save-package-data does not take down abrtd.
Same goes for isolation of memory leaks - old code actually
had leaks on a rarely used error path. New code doesn't,
but if it would have, it wouldn't matter, since the process
is short-lived.
Run tested.
Please review.
--
vda
diff -x '*.po' -d -urpN abrt.4/abrt.spec abrt.5/abrt.spec
--- abrt.4/abrt.spec 2010-09-20 14:32:02.000000000 +0200
+++ abrt.5/abrt.spec 2010-09-21 17:40:51.339917908 +0200
@@ -350,6 +350,7 @@ fi
%{_sbindir}/abrtd
%{_sbindir}/abrt-server
%{_sbindir}/abrt-action-generate-backtrace
+%{_sbindir}/abrt-action-save-package-data
%{_bindir}/%{name}-debuginfo-install
%{_bindir}/%{name}-handle-upload
%{_bindir}/%{name}-backtrace
diff -x '*.po' -d -urpN abrt.4/src/daemon/abrt-action-save-package-data.cpp abrt.5/src/daemon/abrt-action-save-package-data.cpp
--- abrt.4/src/daemon/abrt-action-save-package-data.cpp 1970-01-01 01:00:00.000000000 +0100
+++ abrt.5/src/daemon/abrt-action-save-package-data.cpp 2010-09-22 00:59:10.814550766 +0200
@@ -0,0 +1,341 @@
+/*
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <fnmatch.h>
+#include "abrtlib.h"
+#include "abrt_packages.h"
+#include "Settings.h"
+#include "rpm.h"
+
+
+/**
+ * Returns the first full path argument in the command line or NULL.
+ * Skips options are in form "-XXX".
+ * Caller must delete the returned string using free().
+ */
+static char *get_argv1_if_full_path(const char* cmdline)
+{
+ const char *argv1 = strpbrk(cmdline, " \t");
+ while (argv1 != NULL)
+ {
+ /* we found space in cmdline, so it might contain
+ * path to some script like:
+ * /usr/bin/python [-XXX] /usr/bin/system-control-network
+ */
+ argv1++; /* skip the space */
+ if (*argv1 == '-')
+ {
+ /* looks like -XXX in "perl -XXX /usr/bin/script.pl", skip */
+ argv1 = strpbrk(argv1, " \t");
+ continue;
+ }
+ if (*argv1 == ' ' || *argv1 == '\t') /* skip multiple spaces */
+ continue;
+ if (*argv1 != '/')
+ {
+ /* if the string following the space doesn't start
+ * with '/' it's probably not a full path to script
+ * and we can't use it to determine the package name
+ */
+ break;
+ }
+
+ /* cut the rest of cmdline arguments */
+ int len = strchrnul(argv1, ' ') - argv1;
+ return xstrndup(argv1, len);
+ }
+ return NULL;
+}
+
+static bool is_path_blacklisted(const char *path)
+{
+ set_string_t::iterator it = g_settings_setBlackListedPaths.begin();
+ while (it != g_settings_setBlackListedPaths.end())
+ {
+ if (fnmatch(it->c_str(), path, /*flags:*/ 0) == 0)
+ {
+ return true;
+ }
+ it++;
+ }
+ return false;
+}
+
+static int SavePackageDescriptionToDebugDump(const char *dump_dir_name)
+{
+ struct dump_dir *dd = dd_init();
+ if (!dd_opendir(dd, dump_dir_name))
+ {
+ VERB1 log(_("Unable to open debug dump '%s'"), dump_dir_name);
+ dd_close(dd);
+ return 1;
+ }
+ char *remote_str = dd_load_text(dd, FILENAME_REMOTE);
+ bool remote = (remote_str[0] == '1');
+ free(remote_str);
+
+ char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
+ char *cmdline = dd_load_text(dd, FILENAME_CMDLINE);
+ char *package_full_name = NULL;
+ char *package_short_name = NULL;
+ char *component = NULL;
+ char *script_name = NULL; /* only if "interpreter /path/to/script" */
+ char *dsc = NULL;
+ int result;
+ /* note: "goto ret" statements below free all the above variables,
+ * but they don't dd_close(dd) */
+
+ if (strcmp(executable, "kernel") == 0)
+ {
+ component = xstrdup("kernel");
+ package_full_name = xstrdup("kernel");
+ package_short_name = xstrdup("kernel");
+ dsc = rpm_get_description(package_short_name);
+ }
+ else
+ {
+ /* Close dd while we query package database. It can take some time,
+ * don't want to keep dd locked longer than necessary */
+ dd_close(dd);
+
+ if (is_path_blacklisted(executable))
+ {
+ log("Blacklisted executable '%s', deleting '%s'", executable, dump_dir_name);
+ result = 1;
+ goto ret;
+ }
+
+ package_full_name = rpm_get_package_nvr(executable);
+ if (!package_full_name)
+ {
+ if (g_settings_bProcessUnpackaged || remote)
+ {
+ VERB2 log("Crash in unpackaged executable '%s', proceeding without packaging information", executable);
+ package_full_name = xstrdup("");
+ component = xstrdup("");
+ dsc = xstrdup("Crashed executable does not belong to any installed package");
+ goto reopen_dd_and_save;
+ }
+ log("Executable '%s' doesn't belong to any package, deleting '%s'", executable, dump_dir_name);
+ result = 1;
+ goto ret;
+ }
+
+ /* Check well-known interpreter names */
+ {
+ const char *basename = strrchr(executable, '/');
+ if (basename) basename++; else basename = executable;
+
+ /* Add more interpreters as needed */
+ if (strcmp(basename, "python") == 0
+ || strcmp(basename, "perl") == 0
+ ) {
+// TODO: we don't verify that python executable is not modified
+// or that python package is properly signed
+// (see CheckFingerprint/CheckHash below)
+ /* Try to find package for the script by looking at argv[1].
+ * This will work only if the cmdline contains the whole path.
+ * Example: python /usr/bin/system-control-network
+ */
+ char *script_pkg = NULL;
+ char *script_name = get_argv1_if_full_path(cmdline);
+ if (script_name)
+ {
+ script_pkg = rpm_get_package_nvr(script_name);
+ if (script_pkg)
+ {
+ /* There is a well-formed script name in argv[1],
+ * and it does belong to some package.
+ * Replace interpreter's package_full_name and executable
+ * with data pertaining to the script.
+ */
+ free(package_full_name);
+ package_full_name = script_pkg;
+ executable = script_name;
+ /* executable has changed, check it again */
+ if (is_path_blacklisted(executable))
+ {
+ log("Blacklisted executable '%s'", executable);
+ result = 1;
+ goto ret;
+ }
+ }
+ }
+ if (!script_pkg && !g_settings_bProcessUnpackaged && !remote)
+ {
+ log("Interpreter crashed, but no packaged script detected: '%s'", cmdline);
+ result = 1;
+ goto ret;
+ }
+ }
+ }
+
+ package_short_name = get_package_name_from_NVR_or_NULL(package_full_name);
+ VERB2 log("Package:'%s' short:'%s'", package_full_name, package_short_name);
+
+ if (g_settings_setBlackListedPkgs.find(package_short_name) != g_settings_setBlackListedPkgs.end())
+ {
+ log("Blacklisted package '%s'", package_short_name);
+ result = 1;
+ goto ret;
+ }
+ if (g_settings_bOpenGPGCheck && !remote)
+ {
+ if (rpm_chk_fingerprint(package_short_name))
+ {
+ log("Package '%s' isn't signed with proper key", package_short_name);
+ result = 1;
+ goto ret;
+ }
+ /*
+ Checking the MD5 sum requires to run prelink to "un-prelink" the
+ binaries - this is considered potential security risk so we don't
+ use it, until we find some non-intrusive way
+
+ Delete?
+ */
+ /*
+ if (!CheckHash(package_short_name.c_str(), executable))
+ {
+ error_msg("Executable '%s' seems to be modified, "
+ "doesn't match one from package '%s'",
+ executable, package_short_name.c_str());
+ result = 1;
+ goto ret;
+ }
+ */
+ }
+ component = rpm_get_component(executable);
+ dsc = rpm_get_description(package_short_name);
+
+ reopen_dd_and_save:
+ dd = dd_init();
+ if (!dd_opendir(dd, dump_dir_name))
+ {
+ dd_close(dd);
+ result = 1;
+ goto ret;
+ }
+ }
+
+ if (package_full_name)
+ {
+ dd_save_text(dd, FILENAME_PACKAGE, package_full_name);
+ }
+ if (dsc)
+ {
+ dd_save_text(dd, FILENAME_DESCRIPTION, dsc);
+ }
+ if (component)
+ {
+ dd_save_text(dd, FILENAME_COMPONENT, component);
+ }
+
+//TODO: move this to a more logical place
+ if (!remote)
+ {
+ char host[HOST_NAME_MAX + 1];
+ // HOST_NAME_MAX is defined in limits.h
+ int ret = gethostname(host, HOST_NAME_MAX);
+ host[HOST_NAME_MAX] = '\0';
+ if (ret < 0)
+ {
+ perror_msg("gethostname");
+ host[0] = '\0';
+ }
+ dd_save_text(dd, FILENAME_HOSTNAME, host);
+ }
+
+ dd_close(dd);
+ result = 0;
+
+ ret:
+ free(package_full_name);
+ free(package_short_name);
+ free(component);
+ free(script_name);
+ free(dsc);
+
+ return result;
+}
+
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
+ const char *dump_dir_name = ".";
+ enum {
+ OPT_s = (1 << 0),
+ };
+ int optflags = 0;
+ int opt;
+ while ((opt = getopt(argc, argv, "d:i:t:vs")) != -1)
+ {
+ switch (opt)
+ {
+ case 'd':
+ dump_dir_name = optarg;
+ break;
+ case 'v':
+ g_verbose++;
+ break;
+ case 's':
+ optflags |= OPT_s;
+ break;
+ default:
+ /* Careful: the string below contains tabs, dont replace with spaces */
+ error_msg_and_die(
+ "Usage: abrt-action-save-package-data -d DIR [-vs]"
+ "\n"
+ "\nQuery package database and save pacakge name, component, and description"
+ "\n"
+ "\nOptions:"
+ "\n -d DIR Crash dump directory"
+ "\n -v Verbose"
+ "\n -s Log to syslog"
+ );
+ }
+ }
+
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+ msg_prefix = xasprintf("abrt-action-save-package-data[%u]", getpid());
+ if (optflags & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ VERB1 log("Loading settings");
+ if (LoadSettings() != 0)
+ return 1; /* syntax error (looged already by LoadSettings) */
+
+ VERB1 log("Initializing rpm library");
+ rpm_init();
+
+ set_string_t::iterator it_k = g_settings_setOpenGPGPublicKeys.begin();
+ for (; it_k != g_settings_setOpenGPGPublicKeys.end(); it_k++)
+ {
+ VERB1 log("Loading GPG key '%s'", it_k->c_str());
+ rpm_load_gpgkey(it_k->c_str());
+ }
+
+ return SavePackageDescriptionToDebugDump(dump_dir_name);
+ /* can call rpm_destroy but do we really need to bother? we are exiting! */
+}
diff -x '*.po' -d -urpN abrt.4/src/daemon/Daemon.cpp abrt.5/src/daemon/Daemon.cpp
--- abrt.4/src/daemon/Daemon.cpp 2010-09-22 00:55:25.623801085 +0200
+++ abrt.5/src/daemon/Daemon.cpp 2010-09-21 20:28:29.792929933 +0200
@@ -719,11 +719,8 @@ static gboolean handle_inotify_cb(GIOCha
case MW_IN_DB:
log("Huh, this crash is already in db?! Nothing to do");
break;
- case MW_BLACKLISTED:
case MW_CORRUPTED:
- case MW_PACKAGE_ERROR:
case MW_GPG_ERROR:
- case MW_FILE_ERROR:
default:
log("Corrupted or bad crash %s (res:%d), deleting", fullname, (int)res);
delete_debug_dump_dir(fullname);
diff -x '*.po' -d -urpN abrt.4/src/daemon/Makefile.am abrt.5/src/daemon/Makefile.am
--- abrt.4/src/daemon/Makefile.am 2010-09-20 14:32:02.000000000 +0200
+++ abrt.5/src/daemon/Makefile.am 2010-09-21 19:26:38.761202185 +0200
@@ -1,6 +1,9 @@
bin_SCRIPTS = abrt-debuginfo-install abrt-handle-upload
-sbin_PROGRAMS = abrtd abrt-server abrt-action-generate-backtrace
+sbin_PROGRAMS = abrtd \
+ abrt-server \
+ abrt-action-generate-backtrace \
+ abrt-action-save-package-data
abrtd_SOURCES = \
PluginManager.h PluginManager.cpp \
@@ -70,6 +73,30 @@ abrt_action_generate_backtrace_CPPFLAGS
abrt_action_generate_backtrace_LDADD = \
../../lib/utils/libABRTUtils.la
+abrt_action_save_package_data_SOURCES = \
+ rpm.h rpm.c \
+ Settings.h Settings.cpp \
+ abrt-action-save-package-data.cpp
+abrt_action_save_package_data_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \pacakge
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+# polkit_check_authorization is in libABRTdUtils
+abrt_action_save_package_data_LDADD = \
+ $(RPM_LIBS) \
+ ../../lib/utils/libABRTdUtils.la \
+ ../../lib/utils/libABRTUtils.la
+
dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
dist_dbusabrtconf_DATA = dbus-abrt.conf
diff -x '*.po' -d -urpN abrt.4/src/daemon/MiddleWare.cpp abrt.5/src/daemon/MiddleWare.cpp
--- abrt.4/src/daemon/MiddleWare.cpp 2010-09-22 00:55:58.076551160 +0200
+++ abrt.5/src/daemon/MiddleWare.cpp 2010-09-21 20:28:51.137178573 +0200
@@ -18,7 +18,6 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <fnmatch.h>
#include <algorithm> /* for std::find */
#include "abrtlib.h"
#include "Daemon.h"
@@ -639,253 +638,38 @@ static bool is_debug_dump_saved(long uid
}
/**
- * Returns the first full path argument in the command line or NULL.
- * Skips options are in form "-XXX".
- * Caller must delete the returned string using free().
- */
-static char *get_argv1_if_full_path(const char* cmdline)
-{
- const char *argv1 = strpbrk(cmdline, " \t");
- while (argv1 != NULL)
- {
- /* we found space in cmdline, so it might contain
- * path to some script like:
- * /usr/bin/python [-XXX] /usr/bin/system-control-network
- */
- argv1++; /* skip the space */
- if (*argv1 == '-') /* skip arguments */
- {
- /* looks like -XXX in "perl -XXX /usr/bin/script.pl", skip */
- argv1 = strpbrk(argv1, " \t");
- continue;
- }
- else if (*argv1 == ' ' || *argv1 == '\t') /* skip multiple spaces */
- continue;
- else if (*argv1 != '/')
- {
- /* if the string following the space doesn't start
- * with '/' it's probably not a full path to script
- * and we can't use it to determine the package name
- */
- break;
- }
-
- /* cut the rest of cmdline arguments */
- int len = strchrnul(argv1, ' ') - argv1;
- return xstrndup(argv1, len);
- }
- return NULL;
-}
-
-static bool is_path_blacklisted(const char *path)
-{
- set_string_t::iterator it = g_settings_setBlackListedPaths.begin();
- while (it != g_settings_setBlackListedPaths.end())
- {
- if (fnmatch(it->c_str(), path, /*flags:*/ 0) == 0)
- {
- return true;
- }
- it++;
- }
- return false;
-}
-
-
-/**
* Get a package name from executable name and save
* package description to particular debugdump directory of a crash.
* @param pExecutable A name of crashed application.
* @param pDebugDumpDir A debugdump dir containing all necessary data.
* @return It return results of operation. See mw_result_t.
*/
-static mw_result_t SavePackageDescriptionToDebugDump(
- const char *pExecutable,
- const char *cmdline,
- bool remote,
- const char *pDebugDumpDir)
+static mw_result_t SavePackageDescriptionToDebugDump(const char *pDebugDumpDir)
{
- char* rpm_pkg = NULL;
- char* packageName = NULL;
- char* component = NULL;
- std::string scriptName; /* only if "interpreter /path/to/script" */
-
- if (strcmp(pExecutable, "kernel") == 0)
- {
- component = xstrdup("kernel");
- rpm_pkg = xstrdup("kernel");
- packageName = xstrdup("kernel");
- }
- else
- {
- if (is_path_blacklisted(pExecutable))
- {
- log("Blacklisted executable '%s'", pExecutable);
- return MW_BLACKLISTED;
- }
-
- rpm_pkg = rpm_get_package_nvr(pExecutable);
- if (rpm_pkg == NULL)
- {
- if (g_settings_bProcessUnpackaged || remote)
- {
- VERB2 log("Crash in unpackaged executable '%s', proceeding without packaging information", pExecutable);
-
- struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- return MW_ERROR;
- }
-
- dd_save_text(dd, FILENAME_PACKAGE, "");
- dd_save_text(dd, FILENAME_COMPONENT, "");
- dd_save_text(dd, FILENAME_DESCRIPTION, "Crashed executable does not belong to any installed package");
-
- dd_close(dd);
- return MW_OK;
- }
- else
- {
- log("Executable '%s' doesn't belong to any package", pExecutable);
- return MW_PACKAGE_ERROR;
- }
- }
-
- /* Check well-known interpreter names */
-
- const char *basename = strrchr(pExecutable, '/');
- if (basename) basename++; else basename = pExecutable;
-
- /* Add more interpreters as needed */
- if (strcmp(basename, "python") == 0
- || strcmp(basename, "perl") == 0
- ) {
-// TODO: we don't verify that python executable is not modified
-// or that python package is properly signed
-// (see CheckFingerprint/CheckHash below)
-
- /* Try to find package for the script by looking at argv[1].
- * This will work only if the cmdline contains the whole path.
- * Example: python /usr/bin/system-control-network
- */
- bool knownOrigin = false;
- char *script_name = get_argv1_if_full_path(cmdline);
- if (script_name)
- {
- char *script_pkg = rpm_get_package_nvr(script_name);
- if (script_pkg)
- {
- /* There is a well-formed script name in argv[1],
- * and it does belong to some package.
- * Replace interpreter's rpm_pkg and pExecutable
- * with data pertaining to the script.
- */
- free(rpm_pkg);
- rpm_pkg = script_pkg;
- scriptName = script_name;
- pExecutable = scriptName.c_str();
- knownOrigin = true;
- /* pExecutable has changed, check it again */
- if (is_path_blacklisted(pExecutable))
- {
- log("Blacklisted executable '%s'", pExecutable);
- return MW_BLACKLISTED;
- }
- }
- free(script_name);
- }
-
- if (!knownOrigin && !g_settings_bProcessUnpackaged && !remote)
- {
- log("Interpreter crashed, but no packaged script detected: '%s'", cmdline);
- return MW_PACKAGE_ERROR;
- }
- }
-
- packageName = get_package_name_from_NVR_or_NULL(rpm_pkg);
- VERB2 log("Package:'%s' short:'%s'", rpm_pkg, packageName);
-
- if (g_settings_setBlackListedPkgs.find(packageName) != g_settings_setBlackListedPkgs.end())
- {
- log("Blacklisted package '%s'", packageName);
- free(packageName);
- return MW_BLACKLISTED;
- }
- if (g_settings_bOpenGPGCheck && !remote)
- {
- if (rpm_chk_fingerprint(packageName))
- {
- log("Package '%s' isn't signed with proper key", packageName);
- free(packageName);
- return MW_GPG_ERROR;
- }
- /*
- Checking the MD5 sum requires to run prelink to "un-prelink" the
- binaries - this is considered potential security risk so we don't
- use it, until we find some non-intrusive way
-
- Delete?
- */
- /*
- if (!CheckHash(packageName.c_str(), pExecutable))
- {
- error_msg("Executable '%s' seems to be modified, "
- "doesn't match one from package '%s'",
- pExecutable, packageName.c_str());
- return MW_GPG_ERROR;
- }
- */
- }
- component = rpm_get_component(pExecutable);
- }
-
- char *dsc = rpm_get_description(packageName);
- free(packageName);
-
- char host[HOST_NAME_MAX + 1];
- if (!remote)
+ pid_t pid = fork();
+ if (pid < 0)
{
- // HOST_NAME_MAX is defined in limits.h
- int ret = gethostname(host, HOST_NAME_MAX);
- host[HOST_NAME_MAX] = '\0';
- if (ret < 0)
- {
- perror_msg("gethostname");
- host[0] = '\0';
- }
+ perror_msg("fork");
+ return MW_ERROR;
}
-
- struct dump_dir *dd = dd_init();
- if (dd_opendir(dd, pDebugDumpDir))
+ if (pid == 0) /* child */
{
- if (rpm_pkg)
- {
- dd_save_text(dd, FILENAME_PACKAGE, rpm_pkg);
- free(rpm_pkg);
- }
-
- if (dsc)
- {
- dd_save_text(dd, FILENAME_DESCRIPTION, dsc);
- free(dsc);
- }
-
- if (component)
- {
- dd_save_text(dd, FILENAME_COMPONENT, component);
- free(component);
- }
-
- if (!remote)
- dd_save_text(dd, FILENAME_HOSTNAME, host);
+ char *argv[5]; /* abrt-action-save-package-data [-s] -d DIR NULL */
+ char **pp = argv;
+ *pp++ = (char*)"abrt-action-save-package-data";
+ if (logmode & LOGMODE_SYSLOG)
+ *pp++ = (char*)"-s";
+ *pp++ = (char*)"-d";
+ *pp++ = (char*)pDebugDumpDir;
+ *pp = NULL;
- dd_close(dd);
- return MW_OK;
+ execvp(argv[0], argv);
+ perror_msg_and_die("Can't execute '%s'", argv[0]);
}
- dd_close(dd);
-
- return MW_ERROR;
+ /* parent */
+ int status;
+ waitpid(pid, &status, 0);
+ return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? MW_OK : MW_ERROR;
}
bool analyzer_has_InformAllUsers(const char *analyzer_name)
@@ -1045,7 +829,6 @@ mw_result_t SaveDebugDump(const char *pD
map_crash_data_t& pCrashData)
{
mw_result_t res;
- int remote = 0;
struct dump_dir *dd = dd_init();
if (!dd_opendir(dd, pDebugDumpDir))
@@ -1057,14 +840,6 @@ mw_result_t SaveDebugDump(const char *pD
char *time = dd_load_text(dd, FILENAME_TIME);
char *uid = dd_load_text(dd, CD_UID);
char *analyzer = dd_load_text(dd, FILENAME_ANALYZER);
- char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
- char *cmdline = dd_load_text(dd, FILENAME_CMDLINE);
-
- char *remote_str;
- if (dd_exist(dd, FILENAME_REMOTE))
- remote_str = dd_load_text(dd, FILENAME_REMOTE);
- else
- remote_str = xstrdup("");
dd_close(dd);
@@ -1087,14 +862,7 @@ mw_result_t SaveDebugDump(const char *pD
goto error;
}
- if (remote_str[0])
- remote = remote_str[0] != '1';
-
- res = SavePackageDescriptionToDebugDump(executable,
- cmdline,
- remote,
- pDebugDumpDir
- );
+ res = SavePackageDescriptionToDebugDump(pDebugDumpDir);
if (res != MW_OK)
goto error;
@@ -1117,10 +885,7 @@ mw_result_t SaveDebugDump(const char *pD
}
error:
- free(remote_str);
free(time);
- free(executable);
- free(cmdline);
free(uid);
free(analyzer);
diff -x '*.po' -d -urpN abrt.4/src/daemon/MiddleWare.h abrt.5/src/daemon/MiddleWare.h
--- abrt.4/src/daemon/MiddleWare.h 2010-09-22 00:55:25.624800905 +0200
+++ abrt.5/src/daemon/MiddleWare.h 2010-09-21 20:28:36.334928537 +0200
@@ -30,18 +30,14 @@
*/
typedef enum {
MW_OK, /**< No error.*/
+ MW_OCCURRED, /**< A not-yet-reported dup.*/
+ MW_REPORTED, /**< A reported dup.*/
MW_ERROR, /**< Common error.*/
- MW_BLACKLISTED, /**< Package is blacklisted.*/
MW_CORRUPTED, /**< Debugdump directory is corrupted.*/
- MW_PACKAGE_ERROR, /**< Cannot determine package name.*/
MW_GPG_ERROR, /**< Package is not signed properly.*/
- MW_REPORTED, /**< Crash is already reported.*/
- MW_OCCURRED, /**< Crash occurred in the past, but it is not reported yet.*/
MW_IN_DB, /**< Debugdump directory is already saved in a database.*/
MW_IN_DB_ERROR, /**< Error while working with a database.*/
MW_PLUGIN_ERROR, /**< plugin wasn't found or error within plugin*/
- MW_FILE_ERROR /**< Error when trying open debugdump directory or
- when trying open file in debug dump directory..*/
} mw_result_t;
typedef enum {
13 years, 7 months
[PATCH] add DD_CLOSE_ON_OPEN_ERR flag to dd_opendir()
by Nikola Pajkovsky
DD_CLOSE_ON_OPEN_ERR flag indicate to free all memory allocated by
dd_init() which is passed to dd_opendir().
dd_opendir fails when dump_dir does not exist.
VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
is all removed because there is error_msg("'%s' does not exist",
dd->dd_dir); in dd_opendir().
There are two places where condition was inverted.
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
inc/dump_dir.h | 6 ++-
lib/plugins/CCpp.cpp | 28 ++-------
lib/plugins/Kerneloops.cpp | 6 +--
lib/plugins/Python.cpp | 6 +--
lib/plugins/RunApp.cpp | 6 +--
lib/plugins/SOSreport.cpp | 6 +--
lib/utils/dump_dir.c | 21 ++-----
src/daemon/MiddleWare.cpp | 88 +++++++++++---------------
src/daemon/abrt-action-generate-backtrace.c | 13 +---
9 files changed, 60 insertions(+), 120 deletions(-)
diff --git a/inc/dump_dir.h b/inc/dump_dir.h
index 8e65b1f..f02e1a5 100644
--- a/inc/dump_dir.h
+++ b/inc/dump_dir.h
@@ -26,6 +26,10 @@
extern "C" {
#endif
+enum {
+ DD_CLOSE_ON_OPEN_ERR = 1 << 0,
+};
+
struct dump_dir {
char *dd_dir;
DIR *next_dir;
@@ -37,7 +41,7 @@ struct dump_dir {
struct dump_dir *dd_init(void);
void dd_close(struct dump_dir *dd);
-int dd_opendir(struct dump_dir *dd, const char *dir);
+int dd_opendir(struct dump_dir *dd, const char *dir, int flags);
int dd_exist(struct dump_dir *dd, const char *path);
int dd_create(struct dump_dir *dd, const char *dir, uid_t uid);
DIR *dd_init_next_file(struct dump_dir *dd);
diff --git a/lib/plugins/CCpp.cpp b/lib/plugins/CCpp.cpp
index c4a1f08..041c85b 100644
--- a/lib/plugins/CCpp.cpp
+++ b/lib/plugins/CCpp.cpp
@@ -209,12 +209,8 @@ static void GetIndependentBuildIdPC(const char *unstrip_n_output,
static char* run_unstrip_n(const char *pDebugDumpDir, unsigned timeout_sec)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return NULL;
- }
char *uid = dd_load_text(dd, CD_UID);
dd_close(dd);
@@ -403,12 +399,8 @@ static void trim_debuginfo_cache(unsigned max_mb)
string CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return string("");
- }
char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
char *package = dd_load_text(dd, FILENAME_PACKAGE);
@@ -464,12 +456,8 @@ string CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir)
string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return string("");
- }
if (dd_exist(dd, FILENAME_GLOBAL_UUID))
{
@@ -640,12 +628,8 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force)
}
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return;
- }
if (!force)
{
@@ -688,11 +672,9 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force)
gen_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str(), m_nGdbTimeoutSec);
dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
{
- dd_close(dd);
free(build_ids);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
return;
}
diff --git a/lib/plugins/Kerneloops.cpp b/lib/plugins/Kerneloops.cpp
index 0c4b1a5..d3ce2e8 100644
--- a/lib/plugins/Kerneloops.cpp
+++ b/lib/plugins/Kerneloops.cpp
@@ -126,12 +126,8 @@ std::string CAnalyzerKerneloops::GetLocalUUID(const char *pDebugDumpDir)
VERB3 log("Getting local universal unique identification");
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return std::string("");
- }
char *oops = dd_load_text(dd, FILENAME_BACKTRACE);
unsigned hash = hash_oops_str(oops);
diff --git a/lib/plugins/Python.cpp b/lib/plugins/Python.cpp
index 9ef830e..5e4cc02 100644
--- a/lib/plugins/Python.cpp
+++ b/lib/plugins/Python.cpp
@@ -26,12 +26,8 @@ using namespace std;
string CAnalyzerPython::GetLocalUUID(const char *pDebugDumpDir)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return string("");
- }
char *bt = dd_load_text(dd, FILENAME_BACKTRACE);
dd_close(dd);
diff --git a/lib/plugins/RunApp.cpp b/lib/plugins/RunApp.cpp
index 0bf5ff0..3ae6638 100644
--- a/lib/plugins/RunApp.cpp
+++ b/lib/plugins/RunApp.cpp
@@ -58,12 +58,8 @@ void CActionRunApp::Run(const char *pActionDir, const char *pArgs, int force)
if (args.size() > FILENAME)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pActionDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pActionDir);
+ if (!dd_opendir(dd, pActionDir, DD_CLOSE_ON_OPEN_ERR))
return;
- }
dd_save_binary(dd, args[FILENAME].c_str(), cmd_out, cmd_out_size);
dd_close(dd);
diff --git a/lib/plugins/SOSreport.cpp b/lib/plugins/SOSreport.cpp
index 280738d..5c1b658 100644
--- a/lib/plugins/SOSreport.cpp
+++ b/lib/plugins/SOSreport.cpp
@@ -51,12 +51,8 @@ void CActionSOSreport::Run(const char *pActionDir, const char *pArgs, int force)
if (!force)
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pActionDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pActionDir);
+ if (!dd_opendir(dd, pActionDir, DD_CLOSE_ON_OPEN_ERR))
return;
- }
bool bt_exists = dd_exist(dd, "sosreport.tar.bz2") || dd_exist(dd, "sosreport.tar.xz");
if (bt_exists)
diff --git a/lib/utils/dump_dir.c b/lib/utils/dump_dir.c
index 2602ede..f81e7c9 100644
--- a/lib/utils/dump_dir.c
+++ b/lib/utils/dump_dir.c
@@ -25,16 +25,6 @@
// TODO:
//
-// dd_opendir needs a bit flags parameter, with bits for
-// "auto-close on error" and "log error message on error".
-// This will simplify a ton of places which do this:
-// if (!dd_opendir(dd, dirname))
-// {
-// dd_close(dd);
-// VERB1 log(_("Unable to open debug dump '%s'"), dirname);
-// return ........;
-// }
-//
// Perhaps dd_opendir should do some sanity checking like
// "if there is no "uid" file in the directory, it's not a crash dump",
// and fail.
@@ -99,7 +89,7 @@ void dd_close(struct dump_dir *dd)
free(dd);
}
-int dd_opendir(struct dump_dir *dd, const char *dir)
+int dd_opendir(struct dump_dir *dd, const char *dir, int flags)
{
if (dd->locked)
error_msg_and_die("dump_dir is already opened"); /* bug */
@@ -108,7 +98,9 @@ int dd_opendir(struct dump_dir *dd, const char *dir)
if (!exist_file_dir(dd->dd_dir))
{
error_msg("'%s' does not exist", dd->dd_dir);
- free(dd->dd_dir);
+ if (flags & DD_CLOSE_ON_OPEN_ERR)
+ dd_close(dd);
+
return 0;
}
@@ -485,9 +477,8 @@ int dd_get_next_file(struct dump_dir *dd, char **short_name, char **full_name)
void delete_debug_dump_dir(const char *dd_dir)
{
struct dump_dir *dd = dd_init();
- if (dd_opendir(dd, dd_dir))
+ if (dd_opendir(dd, dd_dir, 0))
dd_delete(dd);
- else
- VERB1 log("Unable to open debug dump '%s'", dd_dir);
+
dd_close(dd);
}
diff --git a/src/daemon/MiddleWare.cpp b/src/daemon/MiddleWare.cpp
index ee35369..bfab9f0 100644
--- a/src/daemon/MiddleWare.cpp
+++ b/src/daemon/MiddleWare.cpp
@@ -189,28 +189,25 @@ static bool DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_data_t&
VERB3 log(" DebugDumpToCrashReport('%s')", pDebugDumpDir);
struct dump_dir *dd = dd_init();
- if (dd_opendir(dd, pDebugDumpDir))
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
+ return false;
+
+ const char *const *v = must_have_files;
+ while (*v)
{
- const char *const *v = must_have_files;
- while (*v)
+ if (!dd_exist(dd, *v))
{
- if (!dd_exist(dd, *v))
- {
- dd_close(dd);
- throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): important file '%s' is missing", *v);
- }
-
- v++;
+ dd_close(dd);
+ throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): important file '%s' is missing", *v);
}
- load_crash_data_from_debug_dump(dd, pCrashData);
- dd_close(dd);
-
- return true;
+ v++;
}
+ load_crash_data_from_debug_dump(dd, pCrashData);
dd_close(dd);
- return false;
+
+ return true;
}
/**
@@ -305,9 +302,8 @@ mw_result_t CreateCrashReport(const char *crash_id,
try
{
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, row->db_dump_dir))
+ if (!dd_opendir(dd, row->db_dump_dir, DD_CLOSE_ON_OPEN_ERR))
{
- dd_close(dd);
db_row_free(row);
return MW_ERROR;
}
@@ -462,7 +458,7 @@ report_status_t Report(const map_crash_data_t& client_report,
if (comment || reproduce || backtrace)
{
struct dump_dir *dd = dd_init();
- if (dd_opendir(dd, pDumpDir.c_str()))
+ if (dd_opendir(dd, pDumpDir.c_str(), 0))
{
if (comment)
{
@@ -738,11 +734,8 @@ static mw_result_t SavePackageDescriptionToDebugDump(
VERB2 log("Crash in unpackaged executable '%s', proceeding without packaging information", pExecutable);
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return MW_ERROR;
- }
dd_save_text(dd, FILENAME_PACKAGE, "");
dd_save_text(dd, FILENAME_COMPONENT, "");
@@ -863,35 +856,32 @@ static mw_result_t SavePackageDescriptionToDebugDump(
}
struct dump_dir *dd = dd_init();
- if (dd_opendir(dd, pDebugDumpDir))
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
+ return MW_ERROR;
+
+ if (rpm_pkg)
{
- if (rpm_pkg)
- {
- dd_save_text(dd, FILENAME_PACKAGE, rpm_pkg);
- free(rpm_pkg);
- }
+ dd_save_text(dd, FILENAME_PACKAGE, rpm_pkg);
+ free(rpm_pkg);
+ }
- if (dsc)
- {
- dd_save_text(dd, FILENAME_DESCRIPTION, dsc);
- free(dsc);
- }
+ if (dsc)
+ {
+ dd_save_text(dd, FILENAME_DESCRIPTION, dsc);
+ free(dsc);
+ }
- if (component)
- {
- dd_save_text(dd, FILENAME_COMPONENT, component);
- free(component);
- }
+ if (component)
+ {
+ dd_save_text(dd, FILENAME_COMPONENT, component);
+ free(component);
+ }
- if (!remote)
- dd_save_text(dd, FILENAME_HOSTNAME, host);
+ if (!remote)
+ dd_save_text(dd, FILENAME_HOSTNAME, host);
- dd_close(dd);
- return MW_OK;
- }
dd_close(dd);
-
- return MW_ERROR;
+ return MW_OK;
}
bool analyzer_has_InformAllUsers(const char *analyzer_name)
@@ -1054,11 +1044,8 @@ mw_result_t SaveDebugDump(const char *pDebugDumpDir,
int remote = 0;
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
+ if (!dd_opendir(dd, pDebugDumpDir, DD_CLOSE_ON_OPEN_ERR))
return MW_ERROR;
- }
char *time = dd_load_text(dd, FILENAME_TIME);
char *uid = dd_load_text(dd, CD_UID);
@@ -1143,9 +1130,8 @@ mw_result_t FillCrashInfo(const char *crash_id,
return MW_ERROR;
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, row->db_dump_dir))
+ if (!dd_opendir(dd, row->db_dump_dir, DD_CLOSE_ON_OPEN_ERR))
{
- dd_close(dd);
db_row_free(row);
return MW_ERROR;
}
diff --git a/src/daemon/abrt-action-generate-backtrace.c b/src/daemon/abrt-action-generate-backtrace.c
index 8bedf54..46f002a 100644
--- a/src/daemon/abrt-action-generate-backtrace.c
+++ b/src/daemon/abrt-action-generate-backtrace.c
@@ -303,12 +303,8 @@ int main(int argc, char **argv)
}
struct dump_dir *dd = dd_init();
- if (!dd_opendir(dd, dump_dir_name))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), dump_dir_name);
+ if (!dd_opendir(dd, dump_dir_name, DD_CLOSE_ON_OPEN_ERR))
return 1;
- }
char *package = dd_load_text(dd, FILENAME_PACKAGE);
char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
@@ -323,12 +319,9 @@ int main(int argc, char **argv)
}
dd = dd_init();
- if (!dd_opendir(dd, dump_dir_name))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), dump_dir_name);
+ if (!dd_opendir(dd, dump_dir_name, DD_CLOSE_ON_OPEN_ERR))
return 1;
- }
+
dd_save_text(dd, FILENAME_BACKTRACE, backtrace_str);
/* Compute and store backtrace hash. */
--
1.7.1
13 years, 7 months
FYI debuginfofs has became viable for F14+ (.gdb_index)
by Jan Kratochvil
Hi,
# https://fedorahosted.org/abrt/wiki/RFE
# RETRACE SERVER
# * recreating the bt means:
# o downloading the required debuginfo (if it's not cached)
# o replacing the ???? with proper function names
# o add a line numbers pointing to source file
Backtracing without debuginfo cannot provide the complete information now
(it misses inlined frames) and more features in development + planned also
could not be supported in the future. Preview of the latter is shown at:
Re: [PATCH] Debug info extensions to support optimized out parameters
http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00385.html
Since Fedora 14 GDB supports .gdb_index (by Tom Tromey) and therefore now
debuginfofs has started to make sense. It made no sense before as GDB read
the whole .debug file first just to index it; this is no longer true and only
the small .gdb_index section is being read in.
http://fedoraproject.org/wiki/Features/DebuginfoFS
debuginfofs can provide the same debug info features as an upload of the whole
core file; the core upload is not feasible for security reasons.
Still it means retrace server cannot do the backtracing task, this has to be
done at the client side - for security reasons.
Which network protocol, its signing and what servers to use for DebuginfoFS
remains a question. Also .gdb_index has been developed with the goal of
improved on-disk performance; a network filesystem performance may need more
tuning. GDB could also use some file access library (neon as an example) for
the .debug files access avoiding the need of mounting any network filesystem.
Regards,
Jan
13 years, 7 months
[PATCH] move backtrace generation to a separate program (abrt-action-generate-backtrace)
by Denys Vlasenko
This patch splits off CCpp's backtrace generation into a separate tool:
# abrt-action-generate-backtrace -z
abrt-action-generate-backtrace: invalid option -- 'z'
Usage: abrt-action-generate-backtrace -d DIR [-i DIR1:DIR2] [-t SECONDS] [-vs]
Generate backtrace, its quality rating, hash, and crashed function
Options:
-d DIR Crash dump directory
-i DIR1:DIR2 Additional debuginfo directories
-t SECONDS Kill gdb if it runs for more than SECONDS
-v Verbose
-s Log to syslog
This allows for simpler timeout handling
using SIGALRM, and makes timers for tracking client timeouts
unnecessary.
This also allows for debugging and regression testing of
abrt-action-generate-backtrace separately - it can be simply run
from command-line.
Also it provides a better fault isolation - crash in
abrt-action-generate-backtrace does not take down abrtd.
The code is based on CCpp.cpp.
CCpp analyzer is made to swawn a child to do the backtrace generation.
Run tested.
Please review.
--
vda
diff -x '*.po' -d -urpN abrt.1/abrt.spec abrt.2/abrt.spec
--- abrt.1/abrt.spec 2010-09-14 19:21:46.000000000 +0200
+++ abrt.2/abrt.spec 2010-09-14 19:30:13.081789613 +0200
@@ -349,6 +349,7 @@ fi
%endif
%{_sbindir}/abrtd
%{_sbindir}/abrt-server
+%{_sbindir}/abrt-action-generate-backtrace
%{_bindir}/%{name}-debuginfo-install
%{_bindir}/%{name}-handle-upload
%{_bindir}/%{name}-backtrace
diff -x '*.po' -d -urpN abrt.1/lib/plugins/CCpp.cpp abrt.2/lib/plugins/CCpp.cpp
--- abrt.1/lib/plugins/CCpp.cpp 2010-09-16 14:40:30.920648834 +0200
+++ abrt.2/lib/plugins/CCpp.cpp 2010-09-16 14:04:21.723648896 +0200
@@ -141,136 +141,42 @@ static char* exec_vp(char **args, uid_t
}
close(pipeout[0]);
- int st;
- waitpid(child, &st, 0); /* prevent having zombie child process */
- if (status)
- *status = st;
+ /* Prevent having zombie child process, and maybe collect status
+ * (note that status == NULL is ok too) */
+ waitpid(child, status, 0);
return strbuf_free_nobuf(buf_out);
}
-static char *get_backtrace(const char *pDebugDumpDir, const char *pDebugInfoDirs, unsigned timeout_sec)
+static void gen_backtrace(const char *pDebugDumpDir, const char *pDebugInfoDirs, unsigned timeout_sec)
{
update_client(_("Generating backtrace"));
- dump_dir_t *dd = dd_init();
- if (!dd_opendir(dd, pDebugDumpDir))
- {
- dd_close(dd);
- VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
- return NULL;
- }
-
- char *uid_str = dd_load_text(dd, CD_UID);
- uid_t uid = xatoi_u(uid_str);
- free(uid_str);
- char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
- dd_close(dd);
-
- // Workaround for
- // http://sourceware.org/bugzilla/show_bug.cgi?id=9622
- unsetenv("TERM");
- // This is not necessary, and was observed to cause
- // environment corruption (because we run in a thread?):
- //putenv((char*)"TERM=dumb");
-
- char *args[21];
- args[0] = (char*)"gdb";
- args[1] = (char*)"-batch";
-
- // when/if gdb supports "set debug-file-directory DIR1:DIR2":
- // (https://bugzilla.redhat.com/show_bug.cgi?id=528668):
- args[2] = (char*)"-ex";
- string dfd = "set debug-file-directory /usr/lib/debug";
- const char *p = pDebugInfoDirs;
- while (1)
+ pid_t pid = fork();
+ if (pid < 0)
{
- const char *colon_or_nul = strchrnul(p, ':');
- dfd += ':';
- dfd.append(p, colon_or_nul - p);
- dfd += "/usr/lib/debug";
- if (*colon_or_nul != ':')
- break;
- p = colon_or_nul + 1;
+ perror_msg("fork");
+ return;
}
- args[3] = (char*)dfd.c_str();
-
- /* "file BINARY_FILE" is needed, without it gdb cannot properly
- * unwind the stack. Currently the unwind information is located
- * in .eh_frame which is stored only in binary, not in coredump
- * or debuginfo.
- *
- * Fedora GDB does not strictly need it, it will find the binary
- * by its build-id. But for binaries either without build-id
- * (= built on non-Fedora GCC) or which do not have
- * their debuginfo rpm installed gdb would not find BINARY_FILE
- * so it is still makes sense to supply "file BINARY_FILE".
- *
- * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE
- * was deleted (as often happens during system updates):
- * gdb uses specified BINARY_FILE
- * even if it is completely unrelated to the coredump.
- * See https://bugzilla.redhat.com/show_bug.cgi?id=525721
- *
- * TODO: check mtimes on COREFILE and BINARY_FILE and not supply
- * BINARY_FILE if it is newer (to at least avoid gdb complaining).
- */
- args[4] = (char*)"-ex";
- args[5] = xasprintf("file %s", executable);
- free(executable);
-
- args[6] = (char*)"-ex";
- args[7] = xasprintf("core-file %s/"FILENAME_COREDUMP, pDebugDumpDir);
-
- args[8] = (char*)"-ex";
- /*args[9] = ... see below */
- args[10] = (char*)"-ex";
- args[11] = (char*)"info sharedlib";
- /* glibc's abort() stores its message in __abort_msg variable */
- args[12] = (char*)"-ex";
- args[13] = (char*)"print (char*)__abort_msg";
- args[14] = (char*)"-ex";
- args[15] = (char*)"print (char*)__glib_assert_msg";
- args[16] = (char*)"-ex";
- args[17] = (char*)"info registers";
- args[18] = (char*)"-ex";
- args[19] = (char*)"disassemble";
- args[20] = NULL;
-
- /* Get the backtrace, but try to cap its size */
- /* Limit bt depth. With no limit, gdb sometimes OOMs the machine */
- unsigned bt_depth = 2048;
- const char *thread_apply_all = "thread apply all";
- const char *full = " full";
- char *bt = NULL;
- while (1)
+ if (pid == 0) /* child */
{
- args[9] = xasprintf("%s backtrace %u%s", thread_apply_all, bt_depth, full);
- bt = exec_vp(args, uid, /*redirect_stderr:*/ 1, timeout_sec, NULL);
- free(args[9]);
- if ((bt && strnlen(bt, 256*1024) < 256*1024) || bt_depth <= 32)
- {
- break;
- }
+ char *argv[8]; /* abrt-action-generate-backtrace [-s] -tSEC -d DIR -i DIR1:DIR2 NULL */
+ char **pp = argv;
+ *pp++ = (char*)"abrt-action-generate-backtrace";
+ if (logmode & LOGMODE_SYSLOG)
+ *pp++ = (char*)"-s";
+ *pp++ = xasprintf("-t%u", timeout_sec);
+ *pp++ = (char*)"-d";
+ *pp++ = (char*)pDebugDumpDir;
+ *pp++ = (char*)"-i";
+ *pp++ = (char*)pDebugInfoDirs;
+ *pp = NULL;
- free(bt);
- bt_depth /= 2;
- if (bt_depth <= 64 && thread_apply_all[0] != '\0')
- {
- /* This program likely has gazillion threads, dont try to bt them all */
- bt_depth = 256;
- thread_apply_all = "";
- }
- if (bt_depth <= 64 && full[0] != '\0')
- {
- /* Looks like there are gigantic local structures or arrays, disable "full" bt */
- bt_depth = 256;
- full = "";
- }
+ execvp(argv[0], argv);
+ perror_msg_and_die("Can't execute '%s'", argv[0]);
}
- free(args[5]);
- free(args[7]);
- return bt;
+ /* parent */
+ waitpid(pid, NULL, 0);
}
static void GetIndependentBuildIdPC(const char *unstrip_n_output,
@@ -764,8 +670,6 @@ void CAnalyzerCCpp::CreateReport(const c
}
}
- char *package = dd_load_text(dd, FILENAME_PACKAGE);
- char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
char *uid = dd_load_text(dd, CD_UID);
dd_close(dd); /* do not keep dir locked longer than needed */
@@ -780,118 +684,30 @@ void CAnalyzerCCpp::CreateReport(const c
VERB1 log(_("Skipping the debuginfo installation"));
free(uid);
- /* Create and store backtrace. */
- char *backtrace_str = get_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str(), m_nGdbTimeoutSec);
- if (!backtrace_str)
- {
- backtrace_str = xstrdup("");
- VERB3 log("get_backtrace() returns NULL, broken core/gdb?");
- }
-
- char *bt_build_ids = xasprintf("%s%s", backtrace_str, (build_ids) ? build_ids : "");
- free(build_ids);
+ /* Create and store backtrace and its hash. */
+ gen_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str(), m_nGdbTimeoutSec);
dd = dd_init();
if (!dd_opendir(dd, pDebugDumpDir))
{
dd_close(dd);
+ free(build_ids);
VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
return;
}
+
+ /* Add build_ids to backtrace */
+ char *backtrace_str = dd_load_text(dd, FILENAME_BACKTRACE);
+ char *bt_build_ids = xasprintf("%s%s", backtrace_str, (build_ids) ? build_ids : "");
dd_save_text(dd, FILENAME_BACKTRACE, bt_build_ids);
+ free(build_ids);
free(bt_build_ids);
+ free(backtrace_str);
+ /* TODO: remove, it's much easier to collect in the coredump helper */
if (m_bMemoryMap)
dd_save_text(dd, FILENAME_MEMORYMAP, "memory map of the crashed C/C++ application, not implemented yet");
- /* Compute and store UUID from the backtrace. */
- char *backtrace_cpy = xstrdup(backtrace_str);
-
- struct backtrace *backtrace = backtrace_parse(backtrace_cpy, false, false);
- free(backtrace_cpy);
-
- if (backtrace)
- {
- /* Get the quality of the full backtrace. */
- float q1 = backtrace_quality(backtrace);
-
- /* Remove all the other threads except the crash thread. */
- struct thread *crash_thread = backtrace_find_crash_thread(backtrace);
- if (crash_thread)
- backtrace_remove_threads_except_one(backtrace, crash_thread);
- else
- log_msg("Detection of crash thread failed");
-
- /* Get the quality of the crash thread. */
- float q2 = backtrace_quality(backtrace);
-
- backtrace_remove_noncrash_frames(backtrace);
-
- /* Do the frame removal now. */
- backtrace_limit_frame_depth(backtrace, 5);
- /* Frame removal can be done before removing exit handlers. */
- backtrace_remove_exit_handlers(backtrace);
-
- /* Get the quality of frames around the crash. */
- float q3 = backtrace_quality(backtrace);
-
- /* Compute UUID. */
- struct strbuf *bt = backtrace_tree_as_str(backtrace, false);
- strbuf_prepend_str(bt, executable);
- strbuf_prepend_str(bt, package);
- char hash_str[SHA1_RESULT_LEN*2 + 1];
- create_hash(hash_str, bt->buf);
- dd_save_text(dd, FILENAME_GLOBAL_UUID, hash_str);
- strbuf_free(bt);
-
- /* Compute and store backtrace rating. The crash frame
- is more important that the others. The frames around
- the crash are more important than the rest. */
- float qtot = 0.25f * q1 + 0.35f * q2 + 0.4f * q3;
-
- /* Turn the quality to rating. */
- const char *rating;
- if (qtot < 0.6f) rating = "0";
- else if (qtot < 0.7f) rating = "1";
- else if (qtot < 0.8f) rating = "2";
- else if (qtot < 0.9f) rating = "3";
- else rating = "4";
- dd_save_text(dd, FILENAME_RATING, rating);
-
- /* Get the function name from the crash frame. */
- if (crash_thread)
- {
- struct frame *crash_frame = crash_thread->frames;
- struct frame *abort_frame = thread_find_abort_frame(crash_thread);
- if (abort_frame)
- crash_frame = abort_frame->next;
- if (crash_frame && crash_frame->function && 0 != strcmp(crash_frame->function, "??"))
- dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function);
- }
-
- backtrace_free(backtrace);
- }
- else
- {
- /* If the parser failed fall back to the independent backtrace. */
- /* If we write and use a hand-written parser instead of the bison one,
- the parser never fails, and it will be possible to get rid of
- the independent_backtrace and backtrace_rate_old. */
- struct strbuf *ibt = independent_backtrace(backtrace_str);
- strbuf_prepend_str(ibt, executable);
- strbuf_prepend_str(ibt, package);
- char hash_str[SHA1_RESULT_LEN*2 + 1];
- create_hash(hash_str, ibt->buf);
- dd_save_text(dd, FILENAME_GLOBAL_UUID, hash_str);
- strbuf_free(ibt);
-
- /* Compute and store backtrace rating. */
- /* Crash frame is not known so store nothing. */
- dd_save_text(dd, FILENAME_RATING, to_string(backtrace_rate_old(backtrace_str)).c_str());
- }
- free(executable);
- free(package);
- free(backtrace_str);
dd_close(dd);
}
diff -x '*.po' -d -urpN abrt.1/src/daemon/abrt-action-generate-backtrace.c abrt.2/src/daemon/abrt-action-generate-backtrace.c
--- abrt.1/src/daemon/abrt-action-generate-backtrace.c 1970-01-01 01:00:00.000000000 +0100
+++ abrt.2/src/daemon/abrt-action-generate-backtrace.c 2010-09-16 14:18:37.317648093 +0200
@@ -0,0 +1,428 @@
+/*
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "backtrace.h"
+
+
+#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di"
+
+
+static const char *dump_dir_name = ".";
+static char *debuginfo_dirs;
+static unsigned exec_timeout_sec = 60;
+
+
+static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput)
+{
+ unsigned len;
+ unsigned char hash2[SHA1_RESULT_LEN];
+ sha1_ctx_t sha1ctx;
+
+ sha1_begin(&sha1ctx);
+ sha1_hash(pInput, strlen(pInput), &sha1ctx);
+ sha1_end(hash2, &sha1ctx);
+ len = SHA1_RESULT_LEN;
+
+ char *d = hash_str;
+ unsigned char *s = hash2;
+ while (len)
+ {
+ *d++ = "0123456789abcdef"[*s >> 4];
+ *d++ = "0123456789abcdef"[*s & 0xf];
+ s++;
+ len--;
+ }
+ *d = '\0';
+ //log("hash2:%s str:'%s'", hash_str, pInput);
+}
+
+/**
+ *
+ * @param[out] status See `man 2 wait` for status information.
+ * @return Malloc'ed string
+ */
+static char* exec_vp(char **args, uid_t uid, int redirect_stderr, int *status)
+{
+ /* Nuke everything which may make setlocale() switch to non-POSIX locale:
+ * we need to avoid having gdb output in some obscure language.
+ */
+ static const char *const unsetenv_vec[] = {
+ "LANG",
+ "LC_ALL",
+ "LC_COLLATE",
+ "LC_CTYPE",
+ "LC_MESSAGES",
+ "LC_MONETARY",
+ "LC_NUMERIC",
+ "LC_TIME",
+ NULL
+ };
+
+ int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETGUID | EXECFLG_SETSID | EXECFLG_QUIET;
+ if (redirect_stderr)
+ flags |= EXECFLG_ERR2OUT;
+ VERB1 flags &= ~EXECFLG_QUIET;
+
+ int pipeout[2];
+ pid_t child = fork_execv_on_steroids(flags, args, pipeout, (char**)unsetenv_vec, /*dir:*/ NULL, uid);
+
+ /* We use this function to run gdb and unstrip. Bugs in gdb or corrupted
+ * coredumps were observed to cause gdb to enter infinite loop.
+ * Therefore we have a (largish) timeout, after which we kill the child.
+ */
+ int t = time(NULL); /* int is enough, no need to use time_t */
+ int endtime = t + exec_timeout_sec;
+
+ struct strbuf *buf_out = strbuf_new();
+
+ while (1)
+ {
+ int timeout = endtime - t;
+ if (timeout < 0)
+ {
+ kill(child, SIGKILL);
+ strbuf_append_strf(buf_out, "\nTimeout exceeded: %u seconds, killing %s\n", exec_timeout_sec, args[0]);
+ break;
+ }
+
+ /* We don't check poll result - checking read result is enough */
+ struct pollfd pfd;
+ pfd.fd = pipeout[0];
+ pfd.events = POLLIN;
+ poll(&pfd, 1, timeout * 1000);
+
+ char buff[1024];
+ int r = read(pipeout[0], buff, sizeof(buff) - 1);
+ if (r <= 0)
+ break;
+ buff[r] = '\0';
+ strbuf_append_str(buf_out, buff);
+ t = time(NULL);
+ }
+ close(pipeout[0]);
+
+ /* Prevent having zombie child process, and maybe collect status
+ * (note that status == NULL is ok too) */
+ waitpid(child, status, 0);
+
+ return strbuf_free_nobuf(buf_out);
+}
+
+static char *get_backtrace(dump_dir_t *dd)
+{
+ char *uid_str = dd_load_text(dd, CD_UID);
+ uid_t uid = xatoi_u(uid_str);
+ free(uid_str);
+ char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
+ dd_close(dd);
+
+ // Workaround for
+ // http://sourceware.org/bugzilla/show_bug.cgi?id=9622
+ unsetenv("TERM");
+ // This is not necessary
+ //putenv((char*)"TERM=dumb");
+
+ char *args[21];
+ args[0] = (char*)"gdb";
+ args[1] = (char*)"-batch";
+
+ // when/if gdb supports "set debug-file-directory DIR1:DIR2":
+ // (https://bugzilla.redhat.com/show_bug.cgi?id=528668):
+ args[2] = (char*)"-ex";
+ struct strbuf *set_debug_file_directory = strbuf_new();
+ strbuf_append_str(set_debug_file_directory, "set debug-file-directory /usr/lib/debug");
+ const char *p = debuginfo_dirs;
+ while (1)
+ {
+ while (*p == ':')
+ p++;
+ if (*p == '\0')
+ break;
+ const char *colon_or_nul = strchrnul(p, ':');
+ strbuf_append_strf(set_debug_file_directory, ":%.*s/usr/lib/debug", (int)(colon_or_nul - p), p);
+ p = colon_or_nul;
+ }
+ args[3] = strbuf_free_nobuf(set_debug_file_directory);
+
+ /* "file BINARY_FILE" is needed, without it gdb cannot properly
+ * unwind the stack. Currently the unwind information is located
+ * in .eh_frame which is stored only in binary, not in coredump
+ * or debuginfo.
+ *
+ * Fedora GDB does not strictly need it, it will find the binary
+ * by its build-id. But for binaries either without build-id
+ * (= built on non-Fedora GCC) or which do not have
+ * their debuginfo rpm installed gdb would not find BINARY_FILE
+ * so it is still makes sense to supply "file BINARY_FILE".
+ *
+ * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE
+ * was deleted (as often happens during system updates):
+ * gdb uses specified BINARY_FILE
+ * even if it is completely unrelated to the coredump.
+ * See https://bugzilla.redhat.com/show_bug.cgi?id=525721
+ *
+ * TODO: check mtimes on COREFILE and BINARY_FILE and not supply
+ * BINARY_FILE if it is newer (to at least avoid gdb complaining).
+ */
+ args[4] = (char*)"-ex";
+ args[5] = xasprintf("file %s", executable);
+ free(executable);
+
+ args[6] = (char*)"-ex";
+ args[7] = xasprintf("core-file %s/"FILENAME_COREDUMP, dump_dir_name);
+
+ args[8] = (char*)"-ex";
+ /*args[9] = ... see below */
+ args[10] = (char*)"-ex";
+ args[11] = (char*)"info sharedlib";
+ /* glibc's abort() stores its message in __abort_msg variable */
+ args[12] = (char*)"-ex";
+ args[13] = (char*)"print (char*)__abort_msg";
+ args[14] = (char*)"-ex";
+ args[15] = (char*)"print (char*)__glib_assert_msg";
+ args[16] = (char*)"-ex";
+ args[17] = (char*)"info registers";
+ args[18] = (char*)"-ex";
+ args[19] = (char*)"disassemble";
+ args[20] = NULL;
+
+ /* Get the backtrace, but try to cap its size */
+ /* Limit bt depth. With no limit, gdb sometimes OOMs the machine */
+ unsigned bt_depth = 2048;
+ const char *thread_apply_all = "thread apply all";
+ const char *full = " full";
+ char *bt = NULL;
+ while (1)
+ {
+ args[9] = xasprintf("%s backtrace %u%s", thread_apply_all, bt_depth, full);
+ bt = exec_vp(args, uid, /*redirect_stderr:*/ 1, NULL);
+ free(args[9]);
+ if ((bt && strnlen(bt, 256*1024) < 256*1024) || bt_depth <= 32)
+ {
+ break;
+ }
+
+ free(bt);
+ bt_depth /= 2;
+ if (bt_depth <= 64 && thread_apply_all[0] != '\0')
+ {
+ /* This program likely has gazillion threads, dont try to bt them all */
+ bt_depth = 256;
+ thread_apply_all = "";
+ }
+ if (bt_depth <= 64 && full[0] != '\0')
+ {
+ /* Looks like there are gigantic local structures or arrays, disable "full" bt */
+ bt_depth = 256;
+ full = "";
+ }
+ }
+
+ free(args[3]);
+ free(args[5]);
+ free(args[7]);
+ return bt;
+}
+
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
+ debuginfo_dirs = xstrdup(DEBUGINFO_CACHE_DIR);
+ enum {
+ OPT_s = (1 << 0),
+ };
+ int optflags = 0;
+ int opt;
+ while ((opt = getopt(argc, argv, "d:i:t:vs")) != -1)
+ {
+ switch (opt)
+ {
+ case 'd':
+ dump_dir_name = optarg;
+ break;
+ case 'i': {
+ char *old = debuginfo_dirs;
+ if (optarg[0])
+ debuginfo_dirs = xasprintf("%s:%s", debuginfo_dirs, optarg);
+ else
+ debuginfo_dirs = xstrdup("");
+ free(old);
+ break;
+ }
+ case 't':
+ exec_timeout_sec = xatoi_u(optarg);
+ break;
+ case 'v':
+ g_verbose++;
+ break;
+ case 's':
+ optflags |= OPT_s;
+ break;
+ default:
+ /* Careful: the string below contains tabs, dont replace with spaces */
+ error_msg_and_die(
+ "Usage: abrt-action-generate-backtrace -d DIR [-i DIR1:DIR2] [-t SECONDS] [-vs]"
+ "\n"
+ "\nGenerate backtrace, its quality rating, hash, and crashed function"
+ "\n"
+ "\nOptions:"
+ "\n -d DIR Crash dump directory"
+ "\n -i DIR1:DIR2 Additional debuginfo directories"
+ "\n -t SECONDS Kill gdb if it runs for more than SECONDS"
+ "\n -v Verbose"
+ "\n -s Log to syslog"
+ );
+ }
+ }
+
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+ msg_prefix = xasprintf("abrt-action-generate-backtrace[%u]", getpid());
+ if (optflags & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ dump_dir_t *dd = dd_init();
+ if (!dd_opendir(dd, dump_dir_name))
+ {
+ dd_close(dd);
+ VERB1 log(_("Unable to open debug dump '%s'"), dump_dir_name);
+ return 1;
+ }
+
+ char *package = dd_load_text(dd, FILENAME_PACKAGE);
+ char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
+
+ /* Create and store backtrace */
+ /* NB: get_backtrace() closes dd */
+ char *backtrace_str = get_backtrace(dd);
+ if (!backtrace_str)
+ {
+ backtrace_str = xstrdup("");
+ VERB3 log("get_backtrace() returns NULL, broken core/gdb?");
+ }
+
+ dd = dd_init();
+ if (!dd_opendir(dd, dump_dir_name))
+ {
+ dd_close(dd);
+ VERB1 log(_("Unable to open debug dump '%s'"), dump_dir_name);
+ return 1;
+ }
+ dd_save_text(dd, FILENAME_BACKTRACE, backtrace_str);
+
+ /* Compute and store backtrace hash. */
+ char *backtrace_cpy = xstrdup(backtrace_str);
+ struct backtrace *backtrace = backtrace_parse(backtrace_cpy, false, false);
+ free(backtrace_cpy);
+ if (backtrace)
+ {
+ /* Get the quality of the full backtrace. */
+ float q1 = backtrace_quality(backtrace);
+
+ /* Remove all the other threads except the crash thread. */
+ struct thread *crash_thread = backtrace_find_crash_thread(backtrace);
+ if (crash_thread)
+ backtrace_remove_threads_except_one(backtrace, crash_thread);
+ else
+ log_msg("Detection of crash thread failed");
+
+ /* Get the quality of the crash thread. */
+ float q2 = backtrace_quality(backtrace);
+
+ backtrace_remove_noncrash_frames(backtrace);
+
+ /* Do the frame removal now. */
+ backtrace_limit_frame_depth(backtrace, 5);
+ /* Frame removal can be done before removing exit handlers. */
+ backtrace_remove_exit_handlers(backtrace);
+
+ /* Get the quality of frames around the crash. */
+ float q3 = backtrace_quality(backtrace);
+
+ /* Compute UUID. */
+ struct strbuf *bt = backtrace_tree_as_str(backtrace, false);
+ strbuf_prepend_str(bt, executable);
+ strbuf_prepend_str(bt, package);
+ char hash_str[SHA1_RESULT_LEN*2 + 1];
+ create_hash(hash_str, bt->buf);
+ dd_save_text(dd, FILENAME_GLOBAL_UUID, hash_str);
+ strbuf_free(bt);
+
+ /* Compute and store backtrace rating. The crash frame
+ is more important that the others. The frames around
+ the crash are more important than the rest. */
+ float qtot = 0.25f * q1 + 0.35f * q2 + 0.4f * q3;
+
+ /* Turn the quality to rating. */
+ const char *rating;
+ if (qtot < 0.6f) rating = "0";
+ else if (qtot < 0.7f) rating = "1";
+ else if (qtot < 0.8f) rating = "2";
+ else if (qtot < 0.9f) rating = "3";
+ else rating = "4";
+ dd_save_text(dd, FILENAME_RATING, rating);
+
+ /* Get the function name from the crash frame. */
+ if (crash_thread)
+ {
+ struct frame *crash_frame = crash_thread->frames;
+ struct frame *abort_frame = thread_find_abort_frame(crash_thread);
+ if (abort_frame)
+ crash_frame = abort_frame->next;
+ if (crash_frame && crash_frame->function && 0 != strcmp(crash_frame->function, "??"))
+ dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function);
+ }
+
+ backtrace_free(backtrace);
+ }
+ else
+ {
+ /* If the parser failed fall back to the independent backtrace. */
+ /* If we write and use a hand-written parser instead of the bison one,
+ the parser never fails, and it will be possible to get rid of
+ the independent_backtrace and backtrace_rate_old. */
+ struct strbuf *ibt = independent_backtrace(backtrace_str);
+ strbuf_prepend_str(ibt, executable);
+ strbuf_prepend_str(ibt, package);
+ char hash_str[SHA1_RESULT_LEN*2 + 1];
+ create_hash(hash_str, ibt->buf);
+ dd_save_text(dd, FILENAME_GLOBAL_UUID, hash_str);
+ strbuf_free(ibt);
+
+ /* Compute and store backtrace rating. */
+ /* Crash frame is not known so store nothing. */
+ int rate = backtrace_rate_old(backtrace_str);
+ char rate_buf[sizeof(rate)*3 + 2];
+ sprintf(rate_buf, "%d", rate);
+ dd_save_text(dd, FILENAME_RATING, rate_buf);
+ }
+
+ dd_close(dd);
+
+ free(executable);
+ free(package);
+ free(backtrace_str);
+
+ return 0;
+}
diff -x '*.po' -d -urpN abrt.1/src/daemon/Makefile.am abrt.2/src/daemon/Makefile.am
--- abrt.1/src/daemon/Makefile.am 2010-09-14 19:21:46.000000000 +0200
+++ abrt.2/src/daemon/Makefile.am 2010-09-14 19:30:13.084789698 +0200
@@ -1,6 +1,6 @@
bin_SCRIPTS = abrt-debuginfo-install abrt-handle-upload
-sbin_PROGRAMS = abrtd abrt-server
+sbin_PROGRAMS = abrtd abrt-server abrt-action-generate-backtrace
abrtd_SOURCES = \
PluginManager.h PluginManager.cpp \
@@ -52,6 +52,24 @@ abrt_server_CPPFLAGS = \
abrt_server_LDADD = \
../../lib/utils/libABRTUtils.la
+abrt_action_generate_backtrace_SOURCES = \
+ abrt-action-generate-backtrace.c
+abrt_action_generate_backtrace_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_generate_backtrace_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
dist_dbusabrtconf_DATA = dbus-abrt.conf
13 years, 7 months