Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
abrt.spec.in | 1 +
src/daemon/Makefile.am | 15 +++
src/daemon/abrt-handle-event.c | 176 ++++++++++++++++++++++++++++++++++
src/daemon/abrtd.c | 207 +++++++++++-----------------------------
4 files changed, 248 insertions(+), 151 deletions(-)
create mode 100644 src/daemon/abrt-handle-event.c
diff --git a/abrt.spec.in b/abrt.spec.in
index e605dea..5b4f23f 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -372,6 +372,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%endif
%{_sbindir}/abrtd
%{_sbindir}/abrt-server
+%{_libexecdir}/abrt-handle-event
%{_bindir}/abrt-handle-upload
%{_bindir}/abrt-action-save-package-data
%config(noreplace) %{_sysconfdir}/%{name}/abrt.conf
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 9770e56..faaccdd 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -13,6 +13,8 @@ sbin_PROGRAMS = \
abrtd \
abrt-server
+libexec_PROGRAMS = abrt-handle-event
+
abrtd_SOURCES = \
CommLayerServerDBus.h CommLayerServerDBus.c \
comm_layer_inner.h comm_layer_inner.c \
@@ -57,6 +59,19 @@ abrt_server_LDADD = \
../lib/libabrt.la \
$(LIBREPORT_LIBS)
+abrt_handle_event_SOURCES = \
+ abrt-handle-event.c
+abrt_handle_event_CPPFLAGS = \
+ -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ $(GLIB_CFLAGS) \
+ $(LIBREPORT_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Wwrite-strings -Werror
+abrt_handle_event_LDADD = \
+ ../lib/libabrt.la \
+ $(LIBREPORT_LIBS)
+
abrt_action_save_package_data_SOURCES = \
rpm.h rpm.c \
abrt-action-save-package-data.c
diff --git a/src/daemon/abrt-handle-event.c b/src/daemon/abrt-handle-event.c
new file mode 100644
index 0000000..809e0e9
--- /dev/null
+++ b/src/daemon/abrt-handle-event.c
@@ -0,0 +1,176 @@
+/*
+ Copyright (C) 2011 ABRT Team
+ Copyright (C) 2011 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 "run_event.h"
+
+static char *uid = NULL;
+static char *uuid = NULL;
+static char *crash_dump_dup_name = NULL;
+
+static int is_crash_a_dup(const char *dump_dir_name, void *param)
+{
+ if (uuid)
+ return 0; /* we already checked it, don't do it again */
+
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ return 0; /* wtf? (error, but will be handled elsewhere later) */
+ uuid = dd_load_text_ext(dd, FILENAME_UUID,
+ DD_FAIL_QUIETLY_ENOENT + DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ );
+ dd_close(dd);
+ if (!uuid)
+ return 0; /* no uuid (yet), "run_event, please continue iterating" */
+
+ /* Scan crash dumps looking for a dup */
+//TODO: explain why this is safe wrt concurrent runs
+ DIR *dir = opendir(g_settings_dump_location);
+ if (dir != NULL)
+ {
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
+ {
+ if (dot_or_dotdot(dent->d_name))
+ continue; /* skip "." and ".." */
+
+ int different;
+ char *dd_uid, *dd_uuid;
+ char *dump_dir_name2 = concat_path_file(g_settings_dump_location, dent->d_name);
+
+ if (strcmp(dump_dir_name, dump_dir_name2) == 0)
+ goto next; /* we are never a dup of ourself */
+
+ dd = dd_opendir(dump_dir_name2, /*flags:*/ DD_FAIL_QUIETLY_ENOENT);
+ if (!dd)
+ goto next;
+ dd_uid = dd_load_text(dd, FILENAME_UID);
+ dd_uuid = dd_load_text(dd, FILENAME_UUID);
+ dd_close(dd);
+ different = strcmp(uid, dd_uid) || strcmp(uuid, dd_uuid);
+ free(dd_uid);
+ free(dd_uuid);
+ if (different)
+ goto next;
+
+ crash_dump_dup_name = dump_dir_name2;
+ /* "run_event, please stop iterating": */
+ return 1;
+
+ next:
+ free(dump_dir_name2);
+ }
+ closedir(dir);
+ }
+
+ /* No dup found */
+ return 0; /* "run_event, please continue iterating" */
+}
+
+static char *do_log(char *log_line, void *param)
+{
+ /* We pipe output of post-create events to our log (which usually
+ * includes syslog). Otherwise, errors on post-create result in
+ * "Corrupted or bad dump DIR, deleting" without adequate explanation why.
+ */
+ log("%s", log_line);
+ return log_line;
+}
+
+int main(int argc, const char **argv)
+{
+ abrt_init((char **)argv);
+
+ const char *program_usage_string = _(
+ "\b [-v] -e|--event EVENT DUMP_DIR [DUMP_DIR]..."
+ );
+
+ char *event_name = NULL;
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_GROUP(""),
+ OPT_STRING('e', "event" , &event_name, "EVENT", _("Run EVENT on DUMP_DIR")),
+ OPT_END()
+ };
+
+ parse_opts(argc, (char **)argv, program_options, program_usage_string);
+ if (!argv[optind] || !event_name)
+ show_usage_and_die(program_usage_string, program_options);
+
+ load_abrt_conf();
+
+ const char *dump_dir_name = NULL;
+ while (argv[optind])
+ {
+ dump_dir_name = argv[optind++];
+
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ return 1;
+
+ uid = dd_load_text(dd, FILENAME_UID);
+ dd_close(dd);
+
+ struct run_event_state *run_state = new_run_event_state();
+ if (strcmp(event_name, "post-create") == 0)
+ run_state->post_run_callback = is_crash_a_dup;
+ run_state->logging_callback = do_log;
+ int r = run_event_on_dir_name(run_state, dump_dir_name, event_name);
+ if (r == 0 && run_state->children_count == 0)
+ error_msg_and_die("No actions are found for event '%s'", event_name);
+ free_run_event_state(run_state);
+
+//TODO: consider this case:
+// new dump is created, post-create detects that it is a dup,
+// but then load_crash_info(dup_name) *FAILS*.
+// In this case, we later delete damaged dup_name (right?)
+// but new dump never gets its FILENAME_COUNT set!
+
+ /* Is crash a dup? (In this case, is_crash_a_dup() should have
+ * aborted "post-create" event processing as soon as it saw uuid
+ * and determined that there is another crash with same uuid.
+ * In this case it sets state.crash_dump_dup_name)
+ */
+ if (!crash_dump_dup_name)
+ {
+ /* No. Was there error on one of processing steps in run_event? */
+ if (r != 0)
+ return r; /* yes */
+
+ /* Was uuid created after all? (In this case, is_crash_a_dup()
+ * should have fetched it and created uuid)
+ */
+ if (!uuid)
+ {
+ /* no */
+ fprintf(stdout, "Dump directory '%s' has no UUID element", dump_dir_name);
+ return 1;
+ }
+ }
+ else
+ {
+ fprintf(stdout, "DUP_OF_DIR: %s", crash_dump_dup_name);
+ free(crash_dump_dup_name);
+ return 1;
+ }
+ }
+
+ /* exit 0 means, that there is no duplicate of dump-dir*/
+ return 0;
+}
diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
index 5d93426..1badfe1 100644
--- a/src/daemon/abrtd.c
+++ b/src/daemon/abrtd.c
@@ -245,103 +245,6 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint
/* Inotify handler */
-/* helpers first */
-
-struct logging_state {
- char *last_line;
-};
-
-static char *do_log_and_save_line(char *log_line, void *param)
-{
- struct logging_state *l_state = (struct logging_state *)param;
-
- VERB1 log("%s", log_line);
- update_client("%s", log_line);
- free(l_state->last_line);
- l_state->last_line = log_line;
- return NULL;
-}
-
-/* We need to share some data between LoadDebugDump and is_crash_a_dup: */
-struct cdump_state {
- char *uid; /* filled by LoadDebugDump */
- char *uuid; /* filled by is_crash_a_dup */
- char *crash_dump_dup_name; /* filled by is_crash_a_dup */
-};
-
-static int is_crash_a_dup(const char *dump_dir_name, void *param)
-{
- struct cdump_state *state = (struct cdump_state *)param;
-
- if (state->uuid)
- return 0; /* we already checked it, don't do it again */
-
- struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd)
- return 0; /* wtf? (error, but will be handled elsewhere later) */
- state->uuid = dd_load_text_ext(dd, FILENAME_UUID,
- DD_FAIL_QUIETLY_ENOENT + DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
- );
- dd_close(dd);
- if (!state->uuid)
- {
- return 0; /* no uuid (yet), "run_event, please continue iterating" */
- }
-
- /* Scan crash dumps looking for a dup */
-//TODO: explain why this is safe wrt concurrent runs
- DIR *dir = opendir(g_settings_dump_location);
- if (dir != NULL)
- {
- struct dirent *dent;
- while ((dent = readdir(dir)) != NULL)
- {
- if (dot_or_dotdot(dent->d_name))
- continue; /* skip "." and ".." */
-
- int different;
- char *uid, *uuid;
- char *dump_dir_name2 = concat_path_file(g_settings_dump_location, dent->d_name);
-
- if (strcmp(dump_dir_name, dump_dir_name2) == 0)
- goto next; /* we are never a dup of ourself */
-
- dd = dd_opendir(dump_dir_name2, /*flags:*/ DD_FAIL_QUIETLY_ENOENT);
- if (!dd)
- goto next;
- uid = dd_load_text(dd, FILENAME_UID);
- uuid = dd_load_text(dd, FILENAME_UUID);
- dd_close(dd);
- different = strcmp(state->uid, uid) || strcmp(state->uuid, uuid);
- free(uid);
- free(uuid);
- if (different)
- goto next;
-
- state->crash_dump_dup_name = dump_dir_name2;
- /* "run_event, please stop iterating": */
- return 1;
-
- next:
- free(dump_dir_name2);
- }
- closedir(dir);
- }
-
- /* No dup found */
- return 0; /* "run_event, please continue iterating" */
-}
-
-static char *do_log(char *log_line, void *param)
-{
- /* We pipe output of post-create events to our log (which usually
- * includes syslog). Otherwise, errors on post-create result in
- * "Corrupted or bad dump DIR, deleting" without adequate explanation why.
- */
- log("%s", log_line);
- return log_line;
-}
-
static problem_data_t *load_crash_info(const char *dump_dir_name)
{
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
@@ -365,60 +268,66 @@ typedef enum {
static mw_result_t LoadDebugDump(const char *dump_dir_name, problem_data_t **problem_data)
{
- mw_result_t res;
+ mw_result_t res = MW_ERROR;
- struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd)
- return MW_ERROR;
- struct cdump_state state;
- state.uid = dd_load_text(dd, FILENAME_UID);
- state.uuid = NULL;
- state.crash_dump_dup_name = NULL;
- char *analyzer = dd_load_text(dd, FILENAME_ANALYZER);
- dd_close(dd);
+ char *args[5];
+ args[0] = (char *) "/usr/libexec/abrt-handle-event";
+ args[1] = (char *) "-e";
+ args[2] = (char *) "post-create";
+ args[3] = (char *) dump_dir_name;
+ args[4] = NULL;
- res = MW_ERROR;
-
- /* Run post-create event handler(s) */
- struct run_event_state *run_state = new_run_event_state();
- run_state->post_run_callback = is_crash_a_dup;
- run_state->post_run_param = &state;
- run_state->logging_callback = do_log;
- int r = run_event_on_dir_name(run_state, dump_dir_name, "post-create");
- free_run_event_state(run_state);
-
-//TODO: consider this case:
-// new dump is created, post-create detects that it is a dup,
-// but then load_crash_info(dup_name) *FAILS*.
-// In this case, we later delete damaged dup_name (right?)
-// but new dump never gets its FILENAME_COUNT set!
-
- /* Is crash a dup? (In this case, is_crash_a_dup() should have
- * aborted "post-create" event processing as soon as it saw uuid
- * and determined that there is another crash with same uuid.
- * In this case it sets state.crash_dump_dup_name)
- */
- if (!state.crash_dump_dup_name)
+ int pipeout[2];
+ int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_QUIET;
+ VERB1 flags &= ~EXECFLG_QUIET;
+
+ pid_t child = fork_execv_on_steroids(flags, args, pipeout,
+ /*env_vec:*/ NULL, /*dir:*/ NULL, 0);
+
+ struct strbuf *buf_out = strbuf_new();
+ while (1)
{
- /* No. Was there error on one of processing steps in run_event? */
- if (r != 0)
- goto ret; /* yes */
-
- /* Was uuid created after all? (In this case, is_crash_a_dup()
- * should have fetched it and created state.uuid)
- */
- if (!state.uuid)
- {
- /* no */
- log("Dump directory '%s' has no UUID element", dump_dir_name);
- goto ret;
- }
+ 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);
}
- else
+ close(pipeout[0]);
+
+ /* Prevent having zombie child process */
+ int status;
+ waitpid(child, &status, 0);
+ status = WEXITSTATUS(status);
+
+ /* exit 0 means, this is a good, non-dup dir */
+ if (status != 0)
{
- dump_dir_name = state.crash_dump_dup_name;
- }
+ /* exit != 0 and empty buffer means error processing in run_event */
+ if (buf_out->len == 0)
+ {
+ strbuf_free(buf_out);
+ return MW_ERROR;
+ }
+
+ if (buf_out->buf[buf_out->len - 1] == '\n')
+ buf_out->buf[buf_out->len - 1] = '\0';
+
+ char *last_line = strrchr(buf_out->buf, '\n');
+ if (!last_line)
+ last_line = buf_out->buf;
+ if (strncmp("DUP_OF_DIR: ", last_line, strlen("DUP_OF_DIR")) == 0)
+ {
+ dump_dir_name = last_line + strlen("DUP_OF_DIR: ");
+ }
+ else /* no DUP_OF_DIR */
+ {
+ strbuf_free(buf_out);
+ return MW_ERROR;
+ }
+ }
/* Loads problem_data (from the *first debugdump dir* if this one is a dup)
* Returns:
* MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup)
@@ -426,7 +335,7 @@ static mw_result_t LoadDebugDump(const char *dump_dir_name, problem_data_t **pro
* else: an error code
*/
{
- dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
{
res = MW_ERROR;
@@ -458,11 +367,7 @@ static mw_result_t LoadDebugDump(const char *dump_dir_name, problem_data_t **pro
}
ret:
- free(state.uuid);
- free(state.uid);
- free(state.crash_dump_dup_name);
- free(analyzer);
-
+ strbuf_free(buf_out);
return res;
}
--
1.7.6.345.g5c2f8