summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2011-03-09 16:49:41 +0100
committerKarel Klic <kklic@redhat.com>2011-03-09 16:58:28 +0100
commit43d84e3f11e46b7c9a042ff338024dfc41bb4f22 (patch)
tree783b1122556f15345290ff8b1623812b6e864827
parent6ec12db137f2d0fe18f059fcef2390512d0b2c3f (diff)
parentc2f2a9f310e7b3bc3725cc8dc7e805fd38c7fbbd (diff)
Merge branch 'master' of ssh://git.fedorahosted.org/git/abrt
-rw-r--r--.gitignore4
-rw-r--r--abrt.spec1
-rw-r--r--configure.ac2
-rw-r--r--doc/abrt-retrace-server.texi4
-rw-r--r--src/applet/Makefile.am4
-rw-r--r--src/btparser/Makefile.am2
-rw-r--r--src/cli/Makefile.am2
-rw-r--r--src/cli/report.cpp10
-rw-r--r--src/daemon/Daemon.cpp2
-rw-r--r--src/daemon/Makefile.am8
-rw-r--r--src/daemon/MiddleWare.cpp10
-rw-r--r--src/gui-gtk/Makefile.am5
-rw-r--r--src/gui-gtk/abrt-gtk.c137
-rw-r--r--src/gui-gtk/event_config_dialog.c269
-rw-r--r--src/gui-gtk/event_config_dialog.h1
-rw-r--r--src/gui-wizard-gtk/Makefile.am2
-rw-r--r--src/gui-wizard-gtk/wizard.c127
-rw-r--r--src/hooks/Makefile.am3
-rw-r--r--src/hooks/abrt-hook-ccpp.c4
-rw-r--r--src/include/Makefile.am3
-rw-r--r--src/include/abrtlib.h10
-rw-r--r--src/include/report/crash_data.h4
-rw-r--r--src/include/report/event_config.h82
-rw-r--r--src/include/xfuncs.h13
-rw-r--r--src/lib/Makefile.am23
-rw-r--r--src/lib/crash_data.c13
-rw-r--r--src/lib/event_config.c135
-rw-r--r--src/lib/event_xml_parser.c203
-rw-r--r--src/lib/load_plugin_settings.c52
-rw-r--r--src/lib/run_event.c46
-rw-r--r--src/lib/spawn.c12
-rw-r--r--src/lib/xfuncs.c14
-rw-r--r--src/plugins/Bugzilla.xml30
-rw-r--r--src/plugins/Makefile.am31
-rw-r--r--src/plugins/abrt-action-analyze-c.c2
-rw-r--r--src/plugins/abrt-action-generate-backtrace.c11
-rw-r--r--src/plugins/abrt-action-mailx.c2
-rw-r--r--src/report-python/Makefile.am2
-rw-r--r--src/report-python/dump_dir.c2
-rw-r--r--src/report-python/reportmodule.c2
-rw-r--r--src/report-python/run_event.c8
-rw-r--r--src/retrace/retrace.py45
-rwxr-xr-xsrc/retrace/worker.py71
43 files changed, 1211 insertions, 202 deletions
diff --git a/.gitignore b/.gitignore
index 0bf1d396..727bd413 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ src/plugins/abrt-action-upload
src/plugins/abrt-action-mailx
src/plugins/abrt-action-print
src/plugins/abrt-dump-oops
+src/plugins/abrt-action-install-debuginfo
+src/plugins/abrt-retrace-client
src/daemon/abrt-action-save-package-data
src/daemon/abrt-handle-crashdump
@@ -39,6 +41,8 @@ src/gui/abrt.desktop
src/gui-wizard-gtk/bug-reporting-wizard
+src/retrace/abrt-retrace-worker
+
# cscope files
cscope.*
ncscope.*
diff --git a/abrt.spec b/abrt.spec
index 8eeb1db0..76285892 100644
--- a/abrt.spec
+++ b/abrt.spec
@@ -510,6 +510,7 @@ fi
%files plugin-bugzilla
%defattr(-,root,root,-)
%config(noreplace) %{_sysconfdir}/%{name}/plugins/Bugzilla.conf
+%{_sysconfdir}/%{name}/events/Bugzilla.xml
%{_libdir}/%{name}/Bugzilla.glade
%{_mandir}/man7/abrt-Bugzilla.7.gz
%{_bindir}/abrt-action-bugzilla
diff --git a/configure.ac b/configure.ac
index b6999daf..ccd25f62 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,6 +70,7 @@ AC_CHECK_HEADER([sys/inotify.h], [],
CONF_DIR='${sysconfdir}/${PACKAGE_NAME}'
VAR_RUN='${localstatedir}/run'
PLUGINS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/plugins'
+EVENTS_DIR='${sysconfdir}/${PACKAGE_NAME}/events'
EVENTS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/events.d'
PLUGINS_LIB_DIR='${libdir}/${PACKAGE_NAME}'
ENABLE_SOCKET_OR_DBUS='-DENABLE_DBUS=1'
@@ -104,6 +105,7 @@ AC_SUBST(CONF_DIR)
AC_SUBST(VAR_RUN)
AC_SUBST(PLUGINS_CONF_DIR)
AC_SUBST(EVENTS_CONF_DIR)
+AC_SUBST(EVENTS_DIR)
AC_SUBST(PLUGINS_LIB_DIR)
AC_SUBST(DEBUG_DUMPS_DIR)
AC_SUBST(DEBUG_INFO_DIR)
diff --git a/doc/abrt-retrace-server.texi b/doc/abrt-retrace-server.texi
index 43f05627..75c78814 100644
--- a/doc/abrt-retrace-server.texi
+++ b/doc/abrt-retrace-server.texi
@@ -1,8 +1,8 @@
\input texinfo
-@c retrace-server.texi - Retrace Server Documentation
+@c abrt-retrace-server.texi - Retrace Server Documentation
@c
@c .texi extension is recommended in GNU Automake manual
-@setfilename retrace-server.info
+@setfilename abrt-retrace-server.info
@include version.texi
@settitle Retrace server for ABRT @value{VERSION} Manual
diff --git a/src/applet/Makefile.am b/src/applet/Makefile.am
index cd4a643f..4756f312 100644
--- a/src/applet/Makefile.am
+++ b/src/applet/Makefile.am
@@ -17,7 +17,7 @@ abrt_applet_CPPFLAGS = \
$(GTK_CFLAGS) \
$(DBUS_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
# -I/usr/include/glib-2.0
# -I/usr/lib/glib-2.0/include
# $(LIBNOTIFY_CFLAGS)
@@ -37,7 +37,7 @@ abrt_applet_LDADD = \
# -I$(srcdir)/../include/report -I$(srcdir)/../include \
# $(GLIB_CFLAGS) \
# -D_GNU_SOURCE \
-# -Wall -Werror
+# -Wall -Wwrite-strings -Werror
#test_report_LDADD = \
# ../lib/libreport.la
diff --git a/src/btparser/Makefile.am b/src/btparser/Makefile.am
index 9f64f826..030d94da 100644
--- a/src/btparser/Makefile.am
+++ b/src/btparser/Makefile.am
@@ -13,7 +13,7 @@ libbtparser_la_SOURCES = \
normalize_xorg.c \
thread.h thread.c \
utils.h utils.c
-libbtparser_la_CFLAGS = -Wall -Werror -D_GNU_SOURCE -I../lib
+libbtparser_la_CFLAGS = -Wall -Wwrite-strings -Werror -D_GNU_SOURCE -I../lib
libbtparser_la_LDFLAGS = -version-info 1:1:0
libbtparser_la_LIBADD = ../lib/libreport.la
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
index 0a5c6e1a..345598d0 100644
--- a/src/cli/Makefile.am
+++ b/src/cli/Makefile.am
@@ -13,7 +13,7 @@ abrt_cli_CPPFLAGS = \
$(ENABLE_SOCKET_OR_DBUS) \
$(DBUS_CFLAGS) $(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
# $(GTK_CFLAGS)
abrt_cli_LDADD = \
../lib/libreport.la \
diff --git a/src/cli/report.cpp b/src/cli/report.cpp
index ff18d19c..ebbe8e0b 100644
--- a/src/cli/report.cpp
+++ b/src/cli/report.cpp
@@ -649,14 +649,8 @@ static int run_events(const char *dump_dir_name,
for (GList *li = env_list; li; li = g_list_next(li))
{
char *s = (char*)li->data;
- /* Need to make a copy: just cutting s at '=' and unsetenv'ing
- * the result would be a bug! s _itself_ is in environment now,
- * we must not modify it there!
- */
- char *name = xstrndup(s, strchrnul(s, '=') - s);
- VERB3 log("Unexporting '%s'", name);
- unsetenv(name);
- free(name);
+ VERB3 log("Unexporting '%s'", s);
+ safe_unsetenv(s);
free(s);
}
g_list_free(env_list);
diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp
index f791fb38..2d2c85ed 100644
--- a/src/daemon/Daemon.cpp
+++ b/src/daemon/Daemon.cpp
@@ -719,7 +719,7 @@ int main(int argc, char** argv)
log_scanner_pid = fork_execv_on_steroids(EXECFLG_INPUT_NUL,
(char**)scanner_argv,
/*pipefds:*/ NULL,
- /*unsetenv_vec:*/ NULL,
+ /*env_vec:*/ NULL,
/*dir:*/ NULL,
/*uid:*/ 0);
VERB1 log("Started log scanner, pid:%d", (int)log_scanner_pid);
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 6fe73065..4c48ceb9 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -30,7 +30,7 @@ abrtd_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(ENABLE_SOCKET_OR_DBUS) \
-D_GNU_SOURCE \
- -Wall
+ -Wall -Wwrite-strings
abrtd_LDADD = \
$(DL_LIBS) \
$(DBUS_LIBS) \
@@ -51,7 +51,7 @@ abrt_server_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_server_LDADD = \
../lib/libreport.la
@@ -71,7 +71,7 @@ abrt_handle_crashdump_CPPFLAGS = \
-DLIBEXEC_DIR=\"$(LIBEXEC_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_handle_crashdump_LDADD = \
../lib/libreport.la
@@ -92,7 +92,7 @@ abrt_action_save_package_data_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_save_package_data_LDADD = \
$(RPM_LIBS) \
../lib/libreport.la
diff --git a/src/daemon/MiddleWare.cpp b/src/daemon/MiddleWare.cpp
index 215e7b49..8d62c697 100644
--- a/src/daemon/MiddleWare.cpp
+++ b/src/daemon/MiddleWare.cpp
@@ -351,14 +351,8 @@ report_status_t Report(crash_data_t *client_report,
for (GList *li = env_list; li; li = g_list_next(li))
{
char *s = (char*)li->data;
- /* Need to make a copy: just cutting s at '=' and unsetenv'ing
- * the result would be a bug! s _itself_ is in environment now,
- * we must not modify it there!
- */
- char *name = xstrndup(s, strchrnul(s, '=') - s);
- VERB3 log("Unexporting '%s'", name);
- unsetenv(name);
- free(name);
+ VERB3 log("Unexporting '%s'", s);
+ safe_unsetenv(s);
free(s);
}
g_list_free(env_list);
diff --git a/src/gui-gtk/Makefile.am b/src/gui-gtk/Makefile.am
index a0d0de40..64754080 100644
--- a/src/gui-gtk/Makefile.am
+++ b/src/gui-gtk/Makefile.am
@@ -2,6 +2,7 @@ bin_PROGRAMS = abrt-gtk
abrt_gtk_SOURCES = \
abrt-gtk.h abrt-gtk.c \
+ event_config_dialog.h event_config_dialog.c \
main.c
abrt_gtk_CFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
@@ -16,7 +17,7 @@ abrt_gtk_CFLAGS = \
$(GTK_CFLAGS) \
$(DBUS_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
# -I/usr/include/glib-2.0
# -I/usr/lib/glib-2.0/include
# $(LIBNOTIFY_CFLAGS)
@@ -36,7 +37,7 @@ abrt_gtk_LDADD = \
# -I$(srcdir)/../include/report -I$(srcdir)/../include \
# $(GLIB_CFLAGS) \
# -D_GNU_SOURCE \
-# -Wall -Werror
+# -Wall -Wwrite-strings -Werror
#test_report_LDADD = \
# ../lib/libreport.la
diff --git a/src/gui-gtk/abrt-gtk.c b/src/gui-gtk/abrt-gtk.c
index 751d1c7a..120389d4 100644
--- a/src/gui-gtk/abrt-gtk.c
+++ b/src/gui-gtk/abrt-gtk.c
@@ -3,9 +3,11 @@
#include "abrtlib.h"
#include "abrt_dbus.h"
#include "abrt-gtk.h"
+#include "event_config_dialog.h"
static GtkListStore *s_dumps_list_store;
static GtkWidget *s_treeview;
+static GtkWidget *g_main_window;
enum
{
@@ -87,49 +89,75 @@ static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTre
}
}
-static gint on_key_press_event_cb(GtkTreeView *treeview, GdkEventKey *key, gpointer unused)
+static void on_btn_report_cb(GtkButton *button, gpointer user_data)
{
- int k = key->keyval;
+ on_row_activated_cb(GTK_TREE_VIEW(s_treeview), NULL, NULL, NULL);
+}
- if (k == GDK_Delete || k == GDK_KP_Delete)
+static void delete_report(GtkTreeView *treeview)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
+ if (selection)
{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- if (selection)
+ GtkTreeIter iter;
+ GtkTreeModel *store = gtk_tree_view_get_model(treeview);
+ if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE)
{
- GtkTreeIter iter;
- GtkTreeModel *store = gtk_tree_view_get_model(treeview);
- if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE)
+ GtkTreePath *old_path = gtk_tree_model_get_path(store, &iter);
+
+ GValue d_dir = { 0 };
+ gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir);
+ const char *dump_dir_name = g_value_get_string(&d_dir);
+
+ VERB1 log("Deleting '%s'", dump_dir_name);
+ if (delete_dump_dir_possibly_using_abrtd(dump_dir_name) == 0)
{
- GtkTreePath *old_path = gtk_tree_model_get_path(store, &iter);
-
- GValue d_dir = { 0 };
- gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir);
- const char *dump_dir_name = g_value_get_string(&d_dir);
-
- VERB1 log("Deleting '%s'", dump_dir_name);
- if (delete_dump_dir_possibly_using_abrtd(dump_dir_name) == 0)
- {
- gtk_list_store_remove(s_dumps_list_store, &iter);
- }
- else
- {
- /* Strange. Deletion did not succeed. Someone else deleted it?
- * Rescan the whole list */
- gtk_list_store_clear(s_dumps_list_store);
- scan_dirs_and_add_to_dirlist();
- }
-
- /* Try to retain the same cursor position */
- sanitize_cursor(old_path);
- gtk_tree_path_free(old_path);
+ gtk_list_store_remove(s_dumps_list_store, &iter);
}
+ else
+ {
+ /* Strange. Deletion did not succeed. Someone else deleted it?
+ * Rescan the whole list */
+ gtk_list_store_clear(s_dumps_list_store);
+ scan_dirs_and_add_to_dirlist();
+ }
+
+ /* Try to retain the same cursor position */
+ sanitize_cursor(old_path);
+ gtk_tree_path_free(old_path);
}
+ }
+}
+
+static gint on_key_press_event_cb(GtkTreeView *treeview, GdkEventKey *key, gpointer unused)
+{
+ int k = key->keyval;
+ if (k == GDK_Delete || k == GDK_KP_Delete)
+ {
+ delete_report(treeview);
return TRUE;
}
return FALSE;
}
+static void on_btn_delete_cb(GtkButton *button, gpointer unused)
+{
+ delete_report(GTK_TREE_VIEW(s_treeview));
+}
+
+static void on_btn_online_help_cb(GtkButton *button, gpointer unused)
+{
+ gtk_show_uri(NULL,"http://docs.fedoraproject.org/en-US/Fedor"
+ "a/14/html/Deployment_Guide/ch-abrt.html",
+ GDK_CURRENT_TIME, NULL);
+}
+
+void show_events_list_dialog_cb(GtkMenuItem *menuitem, gpointer user_data)
+{
+ show_events_list_dialog(GTK_WINDOW(g_main_window));
+}
+
static void add_columns(GtkTreeView *treeview)
{
GtkCellRenderer *renderer;
@@ -193,6 +221,8 @@ GtkWidget *create_menu(void)
gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), quit_item);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_submenu);
+ g_signal_connect(quit_item, "activate", &gtk_main_quit, NULL);
+
/* edit submenu */
GtkWidget *edit_submenu = gtk_menu_new();
GtkWidget *plugins_item = gtk_menu_item_new_with_mnemonic(_("_Plugins"));
@@ -201,6 +231,9 @@ GtkWidget *create_menu(void)
gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), preferences_item);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_submenu);
+ g_signal_connect(plugins_item, "activate", G_CALLBACK(show_events_list_dialog_cb), NULL);
+
+
/* help submenu */
GtkWidget *help_submenu = gtk_menu_new();
GtkWidget *log_item = gtk_menu_item_new_with_mnemonic(_("View _log"));
@@ -217,10 +250,10 @@ GtkWidget *create_menu(void)
GtkWidget *create_main_window(void)
{
/* main window */
- GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_default_size(GTK_WINDOW(main_window), 600, 700);
- gtk_window_set_title(GTK_WINDOW(main_window), _("Automatic Bug Reporting Tool"));
- gtk_window_set_icon_name(GTK_WINDOW(main_window), "abrt");
+ g_main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(g_main_window), 600, 700);
+ gtk_window_set_title(GTK_WINDOW(g_main_window), _("Automatic Bug Reporting Tool"));
+ gtk_window_set_icon_name(GTK_WINDOW(g_main_window), "abrt");
GtkWidget *main_vbox = gtk_vbox_new(false, 0);
@@ -234,7 +267,7 @@ GtkWidget *create_main_window(void)
gtk_box_pack_start(GTK_BOX(main_vbox), create_menu(), false, false, 0);
gtk_box_pack_start(GTK_BOX(main_vbox), scroll_win, true, true, 0);
- gtk_container_add(GTK_CONTAINER(main_window), main_vbox);
+ gtk_container_add(GTK_CONTAINER(g_main_window), main_vbox);
/* tree view inside scrolled region */
s_treeview = gtk_tree_view_new();
@@ -250,14 +283,42 @@ GtkWidget *create_main_window(void)
G_TYPE_STRING);/* dump dir path */
gtk_tree_view_set_model(GTK_TREE_VIEW(s_treeview), GTK_TREE_MODEL(s_dumps_list_store));
+ /* buttons are homogenous so set size only for one button and it will
+ * work for the rest buttons in same gtk_hbox_new() */
+ GtkWidget *btn_report = gtk_button_new_with_label(_("Report"));
+ gtk_widget_set_size_request(btn_report, 200, 30);
+
+ GtkWidget *btn_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+
+ GtkWidget *hbox_report_delete = gtk_hbox_new(true, 4);
+ gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_delete, true, true, 0);
+ gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_report, true, true, 0);
+
+ GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0);
+ gtk_container_add(GTK_CONTAINER(halign), hbox_report_delete);
+
+ GtkWidget *hbox_help_close = gtk_hbutton_box_new();
+ GtkWidget *btn_online_help = gtk_button_new_with_label(_("Online Help"));
+ GtkWidget *btn_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+ gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_online_help, false, false, 0);
+ gtk_box_pack_end(GTK_BOX(hbox_help_close), btn_close, false, false, 0);
+
+ gtk_box_pack_start(GTK_BOX(main_vbox), halign, false, false, 10);
+ gtk_box_pack_start(GTK_BOX(main_vbox), hbox_help_close, false, false, 10);
+
/* Double click/Enter handler */
g_signal_connect(s_treeview, "row-activated", G_CALLBACK(on_row_activated_cb), NULL);
+ g_signal_connect(btn_report, "clicked", G_CALLBACK(on_btn_report_cb), NULL);
/* Delete handler */
g_signal_connect(s_treeview, "key-press-event", G_CALLBACK(on_key_press_event_cb), NULL);
+ g_signal_connect(btn_delete, "clicked", G_CALLBACK(on_btn_delete_cb), NULL);
/* Quit when user closes the main window */
- g_signal_connect(main_window, "destroy", gtk_main_quit, NULL);
-
- return main_window;
+ g_signal_connect(g_main_window, "destroy", gtk_main_quit, NULL);
+ /* Quit when user click on Cancel button */
+ g_signal_connect(btn_close, "clicked", gtk_main_quit, NULL);
+ /* Show online help */
+ g_signal_connect(btn_online_help, "clicked", G_CALLBACK(on_btn_online_help_cb), NULL);
+ return g_main_window;
}
void sanitize_cursor(GtkTreePath *preferred_path)
diff --git a/src/gui-gtk/event_config_dialog.c b/src/gui-gtk/event_config_dialog.c
new file mode 100644
index 00000000..50bdc4f8
--- /dev/null
+++ b/src/gui-gtk/event_config_dialog.c
@@ -0,0 +1,269 @@
+#include "abrtlib.h"
+#include <gtk/gtk.h>
+
+static GtkWidget *option_table;
+static GtkWidget *parent_dialog;
+static int last_row = 0;
+
+enum
+{
+ COLUMN_EVENT_NAME,
+ COLUMN_EVENT,
+ NUM_COLUMNS
+};
+
+static void show_event_config_dialog(event_config_t* event);
+
+static void show_error_message(const char* message)
+{
+ GtkWidget *dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ message
+ );
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
+GtkWidget *gtk_label_new_justify_left(const gchar *label_str)
+{
+ GtkWidget *label = gtk_label_new(label_str);
+ gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment(GTK_MISC(label), /*xalign:*/ 0, /*yalign:*/ 0.5);
+ return label;
+}
+
+static void add_option_to_dialog(event_option_t *option)
+{
+ GtkWidget *label;
+ GtkWidget *option_input;
+ GtkWidget *option_hbox = gtk_hbox_new(FALSE, 0);
+ switch(option->type)
+ {
+ case OPTION_TYPE_TEXT:
+ case OPTION_TYPE_NUMBER:
+ label = gtk_label_new_justify_left(option->label);
+ gtk_table_attach(GTK_TABLE(option_table), label,
+ 0, 1,
+ last_row, last_row+1,
+ GTK_FILL, GTK_FILL,
+ 0,0);
+ option_input = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(option_table), option_input,
+ 1, 2,
+ last_row, last_row+1,
+ GTK_FILL, GTK_FILL,
+ 0,0);
+
+ break;
+ case OPTION_TYPE_BOOL:
+ option_input = gtk_check_button_new_with_label(option->label);
+ gtk_table_attach(GTK_TABLE(option_table), option_input,
+ 0, 2,
+ last_row, last_row+1,
+ GTK_FILL, GTK_FILL,
+ 0,0);
+ break;
+ case OPTION_TYPE_PASSWORD:
+ label = gtk_label_new_justify_left(option->label);
+ gtk_table_attach(GTK_TABLE(option_table), label,
+ 0, 1,
+ last_row, last_row+1,
+ GTK_FILL, GTK_FILL,
+ 0,0);
+ option_input = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(option_table), option_input,
+ 1, 2,
+ last_row, last_row+1,
+ GTK_FILL, GTK_FILL,
+ 0,0);
+
+ gtk_entry_set_visibility(GTK_ENTRY(option_input), 0);
+ break;
+ default:
+ option_input = gtk_label_new_justify_left("WTF?");
+ g_print("unsupported option type\n");
+ }
+ last_row++;
+
+ gtk_widget_show_all(GTK_WIDGET(option_hbox));
+}
+
+static void add_option(gpointer data, gpointer user_data)
+{
+ event_option_t * option = (event_option_t *)data;
+ add_option_to_dialog(option);
+}
+
+static void on_close_event_list_cb(GtkWidget *button, gpointer user_data)
+{
+ GtkWidget *window = (GtkWidget *)user_data;
+ gtk_widget_destroy(window);
+}
+
+static event_config_t *get_event_config_from_row(GtkTreeView *treeview)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
+ event_config_t *event_config = NULL;
+ if (selection)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel *store = gtk_tree_view_get_model(treeview);
+ if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE)
+ {
+ GValue value = { 0 };
+ gtk_tree_model_get_value(store, &iter, COLUMN_EVENT, &value);
+ event_config = (event_config_t*)g_value_get_pointer(&value);
+ }
+ }
+ return event_config;
+}
+
+static void on_configure_event_cb(GtkWidget *button, gpointer user_data)
+{
+ GtkTreeView *events_tv = (GtkTreeView *)user_data;
+ event_config_t *ec = get_event_config_from_row(events_tv);
+ if(ec != NULL)
+ show_event_config_dialog(ec);
+ else
+ show_error_message(_("Please select a plugin from the list to edit its options."));
+}
+
+static void on_event_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
+{
+ event_config_t *ec = get_event_config_from_row(treeview);
+ show_event_config_dialog(ec);
+}
+
+static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data)
+{
+ GtkListStore *events_list_store = (GtkListStore *)user_data;
+ event_config_t *ec = (event_config_t *)value;
+ char *event_label = NULL;
+ if(ec->name != NULL && ec->description != NULL)
+ event_label = xasprintf("<b>%s</b>\n%s", ec->name, ec->description);
+ else
+ //if event has no xml description
+ event_label = xasprintf("<b>%s</b>\nNo description available", key);
+
+ GtkTreeIter iter;
+ gtk_list_store_append(events_list_store, &iter);
+ gtk_list_store_set(events_list_store, &iter,
+ COLUMN_EVENT_NAME, event_label,
+ COLUMN_EVENT, value,
+ -1);
+}
+
+static void show_event_config_dialog(event_config_t* event)
+{
+ GtkWidget *dialog = gtk_dialog_new_with_buttons(
+ event->name,
+ GTK_WINDOW(parent_dialog),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_APPLY,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ NULL);
+ if(parent_dialog != NULL)
+ {
+ gtk_window_set_icon_name(GTK_WINDOW(dialog),
+ gtk_window_get_icon_name(GTK_WINDOW(parent_dialog)));
+ }
+ int length = g_list_length(event->options);
+ option_table = gtk_table_new(length, 2, 0);
+ g_list_foreach(event->options, &add_option, NULL);
+
+ GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(content), option_table, 0, 0, 10);
+ gtk_widget_show_all(option_table);
+ int result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if(result == GTK_RESPONSE_APPLY)
+ g_print("apply\n");
+ else if(result == GTK_RESPONSE_CANCEL)
+ g_print("cancel\n");
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+void show_events_list_dialog(GtkWindow *parent)
+{
+ /*remove this line if we want to reload the config
+ *everytime we show the config dialog
+ */
+ if(g_event_config_list == NULL)
+ load_event_config_data();
+ if(g_event_config_list == NULL)
+ {
+ VERB1 log("can't load event's config\n");
+ show_error_message(_("Can't load event descriptions"));
+ return;
+ }
+ parent_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(parent_dialog), _("Event Config"));
+ gtk_window_set_default_size(GTK_WINDOW(parent_dialog), 450, 400);
+ if(parent != NULL)
+ {
+ gtk_window_set_transient_for(GTK_WINDOW(parent_dialog), parent);
+ // modal = parent window can't steal focus
+ gtk_window_set_modal(GTK_WINDOW(parent_dialog), true);
+ gtk_window_set_icon_name(GTK_WINDOW(parent_dialog),
+ gtk_window_get_icon_name(parent));
+ }
+
+ GtkWidget *main_vbox = gtk_vbox_new(0, 0);
+ GtkWidget *events_scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(events_scroll),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ /* event list treeview */
+ GtkWidget *events_tv = gtk_tree_view_new();
+ /* column with event name and description */
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ /* add column to tree view */
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(_("Event"),
+ renderer,
+ "markup",
+ COLUMN_EVENT_NAME,
+ NULL);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ gtk_tree_view_column_set_sort_column_id(column, COLUMN_EVENT_NAME);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(events_tv), column);
+
+ /* Create data store for the list and attach it
+ * COLUMN_EVENT_NAME -> name+description
+ * COLUMN_EVENT -> event_conf_t* so we can retrieve the event_config from the row
+ */
+ GtkListStore *events_list_store = gtk_list_store_new(NUM_COLUMNS,
+ G_TYPE_STRING, /* Event name + description */
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(events_tv), GTK_TREE_MODEL(events_list_store));
+
+ g_hash_table_foreach(g_event_config_list,
+ &add_event_to_liststore,
+ events_list_store);
+
+ /* Double click/Enter handler */
+ g_signal_connect(events_tv, "row-activated", G_CALLBACK(on_event_row_activated_cb), NULL);
+
+ gtk_container_add(GTK_CONTAINER(events_scroll), events_tv);
+
+ GtkWidget *configure_event_btn = gtk_button_new_with_label(_("Configure"));
+ g_signal_connect(configure_event_btn, "clicked", G_CALLBACK(on_configure_event_cb), events_tv);
+
+ GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+ g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_event_list_cb), parent_dialog);
+
+ GtkWidget *btnbox = gtk_hbutton_box_new();
+ gtk_box_pack_end(GTK_BOX(btnbox), configure_event_btn, false, false, 0);
+ gtk_box_pack_end(GTK_BOX(btnbox), close_btn, false, false, 0);
+
+ gtk_box_pack_start(GTK_BOX(main_vbox), events_scroll, true, true, 10);
+ gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
+ gtk_container_add(GTK_CONTAINER(parent_dialog), main_vbox);
+
+ gtk_widget_show_all(parent_dialog);
+}
diff --git a/src/gui-gtk/event_config_dialog.h b/src/gui-gtk/event_config_dialog.h
new file mode 100644
index 00000000..1e70e549
--- /dev/null
+++ b/src/gui-gtk/event_config_dialog.h
@@ -0,0 +1 @@
+void show_events_list_dialog(GtkWindow *parent);
diff --git a/src/gui-wizard-gtk/Makefile.am b/src/gui-wizard-gtk/Makefile.am
index 4281c470..a44de58c 100644
--- a/src/gui-wizard-gtk/Makefile.am
+++ b/src/gui-wizard-gtk/Makefile.am
@@ -24,7 +24,7 @@ bug_reporting_wizard_CFLAGS = \
$(GTK_CFLAGS) \
$(DBUS_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
# Required for gtk_builder_connect_signals() to work correctly:
# -lgmodule-2.0
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 07ce4ed7..156d05f0 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -237,6 +237,23 @@ static void save_text_from_text_view(GtkTextView *tv, const char *name)
free(new_str);
}
+static void append_to_textview(GtkTextView *tv, const char *str, int len)
+{
+ GtkTextBuffer *tb = gtk_text_view_get_buffer(tv);
+
+ /* Ensure we insert text at the end */
+ GtkTextIter text_iter;
+ gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
+ gtk_text_buffer_place_cursor(tb, &text_iter);
+
+ gtk_text_buffer_insert_at_cursor(tb, str, len >= 0 ? len : strlen(str));
+
+ /* Scroll so that the end of the log is visible */
+ gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
+ gtk_text_view_scroll_to_iter(tv, &text_iter,
+ /*within_margin:*/ 0.0, /*use_align:*/ FALSE, /*xalign:*/ 0, /*yalign:*/ 0);
+}
+
/* update_gui_state_from_crash_data */
@@ -309,6 +326,39 @@ struct cd_stats {
unsigned filecount;
};
+static void tv_details_edit_cb(GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(tree_view);
+ if (!gtk_tree_selection_get_selected(selection, &model, &iter))
+ return;
+
+ gchar *column_name;
+ gtk_tree_model_get(model, &iter, DETAIL_COLUMN_NAME, &column_name, -1);
+ struct crash_item *item = get_crash_data_item_or_NULL(g_cd, column_name);
+ if (!item || !IS_TXT(item->flags))
+ return;
+
+ if (item && IS_ONELINE(item->flags))
+ return;
+
+ gchar *arg[3];
+ arg[0] = (char *) "xdg-open";
+ arg[1] = concat_path_file(g_dump_dir_name, column_name);
+ arg[2] = NULL;
+ g_free(column_name);
+
+ g_spawn_sync(NULL, arg, NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ free(arg[1]);
+}
+
static void append_item_to_ls_details(gpointer name, gpointer value, gpointer data)
{
crash_item *item = (crash_item*)value;
@@ -453,6 +503,7 @@ struct analyze_event_data
struct run_event_state *run_state;
const char *event_name;
GList *more_events;
+ GList *env_list;
GtkWidget *page_widget;
GtkLabel *status_label;
GtkTextView *tv_log;
@@ -462,21 +513,56 @@ struct analyze_event_data
/*guint event_source_id;*/
};
-static void append_to_textview(GtkTextView *tv, const char *str, int len)
+static GList *export_event_config(const char *event_name)
{
- GtkTextBuffer *tb = gtk_text_view_get_buffer(tv);
+ GList *env_list = NULL;
- /* Ensure we insert text at the end */
- GtkTextIter text_iter;
- gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
- gtk_text_buffer_place_cursor(tb, &text_iter);
+ if (g_event_config_list)
+ {
+ GHashTableIter iter;
+ char *name;
+ event_config_t *cfg;
+ g_hash_table_iter_init(&iter, g_event_config_list);
+ while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&cfg))
+ {
+ if (strcmp(cfg->name, event_name) != 0)
+ continue;
+ for (GList *lopt = cfg->options; lopt; lopt = lopt->next)
+ {
+ event_option_t *opt = lopt->data;
+ char *var_val = xasprintf("%s=%s", opt->name, opt->value);
+VERB3 log("Exporting '%s'", var_val);
+ env_list = g_list_prepend(env_list, var_val);
+ putenv(var_val);
+ }
+ }
+ }
- gtk_text_buffer_insert_at_cursor(tb, str, len >= 0 ? len : strlen(str));
+ return env_list;
+}
- /* Scroll so that the end of the log is visible */
- gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
- gtk_text_view_scroll_to_iter(tv, &text_iter,
- /*within_margin:*/ 0.0, /*use_align:*/ FALSE, /*xalign:*/ 0, /*yalign:*/ 0);
+static void unexport_event_config(GList *env_list)
+{
+ while (env_list)
+ {
+ char *var_val = env_list->data;
+VERB3 log("Unexporting '%s'", var_val);
+ safe_unsetenv(var_val);
+ env_list = g_list_remove(env_list, var_val);
+ free(var_val);
+ }
+}
+
+static int spawn_next_command_in_evd(struct analyze_event_data *evd)
+{
+ evd->env_list = export_event_config(evd->event_name);
+ int r = spawn_next_command(evd->run_state, g_dump_dir_name, evd->event_name);
+ if (r < 0)
+ {
+ unexport_event_config(evd->env_list);
+ evd->env_list = NULL;
+ }
+ return r;
}
static gboolean consume_cmd_output(GIOChannel *source, GIOCondition condition, gpointer data)
@@ -492,7 +578,7 @@ static gboolean consume_cmd_output(GIOChannel *source, GIOCondition condition, g
}
if (r < 0 && errno == EAGAIN)
- /* We got all data, but fd is still open. Done for now */
+ /* We got all buffered data, but fd is still open. Done for now */
return TRUE; /* "please don't remove this event (yet)" */
/* EOF/error. Wait for child to actually exit, collect status */
@@ -502,9 +588,12 @@ static gboolean consume_cmd_output(GIOChannel *source, GIOCondition condition, g
if (WIFSIGNALED(status))
retval = WTERMSIG(status) + 128;
+ unexport_event_config(evd->env_list);
+ evd->env_list = NULL;
+
/* Stop if exit code is not 0, or no more commands */
if (retval != 0
- || spawn_next_command(evd->run_state, g_dump_dir_name, evd->event_name) < 0
+ || spawn_next_command_in_evd(evd) < 0
) {
VERB1 log("done running event on '%s': %d", g_dump_dir_name, retval);
//append_to_textview(evd->tv_log, msg);
@@ -534,7 +623,7 @@ static gboolean consume_cmd_output(GIOChannel *source, GIOCondition condition, g
evd->more_events = g_list_remove(evd->more_events, evd->more_events->data);
if (prepare_commands(evd->run_state, g_dump_dir_name, evd->event_name) != 0
- && spawn_next_command(evd->run_state, g_dump_dir_name, evd->event_name) >= 0
+ && spawn_next_command_in_evd(evd) >= 0
) {
VERB1 log("running event '%s' on '%s'", evd->event_name, g_dump_dir_name);
break;
@@ -589,8 +678,16 @@ static void start_event_run(const char *event_name,
if (!locked)
return; /* user refused to steal, or write error, etc... */
+ /* Load /etc/abrt/events/foo.{conf,xml} stuff */
+ load_event_config_data();
+//TODO: load overrides from keyring? Load ~/.abrt/events/foo.conf?
+
+ GList *env_list = export_event_config(event_name);
if (spawn_next_command(state, g_dump_dir_name, event_name) < 0)
+ {
+ unexport_event_config(env_list);
goto no_cmds;
+ }
VERB1 log("running event '%s' on '%s'", event_name, g_dump_dir_name);
@@ -601,6 +698,7 @@ static void start_event_run(const char *event_name,
evd->run_state = state;
evd->event_name = event_name;
evd->more_events = more_events;
+ evd->env_list = env_list;
evd->page_widget = page;
evd->status_label = status_label;
evd->tv_log = tv_log;
@@ -1007,6 +1105,7 @@ void create_assistant()
g_signal_connect(g_tb_approve_bt, "toggled", G_CALLBACK(on_bt_approve_toggle), NULL);
g_signal_connect(g_btn_refresh, "clicked", G_CALLBACK(on_btn_refresh_clicked), NULL);
+ g_signal_connect(g_tv_details, "row-activated", G_CALLBACK(tv_details_edit_cb), NULL);
/* init searching */
GtkTextBuffer *backtrace_buf = gtk_text_view_get_buffer(g_tv_backtrace);
diff --git a/src/hooks/Makefile.am b/src/hooks/Makefile.am
index 6ebf3628..66951f0f 100644
--- a/src/hooks/Makefile.am
+++ b/src/hooks/Makefile.am
@@ -9,8 +9,9 @@ abrt_hook_ccpp_CPPFLAGS = \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DCONF_DIR=\"$(CONF_DIR)\" \
-DVAR_RUN=\"$(VAR_RUN)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
- -Wall \
+ -Wall -Wwrite-strings \
-D_GNU_SOURCE
abrt_hook_ccpp_LDADD = \
../lib/libreport.la
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
index 46d96c91..c2ab166f 100644
--- a/src/hooks/abrt-hook-ccpp.c
+++ b/src/hooks/abrt-hook-ccpp.c
@@ -174,7 +174,7 @@ static char* get_cwd(pid_t pid)
*/
/* Must match CORE_PATTERN order in daemon! */
static const char percent_specifiers[] = "%scpugthe";
-static char *core_basename = "core";
+static char *core_basename = (char*) "core";
static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid, char **percent_values)
{
@@ -380,7 +380,7 @@ int main(int argc, char** argv)
unsigned setting_MaxCrashReportsSize = 0;
bool setting_MakeCompatCore = false;
bool setting_SaveBinaryImage = false;
- parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore, &setting_SaveBinaryImage);
+ parse_conf(PLUGINS_CONF_DIR"/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore, &setting_SaveBinaryImage);
if (!setting_SaveBinaryImage && src_fd_binary >= 0)
{
close(src_fd_binary);
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 477963c3..e6f0387b 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -2,7 +2,8 @@ libreport_includedir = $(includedir)/report
libreport_include_HEADERS = \
report/crash_data.h \
report/dump_dir.h \
- report/run_event.h
+ report/run_event.h \
+ report/event_config.h
libabrt_includedir = $(includedir)/abrt
libabrt_include_HEADERS = \
diff --git a/src/include/abrtlib.h b/src/include/abrtlib.h
index 116f4b36..f64046d9 100644
--- a/src/include/abrtlib.h
+++ b/src/include/abrtlib.h
@@ -82,6 +82,7 @@ int vdprintf(int d, const char *format, va_list ap);
#include "abrt_types.h"
#include "dump_dir.h"
#include "run_event.h"
+#include "event_config.h"
#ifdef __cplusplus
@@ -169,12 +170,17 @@ enum {
EXECFLG_SETGUID = 1 << 7,
EXECFLG_SETSID = 1 << 8,
};
-/* Returns pid */
+/*
+ * env_vec: list of variables to set in environment (if string has
+ * "VAR=VAL" form) or unset in environment (if string has no '=' char).
+ *
+ * Returns pid.
+ */
#define fork_execv_on_steroids abrt_fork_execv_on_steroids
pid_t fork_execv_on_steroids(int flags,
char **argv,
int *pipefds,
- char **unsetenv_vec,
+ char **env_vec,
const char *dir,
uid_t uid);
/* Returns malloc'ed string. NULs are retained, and extra one is appended
diff --git a/src/include/report/crash_data.h b/src/include/report/crash_data.h
index 3854118a..2dfdb242 100644
--- a/src/include/report/crash_data.h
+++ b/src/include/report/crash_data.h
@@ -32,8 +32,12 @@ enum {
CD_FLAG_TXT = (1 << 1),
CD_FLAG_ISEDITABLE = (1 << 2),
CD_FLAG_ISNOTEDITABLE = (1 << 3),
+ CD_FLAG_ONELINE = (1 << 4),
};
+#define IS_TXT(flag) ((flag) & CD_FLAG_TXT)
+#define IS_ONELINE(flag) ((flag) & CD_FLAG_ONELINE)
+
struct crash_item {
char *content;
unsigned flags;
diff --git a/src/include/report/event_config.h b/src/include/report/event_config.h
new file mode 100644
index 00000000..e2310885
--- /dev/null
+++ b/src/include/report/event_config.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2011 ABRT team
+
+ 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 <glib.h>
+
+#ifndef EVENT_CONFIG_H
+#define EVENT_CONFIG_H
+
+typedef enum
+{
+ OPTION_TYPE_TEXT,
+ OPTION_TYPE_BOOL,
+ OPTION_TYPE_PASSWORD,
+ OPTION_TYPE_NUMBER,
+ OPTION_TYPE_INVALID,
+} option_type_t;
+
+/*
+ * struct to hold information about config options
+ * it's supposed to hold information about:
+ * type -> which designates the widget used to display it and we can do some test based on the type
+ * label
+ * allowed value(s) -> regexp?
+ * name -> env variable name
+ * value -> value retrieved from the gui, so when we want to set the env
+ * evn variables, we can just traverse the list of the options
+ * and set the env variables according to name:value in this structure
+ */
+typedef struct
+{
+ char *name; //name of the value which should be used for env variable
+ char *value;
+ char *label;
+ option_type_t type;
+ char *description; //can be used as tooltip in gtk app
+ char *allowed_value;
+ int required;
+} event_option_t;
+
+event_option_t *new_event_option(void);
+void free_event_option(event_option_t *p);
+
+//structure to hold the option data
+typedef struct
+{
+ char *name; //name of the event "Bugzilla" "RedHat Support Uploader"
+ char *title; //window title - not used right now, maybe the "name" is enough?
+ char *action;//action description to show in gui like: Upload report to the Red Hat bugzilla"
+ char *description;
+ GList *options;
+} event_config_t;
+
+event_config_t *new_event_config(void);
+void free_event_config(event_config_t *p);
+
+
+void load_event_description_from_file(event_config_t *event_config, const char* filename);
+
+// (Re)loads data from /etc/abrt/events/*.{conf,xml}
+void load_event_config_data(void);
+/* Frees all loaded data */
+void free_event_config_data(void);
+event_config_t *get_event_config(const char *name);
+
+extern GHashTable *g_event_config_list; // for iterating through entire list of all loaded configs
+
+#endif
diff --git a/src/include/xfuncs.h b/src/include/xfuncs.h
index 61188c81..5f2504b6 100644
--- a/src/include/xfuncs.h
+++ b/src/include/xfuncs.h
@@ -74,6 +74,19 @@ char* xasprintf(const char *format, ...);
#define xsetenv abrt_xsetenv
void xsetenv(const char *key, const char *value);
+/*
+ * Utility function to unsetenv a string which was possibly putenv'ed.
+ * The problem here is that "natural" optimization:
+ * strchrnul(var_val, '=')[0] = '\0';
+ * unsetenv(var_val);
+ * is BUGGY: if string was put into environment via putenv,
+ * its modification (s/=/NUL/) is illegal, and unsetenv will fail to unset it.
+ * Of course, saving/restoring the char wouldn't work either.
+ * This helper creates a copy up to '=', unsetenv's it, and frees:
+ */
+#define safe_unsetenv abrt_safe_unsetenv
+void safe_unsetenv(const char *var_val);
+
#define xsocket abrt_xsocket
int xsocket(int domain, int type, int protocol);
#define xbind abrt_xbind
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index bad3e63a..36fe7b4b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -43,16 +43,19 @@ libreport_la_SOURCES = \
hooklib.c hooklib.h \
parse_release.c \
parse_options.c parse_options.h \
- steal_directory.c
+ steal_directory.c \
+ event_xml_parser.c \
+ event_config.c
libreport_la_CPPFLAGS = \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE
libreport_la_LDFLAGS = \
@@ -64,14 +67,16 @@ libabrt_dbus_la_SOURCES = \
abrt_dbus.c abrt_dbus.h
libabrt_dbus_la_CPPFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-D_GNU_SOURCE
libabrt_dbus_la_LDFLAGS = \
-version-info 0:1:0
@@ -83,13 +88,15 @@ libabrt_web_la_SOURCES = \
abrt_curl.h abrt_curl.c \
abrt_xmlrpc.h abrt_xmlrpc.cpp
libabrt_web_la_CPPFLAGS = \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
$(CURL_CFLAGS) \
$(LIBXML_CFLAGS) \
diff --git a/src/lib/crash_data.c b/src/lib/crash_data.c
index 63b0a7a5..7f23c52f 100644
--- a/src/lib/crash_data.c
+++ b/src/lib/crash_data.c
@@ -233,10 +233,21 @@ void load_crash_data_from_dump_dir(crash_data_t *crash_data, struct dump_dir *dd
content = dd_load_text(dd, short_name);
}
+ int flags = 0;
+
+ if (editable)
+ flags |= CD_FLAG_TXT | CD_FLAG_ISEDITABLE;
+ else
+ flags |= CD_FLAG_TXT | CD_FLAG_ISNOTEDITABLE;
+
+ int oneline = strchr(content, '\n') == NULL;
+ if (oneline)
+ flags |= CD_FLAG_ONELINE;
+
add_to_crash_data_ext(crash_data,
short_name,
content,
- (editable ? CD_FLAG_TXT + CD_FLAG_ISEDITABLE : CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE)
+ flags
);
free(short_name);
free(full_name);
diff --git a/src/lib/event_config.c b/src/lib/event_config.c
new file mode 100644
index 00000000..a79ee40c
--- /dev/null
+++ b/src/lib/event_config.c
@@ -0,0 +1,135 @@
+#include "abrtlib.h"
+
+GHashTable *g_event_config_list;
+
+event_option_t *new_event_option(void)
+{
+ return xzalloc(sizeof(event_option_t));
+}
+
+event_config_t *new_event_config(void)
+{
+ return xzalloc(sizeof(event_config_t));
+}
+
+void free_event_option(event_option_t *p)
+{
+ if (!p)
+ return;
+ free(p->name);
+ free(p->value);
+ free(p->label);
+ free(p->description);
+ free(p->allowed_value);
+ free(p);
+}
+
+void free_event_config(event_config_t *p)
+{
+ if (!p)
+ return;
+ free(p->name);
+ free(p->title);
+ free(p->action);
+ free(p->description);
+ for (GList *opt = p->options; opt; opt = opt->next)
+ free_event_option(opt->data);
+ g_list_free(p->options);
+ free(p);
+}
+
+
+// (Re)loads data from /etc/abrt/events/*.{conf,xml}
+void load_event_config_data(void)
+{
+ free_event_config_data();
+
+ DIR *dir = opendir(EVENTS_DIR);
+ if (!dir)
+ return;
+
+ if (!g_event_config_list)
+ g_event_config_list = g_hash_table_new_full(
+ /*hash_func*/ g_str_hash,
+ /*key_equal_func:*/ g_str_equal,
+ /*key_destroy_func:*/ free,
+ /*value_destroy_func:*/ (GDestroyNotify) free_event_config
+ );
+
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
+ {
+ char *ext = strrchr(dent->d_name, '.');
+ if (!ext)
+ continue;
+ bool conf = strcmp(ext + 1, "conf") == 0;
+ bool xml = strcmp(ext + 1, "xml") == 0;
+ if (!conf && !xml)
+ continue;
+
+ char *fullname = concat_path_file(EVENTS_DIR, dent->d_name);
+
+ *ext = '\0';
+ event_config_t *event_config = get_event_config(dent->d_name);
+ bool new_config = (!event_config);
+ if (new_config)
+ event_config = new_event_config();
+
+ if (xml)
+ load_event_description_from_file(event_config, fullname);
+ if (conf)
+ {
+ map_string_h *keys_and_values = new_map_string();
+
+ load_conf_file(fullname, keys_and_values, /*skipKeysWithoutValue:*/ false);
+
+ /* Insert or replace every key/value from keys_and_values to event_config->option */
+ GHashTableIter iter;
+ char *name;
+ char *value;
+ g_hash_table_iter_init(&iter, keys_and_values);
+ while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
+ {
+ event_option_t *opt;
+ GList *elem = g_list_find(event_config->options, name);
+ if (elem)
+ {
+ opt = elem->data;
+ free(opt->value);
+ }
+ else
+ {
+ opt = new_event_option();
+ opt->name = xstrdup(name);
+ }
+ opt->value = xstrdup(value);
+ if (!elem)
+ event_config->options = g_list_append(event_config->options, opt);
+ }
+
+ free_map_string(keys_and_values);
+ }
+
+ free(fullname);
+
+ if (new_config)
+ g_hash_table_replace(g_event_config_list, xstrdup(dent->d_name), event_config);
+ }
+}
+
+/* Frees all loaded data */
+void free_event_config_data(void)
+{
+ if (g_event_config_list)
+ {
+ g_hash_table_destroy(g_event_config_list);
+ g_event_config_list = NULL;
+ }
+}
+
+event_config_t *get_event_config(const char *name)
+{
+ if (!g_event_config_list)
+ return NULL;
+ return g_hash_table_lookup(g_event_config_list, name);
+}
diff --git a/src/lib/event_xml_parser.c b/src/lib/event_xml_parser.c
new file mode 100644
index 00000000..be4a9e09
--- /dev/null
+++ b/src/lib/event_xml_parser.c
@@ -0,0 +1,203 @@
+#include "abrtlib.h"
+#include "event_config.h"
+
+#define EVENT_ELEMENT "event"
+#define LABEL_ELEMENT "label"
+#define DESCRIPTION_ELEMENT "description"
+#define ALLOW_EMPTY_ELEMENT "allow-empty"
+#define OPTION_ELEMENT "option"
+#define ACTION_ELEMENT "action"
+#define NAME_ELEMENT "name"
+
+static int in_option = 0; //FIXME
+
+static const char *const option_types[] =
+{
+ "text",
+ "bool",
+ "password",
+ "number",
+ NULL
+};
+
+// Called for open tags <foo bar="baz">
+static void start_element(GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ //g_print("start: %s\n", element_name);
+
+ event_config_t *ui = user_data;
+
+ if (strcmp(element_name, OPTION_ELEMENT) == 0)
+ {
+ if (in_option == 0)
+ {
+ in_option = 1;
+ event_option_t *option = new_event_option();
+ //we need to prepend, so ui->options always points to the last created option
+ VERB2 log("adding option");
+ ui->options = g_list_prepend(ui->options, option);
+
+ int i;
+ for (i = 0; attribute_names[i] != NULL; ++i)
+ {
+ VERB2 log("attr: %s:%s", attribute_names[i], attribute_values[i]);
+ if (strcmp(attribute_names[i], "name") == 0)
+ {
+ free(option->name);
+ option->name = xstrdup(attribute_values[i]);
+ }
+ else if (strcmp(attribute_names[i], "type") == 0)
+ {
+ option_type_t type;
+ for (type = OPTION_TYPE_TEXT; type < OPTION_TYPE_INVALID; ++type)
+ {
+ if (strcmp(option_types[type], attribute_values[i]) == 0)
+ option->type = type;
+ }
+ }
+ }
+ }
+ else
+ {
+ error_msg("error, option nested in option");
+ }
+ }
+
+}
+
+// Called for close tags </foo>
+static void end_element(GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ event_config_t *ui = user_data;
+ if (strcmp(element_name, OPTION_ELEMENT) == 0)
+ {
+ in_option = 0;
+ }
+ if (strcmp(element_name, EVENT_ELEMENT) == 0)
+ {
+ //we need to reverse the list, because we we're prepending
+ ui->options = g_list_reverse(ui->options);
+ in_option = 0;
+ }
+}
+
+// Called for character data
+// text is not nul-terminated
+static void text(GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ event_config_t *ui = user_data;
+ const gchar * inner_element = g_markup_parse_context_get_element(context);
+ char *_text = xstrndup(text, text_len);
+ if (in_option == 1)
+ {
+ event_option_t *option = ui->options->data;
+ if (strcmp(inner_element, LABEL_ELEMENT) == 0)
+ {
+ VERB2 log("new label:'%s'", _text);
+ free(option->label);
+ option->label = _text;
+ return;
+ }
+ if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
+ {
+ VERB2 log("tooltip:'%s'", _text);
+ free(option->description);
+ option->description = _text;
+ return;
+ }
+ }
+ else
+ {
+ /* we're not in option, so the description is for the event */
+ if (strcmp(inner_element, ACTION_ELEMENT) == 0)
+ {
+ VERB2 log("action description:'%s'", _text);
+ free(ui->action);
+ ui->action = _text;
+ return;
+ }
+ if (strcmp(inner_element, NAME_ELEMENT) == 0)
+ {
+ VERB2 log("event name:'%s'", _text);
+ free(ui->name);
+ ui->name = _text;
+ return;
+ }
+ if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
+ {
+ VERB2 log("event description:'%s'", _text);
+ free(ui->description);
+ ui->description = _text;
+ return;
+ }
+ }
+ free(_text);
+}
+
+ // Called for strings that should be re-saved verbatim in this same
+ // position, but are not otherwise interpretable. At the moment
+ // this includes comments and processing instructions.
+ // text is not nul-terminated
+static void passthrough(GMarkupParseContext *context,
+ const gchar *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ VERB2 log("passthrough");
+}
+
+// Called on error, including one set by other
+// methods in the vtable. The GError should not be freed.
+static void error(GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ error_msg("error in XML parsing");
+}
+
+/* this function takes 2 parameters
+ * ui -> pointer to event_config_t
+ * filename -> filename to read
+ * event_config_t contains list of options, which is malloced by hits function
+ * and must be freed by the caller
+ */
+
+void load_event_description_from_file(event_config_t *event_config, const char* filename)
+{
+ GMarkupParser parser;
+ parser.start_element = &start_element;
+ parser.end_element = &end_element;
+ parser.text = &text;
+ parser.passthrough = &passthrough;
+ parser.error = &error;
+ GMarkupParseContext *context = g_markup_parse_context_new(
+ &parser, G_MARKUP_TREAT_CDATA_AS_TEXT,
+ event_config, /*GDestroyNotify:*/ NULL);
+
+ FILE* fin = fopen(filename, "r");
+ if (fin != NULL)
+ {
+ size_t read_bytes = 0;
+ char buff[1024];
+ while ((read_bytes = fread(buff, 1, 1024, fin)) != 0)
+ {
+ g_markup_parse_context_parse(context, buff, read_bytes, NULL);
+ }
+ fclose(fin);
+ }
+
+ g_markup_parse_context_free(context);
+}
diff --git a/src/lib/load_plugin_settings.c b/src/lib/load_plugin_settings.c
index 1e6b31e7..1b6086f9 100644
--- a/src/lib/load_plugin_settings.c
+++ b/src/lib/load_plugin_settings.c
@@ -34,47 +34,47 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
char *line;
while ((line = xmalloc_fgetline(fp)) != NULL)
{
- unsigned ii;
- bool valid = false;
bool in_quote = false;
/* We are reusing line buffer to form temporary
* "key\0value\0..." in its beginning
*/
- char *key = line;
- char *value = line;
- char *cur = line;
-
- for (ii = 0; line[ii] != '\0'; ii++)
+ char *value = NULL;
+ char *src;
+ char *dst;
+ for (src = dst = line; *src; src++)
{
- if (line[ii] == '"')
+ char c = *src;
+ if (c == '"')
{
in_quote = !in_quote;
}
- if (isspace(line[ii]) && !in_quote)
- {
- continue;
- }
- if (line[ii] == '#' && !in_quote && cur == line)
- {
- break;
- }
- if (line[ii] == '=' && !in_quote)
+ if (!in_quote)
{
- valid = true;
- *cur++ = '\0'; /* terminate key */
- value = cur; /* remember where value starts */
- continue;
+ if (isspace(c))
+ {
+ continue;
+ }
+ if (c == '#' && dst == line)
+ {
+ break;
+ }
+ if (c == '=')
+ {
+ *dst++ = '\0'; /* terminate key */
+ value = dst; /* remember where value starts */
+ continue;
+ }
}
- *cur++ = line[ii]; /* store next key or value char */
+ *dst++ = c; /* store next key or value char */
}
- *cur++ = '\0'; /* terminate value */
+ *dst = '\0'; /* terminate value */
/* Skip broken or empty lines. */
- if (!valid)
+ if (!value)
goto free_line;
/* Skip lines with empty key. */
- if (key[0] == '\0')
+ if (line[0] == '\0')
goto free_line;
if (skipKeysWithoutValue && value[0] == '\0')
@@ -84,7 +84,7 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
if (in_quote)
goto free_line;
- g_hash_table_replace(settings, xstrdup(key), xstrdup(value));
+ g_hash_table_replace(settings, xstrdup(line), xstrdup(value));
free_line:
free(line);
}
diff --git a/src/lib/run_event.c b/src/lib/run_event.c
index a2bbc76b..45facffd 100644
--- a/src/lib/run_event.c
+++ b/src/lib/run_event.c
@@ -93,7 +93,7 @@ static GList *load_event_config(GList *list,
if (*p == '\0' || *p == '#')
goto next_line; /* empty or comment line, skip */
- VERB3 log("%s: line '%s'", __func__, p);
+ //VERB3 log("%s: line '%s'", __func__, p);
if (strncmp(p, "include", strlen("include")) == 0 && isblank(p[strlen("include")]))
{
@@ -117,15 +117,15 @@ static GList *load_event_config(GList *list,
glob_t globbuf;
memset(&globbuf, 0, sizeof(globbuf));
- VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
+ //VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
glob(name_to_glob, 0, NULL, &globbuf);
free(name_to_glob);
char **name = globbuf.gl_pathv;
if (name) while (*name)
{
- VERB3 log("%s: recursing into '%s'", __func__, *name);
+ //VERB3 log("%s: recursing into '%s'", __func__, *name);
list = load_event_config(list, dump_dir_name, event, *name);
- VERB3 log("%s: returned from '%s'", __func__, *name);
+ //VERB3 log("%s: returned from '%s'", __func__, *name);
name++;
}
globfree(&globbuf);
@@ -174,10 +174,10 @@ static GList *load_event_config(GList *list,
/* Does VAL match? */
if (strcmp(real_val, line_val) != 0)
{
- VERB3 log("var '%s': '%.*s'!='%s', skipping line",
- p,
- (int)(strchrnul(real_val, '\n') - real_val), real_val,
- line_val);
+ //VERB3 log("var '%s': '%.*s'!='%s', skipping line",
+ // p,
+ // (int)(strchrnul(real_val, '\n') - real_val), real_val,
+ // line_val);
free(malloced_val);
goto next_line; /* no */
}
@@ -245,18 +245,19 @@ int spawn_next_command(struct run_event_state *state,
VERB1 log("Executing '%s'", cmd);
/* Export some useful environment variables for children */
+ char *env_vec[3];
/* 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);
+ env_vec[0] = xasprintf("DUMP_DIR=%s", (full_name ? full_name : dump_dir_name));
free(full_name);
- setenv("EVENT", event, 1);
-//FIXME: set vars in the child, not here! Need to improve fork_execv_on_steroids...
+ env_vec[1] = xasprintf("EVENT=%s", event);
+ env_vec[2] = NULL;
char *argv[4];
- argv[0] = (char*)"/bin/sh";
+ argv[0] = (char*)"/bin/sh"; // TODO: honor $SHELL?
argv[1] = (char*)"-c";
argv[2] = cmd;
argv[3] = NULL;
@@ -266,12 +267,15 @@ int spawn_next_command(struct run_event_state *state,
EXECFLG_INPUT_NUL + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
argv,
pipefds,
- /* unsetenv_vec: */ NULL,
+ /* env_vec: */ env_vec,
/* dir: */ dump_dir_name,
/* uid(unused): */ 0
);
state->command_out_fd = pipefds[0];
+ free(env_vec[0]);
+ free(env_vec[1]);
+
state->commands = g_list_remove(state->commands, cmd);
return 0;
@@ -396,7 +400,7 @@ static int list_possible_events_helper(struct strbuf *result,
if (*p == '\0' || *p == '#')
goto next_line; /* empty or comment line, skip */
- VERB3 log("%s: line '%s'", __func__, p);
+ //VERB3 log("%s: line '%s'", __func__, p);
if (strncmp(p, "include", strlen("include")) == 0 && isblank(p[strlen("include")]))
{
@@ -420,15 +424,15 @@ static int list_possible_events_helper(struct strbuf *result,
glob_t globbuf;
memset(&globbuf, 0, sizeof(globbuf));
- VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
+ //VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
glob(name_to_glob, 0, NULL, &globbuf);
free(name_to_glob);
char **name = globbuf.gl_pathv;
if (name) while (*name)
{
- VERB3 log("%s: recursing into '%s'", __func__, *name);
+ //VERB3 log("%s: recursing into '%s'", __func__, *name);
error = list_possible_events_helper(result, dd, dump_dir_name, pfx, *name);
- VERB3 log("%s: returned from '%s'", __func__, *name);
+ //VERB3 log("%s: returned from '%s'", __func__, *name);
if (error)
break;
name++;
@@ -480,10 +484,10 @@ static int list_possible_events_helper(struct strbuf *result,
/* Does VAL match? */
if (strcmp(real_val, line_val) != 0)
{
- VERB3 log("var '%s': '%.*s'!='%s', skipping line",
- p,
- (int)(strchrnul(real_val, '\n') - real_val), real_val,
- line_val);
+ //VERB3 log("var '%s': '%.*s'!='%s', skipping line",
+ // p,
+ // (int)(strchrnul(real_val, '\n') - real_val), real_val,
+ // line_val);
free(real_val);
goto next_line; /* no */
}
diff --git a/src/lib/spawn.c b/src/lib/spawn.c
index f6b7263c..188b63bd 100644
--- a/src/lib/spawn.c
+++ b/src/lib/spawn.c
@@ -32,7 +32,7 @@ static char *concat_str_vector(char **strings)
pid_t fork_execv_on_steroids(int flags,
char **argv,
int *pipefds,
- char **unsetenv_vec,
+ char **env_vec,
const char *dir,
uid_t uid)
{
@@ -69,9 +69,11 @@ pid_t fork_execv_on_steroids(int flags,
xsetreuid(uid, uid);
}
- if (unsetenv_vec) {
- while (*unsetenv_vec)
- unsetenv(*unsetenv_vec++);
+ if (env_vec) {
+ /* Note: we use the glibc extension that putenv("var")
+ * *unsets* $var if "var" string has no '=' */
+ while (*env_vec)
+ putenv(*env_vec++);
}
/* Play with stdio descriptors */
@@ -134,7 +136,7 @@ char *run_in_shell_and_save_output(int flags,
const char *argv[] = { "/bin/sh", "-c", cmd, NULL };
int pipeout[2];
pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout,
- /*unsetenv_vec:*/ NULL, dir, /*uid (unused):*/ 0);
+ /*env_vec:*/ NULL, dir, /*uid (unused):*/ 0);
size_t pos = 0;
char *result = NULL;
diff --git a/src/lib/xfuncs.c b/src/lib/xfuncs.c
index f451693a..3766d231 100644
--- a/src/lib/xfuncs.c
+++ b/src/lib/xfuncs.c
@@ -215,6 +215,20 @@ void xsetenv(const char *key, const char *value)
die_out_of_memory();
}
+void safe_unsetenv(const char *var_val)
+{
+ //char *name = xstrndup(var_val, strchrnul(var_val, '=') - var_val);
+ //unsetenv(name);
+ //free(name);
+
+ /* Avoid malloc/free (name is usually very short) */
+ unsigned len = strchrnul(var_val, '=') - var_val;
+ char name[len + 1];
+ memcpy(name, var_val, len);
+ name[len] = '\0';
+ unsetenv(name);
+}
+
// Die with an error message if we can't open a new socket.
int xsocket(int domain, int type, int protocol)
{
diff --git a/src/plugins/Bugzilla.xml b/src/plugins/Bugzilla.xml
new file mode 100644
index 00000000..bc8e8ecb
--- /dev/null
+++ b/src/plugins/Bugzilla.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<event>
+ <name>Bugzilla</name>
+ <action>Report this problem to the Red Hat bug tracker</action>
+ <description>Reports selected problems to the Red Hat bug tracker</description>
+ <options>
+ <option type="text" name="Bugzilla_BugzillaURL">
+ <label>Bugzilla URL</label>
+ <allow-empty>no</allow-empty>
+ <description>Address of the bugzilla server</description>
+ <property>Address of the bugzilla server</property>
+ <notused1>blahblahblah</notused1>
+ </option>
+ <option type="text" name="Bugzilla_Login">
+ <label>User name</label>
+ <allow-empty>no</allow-empty>
+ <description>Username to use to log into your bugzilla account</description>
+ </option>
+ <option type="password" name="Bugzilla_Password">
+ <label>Password</label>
+ <allow-empty>no</allow-empty>
+ <description>Password for your bugzilla account</description>
+ </option>
+ <option type="bool" name="Bugzilla_SSLVerify">
+ <label>SSL Verify</label>
+ <description>Check the ssl key validity</description>
+ </option>
+ </options>
+</event>
+
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 59e0f1a4..3c4b37cf 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -38,6 +38,11 @@ dist_pluginsconf_DATA = \
RHTSupport.conf \
Upload.conf
+eventsdir = $(EVENTS_DIR)
+
+dist_events_DATA = \
+ Bugzilla.xml
+
eventsconfdir = $(EVENTS_CONF_DIR)
dist_eventsconf_DATA = \
@@ -77,7 +82,7 @@ abrt_dump_oops_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_dump_oops_LDADD = \
../lib/libreport.la
@@ -96,7 +101,7 @@ abrt_action_analyze_c_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_analyze_c_LDADD = \
../lib/libreport.la
@@ -115,7 +120,7 @@ abrt_action_analyze_python_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_analyze_python_LDADD = \
../lib/libreport.la
@@ -134,7 +139,7 @@ abrt_action_analyze_oops_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_analyze_oops_LDADD = \
../lib/libreport.la
@@ -153,7 +158,7 @@ abrt_action_generate_backtrace_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_generate_backtrace_LDADD = \
../lib/libreport.la \
../btparser/libbtparser.la
@@ -173,7 +178,7 @@ abrt_action_bugzilla_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_bugzilla_LDADD = \
$(GLIB_LIBS) \
../lib/libabrt_web.la \
@@ -196,7 +201,7 @@ abrt_action_rhtsupport_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_rhtsupport_LDFLAGS = -ltar
abrt_action_rhtsupport_LDADD = \
$(GLIB_LIBS) \
@@ -220,7 +225,7 @@ abrt_action_upload_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(CURL_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_upload_LDFLAGS = -ltar
abrt_action_upload_LDADD = \
$(GLIB_LIBS) \
@@ -242,7 +247,7 @@ abrt_action_kerneloops_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_kerneloops_LDADD = \
../lib/libabrt_web.la \
../lib/libreport.la
@@ -262,7 +267,7 @@ abrt_action_mailx_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_mailx_LDADD = \
../lib/libreport.la
@@ -281,7 +286,7 @@ abrt_action_print_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_action_print_LDADD = \
../lib/libreport.la
@@ -291,7 +296,7 @@ abrt_action_install_debuginfo_CPPFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
-I$(srcdir)/../lib \
-D_GNU_SOURCE \
- -Wall
+ -Wall -Wwrite-strings
abrt_action_install_debuginfo_LDADD =
abrt_retrace_client_SOURCES = \
@@ -303,7 +308,7 @@ abrt_retrace_client_SOURCES = \
$(NSS_CFLAGS) \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
abrt_retrace_client_LDADD = \
../lib/libreport.la \
../btparser/libbtparser.la \
diff --git a/src/plugins/abrt-action-analyze-c.c b/src/plugins/abrt-action-analyze-c.c
index 5def9aa1..635a3316 100644
--- a/src/plugins/abrt-action-analyze-c.c
+++ b/src/plugins/abrt-action-analyze-c.c
@@ -63,7 +63,7 @@ static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
args[2] = (char*)"-n";
args[3] = NULL;
- pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*unsetenv_vec:*/ NULL, /*dir:*/ NULL, uid);
+ pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, uid);
free(args[1]);
/* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
diff --git a/src/plugins/abrt-action-generate-backtrace.c b/src/plugins/abrt-action-generate-backtrace.c
index a8c18e36..7defc9c4 100644
--- a/src/plugins/abrt-action-generate-backtrace.c
+++ b/src/plugins/abrt-action-generate-backtrace.c
@@ -76,6 +76,11 @@ static char* exec_vp(char **args, uid_t uid, int redirect_stderr, int *status)
"LC_MONETARY",
"LC_NUMERIC",
"LC_TIME",
+ /* Workaround for
+ * http://sourceware.org/bugzilla/show_bug.cgi?id=9622
+ * (gdb emitting ESC sequences even with -batch)
+ */
+ "TERM",
NULL
};
@@ -137,12 +142,6 @@ static char *get_backtrace(struct dump_dir *dd)
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";
diff --git a/src/plugins/abrt-action-mailx.c b/src/plugins/abrt-action-mailx.c
index 3debf449..06f81780 100644
--- a/src/plugins/abrt-action-mailx.c
+++ b/src/plugins/abrt-action-mailx.c
@@ -32,7 +32,7 @@ static void exec_and_feed_input(uid_t uid, const char* text, char **args)
EXECFLG_INPUT | EXECFLG_QUIET | EXECFLG_SETGUID,
args,
pipein,
- /*unsetenv_vec:*/ NULL,
+ /*env_vec:*/ NULL,
/*dir:*/ NULL,
uid);
diff --git a/src/report-python/Makefile.am b/src/report-python/Makefile.am
index a00e2d7b..94dc3abb 100644
--- a/src/report-python/Makefile.am
+++ b/src/report-python/Makefile.am
@@ -23,7 +23,7 @@ _pyreport_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(PYTHON_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Werror
+ -Wall -Wwrite-strings -Werror
_pyreport_la_LDFLAGS = \
-module \
-avoid-version \
diff --git a/src/report-python/dump_dir.c b/src/report-python/dump_dir.c
index c8ff3798..96a96fba 100644
--- a/src/report-python/dump_dir.c
+++ b/src/report-python/dump_dir.c
@@ -193,7 +193,7 @@ static PyMethodDef p_dump_dir_methods[] = {
static PyGetSetDef p_dump_dir_getset[] = {
/* attr_name, getter_func, setter_func, doc_string, void_param */
- { "name", get_name, NULL /*set_name*/ },
+ { (char*) "name", get_name, NULL /*set_name*/ },
{ NULL }
};
diff --git a/src/report-python/reportmodule.c b/src/report-python/reportmodule.c
index 41f0ba29..a684984e 100644
--- a/src/report-python/reportmodule.c
+++ b/src/report-python/reportmodule.c
@@ -61,7 +61,7 @@ init_pyreport(void)
}
/* init the exception object */
- ReportError = PyErr_NewException("_pyreport.error", NULL, NULL);
+ ReportError = PyErr_NewException((char*) "_pyreport.error", NULL, NULL);
Py_INCREF(ReportError);
PyModule_AddObject(m, "error", ReportError);
diff --git a/src/report-python/run_event.c b/src/report-python/run_event.c
index 6131df8e..684c7fc7 100644
--- a/src/report-python/run_event.c
+++ b/src/report-python/run_event.c
@@ -76,7 +76,7 @@ static void p_run_event_state_dealloc(PyObject *pself)
static int post_run_callback(const char *dump_dir_name, void *param)
{
PyObject *obj = (PyObject*)param;
- PyObject *ret = PyObject_CallMethod(obj, "post_run_callback", "(s)", dump_dir_name);
+ PyObject *ret = PyObject_CallMethod(obj, (char*) "post_run_callback", (char*) "(s)", dump_dir_name);
int r = 0;
if (ret)
{
@@ -89,7 +89,7 @@ static int post_run_callback(const char *dump_dir_name, void *param)
static char *logging_callback(char *log_line, void *param)
{
PyObject *obj = (PyObject*)param;
- PyObject *ret = PyObject_CallMethod(obj, "logging_callback", "(s)", log_line);
+ PyObject *ret = PyObject_CallMethod(obj, (char*) "logging_callback", (char*) "(s)", log_line);
Py_XDECREF(ret);
// TODO: handle exceptions: if (PyErr_Occurred()) ...
return log_line; /* signaling to caller that we didnt consume the string */
@@ -200,8 +200,8 @@ static PyMethodDef p_run_event_state_methods[] = {
static PyGetSetDef p_run_event_state_getset[] = {
/* attr_name, getter_func, setter_func, doc_string, void_param */
- { "post_run_callback", get_post_run_callback, set_post_run_callback },
- { "logging_callback" , get_logging_callback , set_logging_callback },
+ { (char*) "post_run_callback", get_post_run_callback, set_post_run_callback },
+ { (char*) "logging_callback" , get_logging_callback , set_logging_callback },
{ NULL }
};
diff --git a/src/retrace/retrace.py b/src/retrace/retrace.py
index 46adb740..ddeb9ffd 100644
--- a/src/retrace/retrace.py
+++ b/src/retrace/retrace.py
@@ -25,6 +25,10 @@ RELEASE_PARSERS = {
"fedora": re.compile("^Fedora[^0-9]+([0-9]+)[^\(]\(([^\)]+)\)$"),
}
+GUESS_RELEASE_PARSERS = {
+ "fedora": re.compile("\.fc([0-9]+)"),
+}
+
TASKPASS_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
CONFIG_FILE = "/etc/abrt/retrace.conf"
@@ -109,6 +113,47 @@ def guess_arch(coredump_path):
return None
+def guess_release(package):
+ for distro in GUESS_RELEASE_PARSERS.keys():
+ match = GUESS_RELEASE_PARSERS[distro].search(package)
+ if match:
+ return distro, match.group(1)
+
+ return None, None
+
+def run_gdb(savedir):
+ try:
+ exec_file = open("%s/crash/executable" % savedir, "r")
+ executable = exec_file.read().replace("'", "")
+ exec_file.close()
+ except:
+ return ""
+
+ mockr = "../../%s/mock" % savedir
+
+ chmod = Popen(["mock", "shell", "-r", mockr, "--",
+ "/bin/chmod", "777", executable])
+ if chmod.wait() != 0:
+ return ""
+
+ pipe = Popen(["mock", "shell", "-r", mockr, "--",
+ "gdb", "-batch",
+ "-ex", "'file %s'" % executable,
+ "-ex", "'core-file /var/spool/abrt/crash/coredump'",
+ "-ex", "'thread apply all backtrace 2048 full'",
+ "-ex", "'info sharedlib'",
+ "-ex", "'print (char*)__abort_msg'",
+ "-ex", "'print (char*)__glib_assert_msg'",
+ "-ex", "'info registers'",
+ "-ex", "'disassemble'",
+ # redirect GDB's stderr, ignore mock's stderr
+ "2>&1"], stdout=PIPE).stdout
+
+ backtrace = pipe.read()
+ pipe.close()
+
+ return backtrace
+
def gen_task_password(taskdir):
generator = random.SystemRandom()
taskpass = ""
diff --git a/src/retrace/worker.py b/src/retrace/worker.py
index 2bb33237..48ef8402 100755
--- a/src/retrace/worker.py
+++ b/src/retrace/worker.py
@@ -68,6 +68,16 @@ if __name__ == "__main__":
LOG.close()
sys.exit(16)
+ # read package file
+ try:
+ package_file = open("%s/crash/package" % savedir, "r")
+ crash_package = package_file.read()
+ package_file.close()
+ except Exception as ex:
+ LOG.write("Unable to read crash package from 'package' file: %s.\n" % ex)
+ LOG.close()
+ sys.exit(17)
+
# read release, distribution and version from release file
release_path = "%s/crash/os_release" % savedir
if not os.path.isfile(release_path):
@@ -77,23 +87,28 @@ if __name__ == "__main__":
release_file = open(release_path, "r")
release = release_file.read()
release_file.close()
- except Exception as ex:
- LOG.write("Unable to read distribution and version from 'release' file: %s.\n" % ex)
- LOG.close()
- sys.exit(17)
- version = distribution = None
- for distro in RELEASE_PARSERS.keys():
- match = RELEASE_PARSERS[distro].match(release)
- if match:
- version = match.group(1)
- distribution = distro
- break
+ version = distribution = None
+ for distro in RELEASE_PARSERS.keys():
+ match = RELEASE_PARSERS[distro].match(release)
+ if match:
+ version = match.group(1)
+ distribution = distro
+ break
- if not version or not distribution:
- LOG.write("Release '%s' is not supported.\n" % release)
- LOG.close()
- sys.exit(18)
+ if not version or not distribution:
+ raise Exception, "Release '%s' is not supported.\n"
+
+ except Exception as ex:
+ LOG.write("Unable to read distribution and version from 'release' file: %s.\n" % ex)
+ LOG.write("Trying to guess distribution and version... ")
+ distribution, version = guess_release(crash_package)
+ if distribution and version:
+ LOG.write("%s-%s\n" % (distribution, version))
+ else:
+ LOG.write("Failure\n")
+ LOG.close()
+ sys.exit(18)
# read package file
try:
@@ -135,7 +150,7 @@ if __name__ == "__main__":
mockcfg = open("%s/mock.cfg" % savedir, "w")
mockcfg.write("config_opts['root'] = 'chroot'\n")
mockcfg.write("config_opts['target_arch'] = '%s'\n" % arch)
- mockcfg.write("config_opts['chroot_setup_cmd'] = 'install %s shadow-utils abrt-addon-ccpp gdb'\n" % packages)
+ mockcfg.write("config_opts['chroot_setup_cmd'] = 'install %s shadow-utils gdb'\n" % packages)
mockcfg.write("config_opts['basedir'] = '%s'\n" % workdir)
mockcfg.write("config_opts['plugin_conf']['ccache_enable'] = False\n")
mockcfg.write("config_opts['plugin_conf']['yum_cache_enable'] = False\n")
@@ -186,12 +201,6 @@ if __name__ == "__main__":
mockcfg.write("baseurl=file://%s/%s-%s-%s-updates-testing-debuginfo/\n" % (CONFIG["RepoDir"], distribution, version, arch))
mockcfg.write("failovermethod=priority\n")
mockcfg.write("\n")
- # custom ABRT repo with ABRT 2.0 binaries - obsolete after release of ABRT 2.0
- mockcfg.write("[abrt]\n")
- mockcfg.write("name=abrt\n")
- mockcfg.write("baseurl=http://repos.fedorapeople.org/repos/mtoman/abrt20/%s-%s/%s/\n" % (distribution, version, arch))
- mockcfg.write("failovermethod=priority\n")
- mockcfg.write("\n")
mockcfg.write("\"\"\"\n")
mockcfg.close()
except Exception as ex:
@@ -236,9 +245,21 @@ if __name__ == "__main__":
# generate backtrace
LOG.write("Generating backtrace... ")
- retrace_run(28, ["mock", "shell", "-r", mockr, "--", "/usr/bin/abrt-action-generate-backtrace", "-d", "/var/spool/abrt/crash/"])
- retrace_run(29, ["mock", "-r", mockr, "--copyout", "/var/spool/abrt/crash/backtrace", savedir])
- retrace_run(30, ["chmod", "a+r", "%s/backtrace" % savedir])
+ backtrace = run_gdb(savedir)
+
+ if not backtrace:
+ LOG.write("Error\n")
+ LOG.close()
+ sys.exit(29)
+
+ try:
+ bt_file = open("%s/backtrace" % savedir, "w")
+ bt_file.write(backtrace)
+ bt_file.close()
+ except Exception as ex:
+ LOG.write("Error: %s.\n" % ex)
+ LOG.close()
+ sys.exit(30)
LOG.write("OK\n")