summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-11-01 18:52:11 +0100
committerDenys Vlasenko <dvlasenk@redhat.com>2010-11-01 18:52:11 +0100
commit8864e7d8ab05b59372f55ec8d637296aefa1515e (patch)
tree820b284348e0e0672534abdca6231212b4bf3af8
parent3b1dd4985ac7e32a3a1a498214bd26df29089dbc (diff)
downloadabrt-8864e7d8ab05b59372f55ec8d637296aefa1515e.tar.gz
abrt-8864e7d8ab05b59372f55ec8d637296aefa1515e.tar.xz
abrt-8864e7d8ab05b59372f55ec8d637296aefa1515e.zip
abrt-handle-crashdump: new semi-debug utility to run abrt actions for a specified event
Some reworking of run_action() API was needed to make it possible to put it into libABRT. abrt-handle-crashdump has no -l option yet: $ abrt-handle-crashdump Usage: abrt-handle-crashdump [-vs] -d DIR -e EVENT Handle crash dump according to rules in abrt_action.conf -v, --verbose be verbose -s Log to syslog -d DIR Crash dump directory -e EVENT Event Can (will) extend it later. Run-tested: performed "analyze" step by hand with abrt-handle-crashdump -e analyze -d CRASH_DUMP_DIR Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r--abrt.spec1
-rw-r--r--inc/abrtlib.h12
-rw-r--r--lib/utils/Makefile.am3
-rw-r--r--lib/utils/run_event.c168
-rw-r--r--src/daemon/Makefile.am19
-rw-r--r--src/daemon/MiddleWare.cpp160
-rw-r--r--src/daemon/abrt-handle-crashdump.c78
-rw-r--r--src/daemon/abrt_action.conf2
8 files changed, 294 insertions, 149 deletions
diff --git a/abrt.spec b/abrt.spec
index dabc0ed3..ecaa96f6 100644
--- a/abrt.spec
+++ b/abrt.spec
@@ -350,6 +350,7 @@ fi
%{_sbindir}/abrtd
%{_sbindir}/abrt-server
%{_bindir}/abrt-handle-upload
+%{_bindir}/abrt-handle-crashdump
%config(noreplace) %{_sysconfdir}/%{name}/abrt.conf
%config(noreplace) %{_sysconfdir}/%{name}/abrt_action.conf
%config(noreplace) %{_sysconfdir}/%{name}/gpg_keys
diff --git a/inc/abrtlib.h b/inc/abrtlib.h
index f9796ada..52896fe9 100644
--- a/inc/abrtlib.h
+++ b/inc/abrtlib.h
@@ -213,6 +213,18 @@ char* get_cmdline(pid_t pid);
/* Returns 1 if abrtd daemon is running, 0 otherwise. */
int daemon_is_ok();
+struct run_event_state {
+ int (*post_run_callback)(const char *dump_dir_name, void *param);
+ void *post_run_param;
+ char* (*logging_callback)(char *log_line, void *param);
+ void *logging_param;
+};
+static inline struct run_event_state *new_run_event_state()
+ { return (struct run_event_state*)xzalloc(sizeof(struct run_event_state)); }
+static inline void free_run_event_state(struct run_event_state *state)
+ { free(state); }
+int run_event(struct run_event_state *state, const char *dump_dir_name, const char *event);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/utils/Makefile.am b/lib/utils/Makefile.am
index e4735cde..129feeb5 100644
--- a/lib/utils/Makefile.am
+++ b/lib/utils/Makefile.am
@@ -30,10 +30,11 @@ libABRTUtils_la_SOURCES = \
stringops.cpp \
dirsize.c \
dump_dir.c \
+ strbuf.c strbuf.h \
abrt_dbus.c abrt_dbus.h \
CrashTypes.cpp \
ABRTException.cpp \
- strbuf.c strbuf.h \
+ run_event.c \
abrt_packages.c abrt_packages.h \
hooklib.c hooklib.h \
database.c \
diff --git a/lib/utils/run_event.c b/lib/utils/run_event.c
new file mode 100644
index 00000000..9c4584a8
--- /dev/null
+++ b/lib/utils/run_event.c
@@ -0,0 +1,168 @@
+/*
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@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"
+
+int run_event(struct run_event_state *state,
+ const char *dump_dir_name,
+ const char *event
+) {
+ FILE *conffile = fopen(CONF_DIR"/abrt_action.conf", "r");
+ if (!conffile)
+ {
+ error_msg("Can't open '%s'", CONF_DIR"/abrt_action.conf");
+ return 1;
+ }
+ close_on_exec_on(fileno(conffile));
+
+ /* Export some useful environment variables for children */
+ /* Just exporting dump_dir_name isn't always ok: it can be "."
+ * and some children want to cd to other directory but still
+ * be able to find dump directory by using $DUMP_DIR...
+ */
+ char *full_name = realpath(dump_dir_name, NULL);
+ setenv("DUMP_DIR", (full_name ? full_name : dump_dir_name), 1);
+ free(full_name);
+ /*setenv("EVENT", event, 1); - is this useful for children to know? */
+
+ /* Read, match, and execute lines from abrt_action.conf */
+ int retval = 0;
+ struct dump_dir *dd = NULL;
+ char *line;
+ while ((line = xmalloc_fgetline(conffile)) != NULL)
+ {
+ /* Line has form: [VAR=VAL]... PROG [ARGS] */
+ char *p = skip_whitespace(line);
+ if (*p == '\0' || *p == '#')
+ goto next_line; /* empty or comment line, skip */
+
+ VERB3 log("line '%s'", p);
+
+ while (1) /* word loop */
+ {
+ /* If there is no '=' in this word... */
+ char *next_word = skip_whitespace(skip_non_whitespace(p));
+ char *needed_val = strchr(p, '=');
+ if (!needed_val || needed_val >= next_word)
+ break; /* ...we found the start of a command */
+
+ /* Current word has VAR=VAL form. needed_val => VAL */
+ *needed_val++ = '\0';
+
+ const char *real_val;
+ char *malloced_val = NULL;
+
+ /* Is it EVENT? */
+ if (strcmp(p, "EVENT") == 0)
+ real_val = event;
+ else
+ {
+ /* Get this name from dump dir */
+ if (!dd)
+ {
+ dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ goto stop; /* error (note: dd_opendir logged error msg) */
+ }
+ real_val = malloced_val = dd_load_text(dd, p);
+ }
+
+ /* Does VAL match? */
+ unsigned len = strlen(real_val);
+ bool match = (strncmp(real_val, needed_val, len) == 0
+ && (needed_val[len] == ' ' || needed_val[len] == '\t'));
+ if (!match)
+ {
+ VERB3 log("var '%s': '%s'!='%s', skipping line", p, real_val, needed_val);
+ free(malloced_val);
+ goto next_line; /* no */
+ }
+ free(malloced_val);
+
+ /* Go to next word */
+ p = next_word;
+ } /* end of word loop */
+
+ dd_close(dd);
+ dd = NULL;
+
+ /* We found matching line, execute its command(s) in shell */
+ {
+ VERB1 log("Executing '%s'", p);
+
+ /* /bin/sh -c 'cmd [args]' NULL */
+ char *argv[4];
+ char **pp = argv;
+ *pp++ = (char*)"/bin/sh";
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)p;
+ *pp = NULL;
+ int pipefds[2];
+ pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT_NUL + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
+ argv,
+ pipefds,
+ /* unsetenv_vec: */ NULL,
+ /* dir: */ dump_dir_name,
+ /* uid(unused): */ 0
+ );
+ free(line);
+ line = NULL;
+
+ /* Consume log from stdout */
+ FILE *fp = fdopen(pipefds[0], "r");
+ if (!fp)
+ die_out_of_memory();
+ char *buf;
+ while ((buf = xmalloc_fgetline(fp)) != NULL)
+ {
+ if (state->logging_callback)
+ buf = state->logging_callback(buf, state->logging_param);
+ free(buf);
+ }
+ fclose(fp); /* Got EOF, close. This also closes pipefds[0] */
+ /* Wait for child to actually exit, collect status */
+ int status;
+ waitpid(pid, &status, 0);
+
+ if (status != 0)
+ {
+ retval = WEXITSTATUS(status);
+ if (WIFSIGNALED(status))
+ retval = WTERMSIG(status) + 128;
+ break;
+ }
+ }
+
+ if (state->post_run_callback)
+ {
+ retval = state->post_run_callback(dump_dir_name, state->post_run_param);
+ if (retval != 0)
+ break;
+ }
+
+ next_line:
+ free(line);
+ } /* end of line loop */
+
+ stop:
+ free(line);
+ dd_close(dd);
+ fclose(conffile);
+
+ return retval;
+}
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 14cb909c..b9be0a62 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -11,6 +11,7 @@ sbin_PROGRAMS = abrtd \
abrt-action-save-package-data
bin_PROGRAMS = \
+ abrt-handle-crashdump \
abrt-action-bugzilla \
abrt-action-rhtsupport \
abrt-action-kerneloops \
@@ -159,6 +160,24 @@ abrt_action_save_package_data_LDADD = \
../../lib/utils/libABRTdUtils.la \
../../lib/utils/libABRTUtils.la
+abrt_handle_crashdump_SOURCES = \
+ abrt-handle-crashdump.c
+abrt_handle_crashdump_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_handle_crashdump_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
abrt_action_bugzilla_SOURCES = \
abrt-action-bugzilla.cpp
abrt_action_bugzilla_CPPFLAGS = \
diff --git a/src/daemon/MiddleWare.cpp b/src/daemon/MiddleWare.cpp
index f4388a6b..43ac9637 100644
--- a/src/daemon/MiddleWare.cpp
+++ b/src/daemon/MiddleWare.cpp
@@ -616,152 +616,6 @@ static void RunAnalyzerActions(const char *pAnalyzer, const char *pPackageName,
}
}
-int run_event(char **last_log_msg_pp,
- const char *dump_dir_name,
- const char *event,
- int (*callback)(const char *dump_dir_name, void *param),
- void *param
-) {
- FILE *conffile = fopen(CONF_DIR"/abrt_action.conf", "r");
- if (!conffile)
- {
- error_msg("Can't open '%s'", CONF_DIR"/abrt_action.conf");
- return 1;
- }
- close_on_exec_on(fileno(conffile));
-
- /* Read, match, and execute lines from abrt_action.conf */
- int retval = 0;
- struct dump_dir *dd = NULL;
- char *line;
- while ((line = xmalloc_fgetline(conffile)) != NULL)
- {
- /* Line has form: [VAR=VAL]... PROG [ARGS] */
- char *p = skip_whitespace(line);
- if (*p == '\0' || *p == '#')
- goto next_line; /* empty or comment line, skip */
-
- VERB3 log("line '%s'", p);
-
- while (1) /* word loop */
- {
- /* If there is no '=' in this word... */
- char *next_word = skip_whitespace(skip_non_whitespace(p));
- char *needed_val = strchr(p, '=');
- if (!needed_val || needed_val >= next_word)
- break; /* ...we found the start of a command */
-
- /* Current word has VAR=VAL form. needed_val => VAL */
- *needed_val++ = '\0';
-
- const char *real_val;
- char *malloced_val = NULL;
-
- /* Is it EVENT? */
- if (strcmp(p, "EVENT") == 0)
- real_val = event;
- else
- {
- /* Get this name from dump dir */
- if (!dd)
- {
- dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd) goto stop;
- }
- real_val = malloced_val = dd_load_text(dd, p);
- }
-
- /* Does VAL match? */
- unsigned len = strlen(real_val);
- bool match = (strncmp(real_val, needed_val, len) == 0
- && (needed_val[len] == ' ' || needed_val[len] == '\t'));
- if (!match)
- {
- VERB3 log("var '%s': '%s'!='%s', skipping line", p, real_val, needed_val);
- free(malloced_val);
- goto next_line; /* no */
- }
- free(malloced_val);
-
- /* Go to next word */
- p = next_word;
- } /* end of word loop */
-
- dd_close(dd);
- dd = NULL;
-
- /* We found matching line, execute its command(s) in shell */
- {
- VERB1 log("Executing '%s'", p);
-
- /* /bin/sh -c 'cmd [args]' NULL */
- char *argv[4];
- char **pp = argv;
- *pp++ = (char*)"/bin/sh";
- *pp++ = (char*)"-c";
- *pp++ = (char*)p;
- *pp = NULL;
- int pipefds[2];
- pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT_NUL + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
- argv,
- pipefds,
- /* unsetenv_vec: */ NULL,
- /* dir: */ dump_dir_name,
- /* uid(unused): */ 0
- );
- free(line);
- line = NULL;
-
- /* Consume log from stdout */
- FILE *fp = fdopen(pipefds[0], "r");
- if (!fp)
- die_out_of_memory();
- char *buf;
- while ((buf = xmalloc_fgetline(fp)) != NULL)
- {
- VERB1 log("%s", buf);
- update_client("%s", buf);
-
- char *to_free = buf;
- if (last_log_msg_pp)
- {
- to_free = *last_log_msg_pp;
- *last_log_msg_pp = buf;
- }
- free(to_free);
- }
- fclose(fp); /* Got EOF, close. This also closes pipefds[0] */
- /* Wait for child to actually exit, collect status */
- int status;
- waitpid(pid, &status, 0);
-
- if (status != 0)
- {
- retval = WEXITSTATUS(status);
- if (WIFSIGNALED(status))
- retval = WTERMSIG(status) + 128;
- break;
- }
- }
-
- if (callback)
- {
- retval = callback(dump_dir_name, param);
- if (retval != 0)
- break;
- }
-
- next_line:
- free(line);
- } /* end of line loop */
-
- stop:
- dd_close(dd);
- fclose(conffile);
-
- return retval;
-}
-
/**
* Save a debugdump into database. If saving is
* successful, then crash info is filled. Otherwise the crash info is
@@ -851,6 +705,13 @@ static int is_crash_id_in_db(const char *dump_dir_name, void *param)
return 1;
}
+static char *do_log(char *log_line, void *param)
+{
+ VERB1 log("%s", log_line);
+ //update_client("%s", log_line);
+ return log_line;
+}
+
mw_result_t SaveDebugDump(const char *dump_dir_name,
map_crash_data_t& pCrashData)
{
@@ -870,7 +731,12 @@ mw_result_t SaveDebugDump(const char *dump_dir_name,
res = MW_ERROR;
- int r = run_event(NULL, dump_dir_name, "post-create", &is_crash_id_in_db, &state);
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->post_run_callback = is_crash_id_in_db;
+ run_state->post_run_param = &state;
+ run_state->logging_callback = do_log;
+ int r = run_event(run_state, dump_dir_name, "post-create");
+ free_run_event_state(run_state);
/* Is crash id in db? (In this case, is_crash_id_in_db() should have
* aborted "post-create" event processing as soon as it saw uuid
diff --git a/src/daemon/abrt-handle-crashdump.c b/src/daemon/abrt-handle-crashdump.c
new file mode 100644
index 00000000..3b757c82
--- /dev/null
+++ b/src/daemon/abrt-handle-crashdump.c
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 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 "parse_options.h"
+//#include "crash_types.h"
+
+#define PROGNAME "abrt-handle-crashdump"
+
+static const char *dump_dir_name = ".";
+//static const char *conf_filename = CONF_DIR"/abrt_action.conf";
+static const char *event;
+
+static char *do_log(char *log_line, void *param)
+{
+ log("%s", log_line);
+ return log_line;
+}
+
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
+ const char *program_usage = _(
+ PROGNAME" [-vs]" /*" [-c CONFFILE]"*/ " -d DIR -e EVENT\n"
+ "\n"
+ "Handle crash dump according to rules in abrt_action.conf");
+ enum {
+ OPT_v = 1 << 0,
+ OPT_s = 1 << 1,
+ OPT_d = 1 << 2,
+ OPT_e = 1 << 3,
+// OPT_c = 1 << 4,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_BOOL( 's', NULL, NULL , _("Log to syslog" )),
+ OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Crash dump directory")),
+ OPT_STRING('e', NULL, &event , "EVENT" , _("Event" )),
+// OPT_STRING('c', NULL, &conf_filename, "CONFFILE", _("Configuration file" )),
+ OPT_END()
+ };
+
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage);
+ if (!(opts & OPT_e))
+ parse_usage_and_die(program_usage, program_options);
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+ if (opts & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->logging_callback = do_log;
+ int r = run_event(run_state, dump_dir_name, event);
+ free_run_event_state(run_state);
+
+ return r;
+}
diff --git a/src/daemon/abrt_action.conf b/src/daemon/abrt_action.conf
index 5d403177..6b4bd50a 100644
--- a/src/daemon/abrt_action.conf
+++ b/src/daemon/abrt_action.conf
@@ -31,7 +31,7 @@ EVENT=post-create analyzer=CCpp abrt-action-analyze-c
EVENT=post-create analyzer=python abrt-action-analyze-python
EVENT=post-create analyzer=oops abrt-action-analyze-oops
-EVENT=analyze analyzer=CCpp abrt-action-install-debuginfo ./coredump /var/run/abrt/$$-$RANDOM /var/cache/abrt-di
+EVENT=analyze analyzer=CCpp abrt-action-install-debuginfo "$DUMP_DIR/coredump" "/var/run/abrt/$$-$RANDOM" /var/cache/abrt-di
EVENT=analyze analyzer=CCpp abrt-action-generate-backtrace
EVENT=report analyzer=oops abrt-action-kerneloops