summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Moskovcak <jmoskovc@redhat.com>2011-05-18 16:55:40 +0200
committerJiri Moskovcak <jmoskovc@redhat.com>2011-05-18 16:55:40 +0200
commitbccd10f39589870673ffd09de6bc09d6e00fab72 (patch)
tree43d0f2e39cb62718ff44522ca6ddca389ac84a81
parent826900355023fcfef39cc91721e681cf558a11f6 (diff)
downloadabrt-bccd10f39589870673ffd09de6bc09d6e00fab72.tar.gz
abrt-bccd10f39589870673ffd09de6bc09d6e00fab72.tar.xz
abrt-bccd10f39589870673ffd09de6bc09d6e00fab72.zip
report C API improvements
-rw-r--r--src/applet/applet_gtk.c2
-rw-r--r--src/gui-gtk/abrt-gtk.c53
-rw-r--r--src/include/report/problem_data.h2
-rw-r--r--src/include/report/report.h10
-rw-r--r--src/lib/problem_data.c32
-rw-r--r--src/lib/report.c162
6 files changed, 227 insertions, 34 deletions
diff --git a/src/applet/applet_gtk.c b/src/applet/applet_gtk.c
index 524aca7c..59c21ef8 100644
--- a/src/applet/applet_gtk.c
+++ b/src/applet/applet_gtk.c
@@ -86,7 +86,7 @@ static void action_report(NotifyNotification *notification, gchar *action, gpoin
struct applet *applet = (struct applet *)user_data;
if (applet->ap_daemon_running)
{
- analyze_and_report_dir(applet->ap_last_crash_id);
+ analyze_and_report_dir(applet->ap_last_crash_id, NOWAIT);
GError *err = NULL;
notify_notification_close(notification, &err);
if (err != NULL)
diff --git a/src/gui-gtk/abrt-gtk.c b/src/gui-gtk/abrt-gtk.c
index df94485e..a44ca685 100644
--- a/src/gui-gtk/abrt-gtk.c
+++ b/src/gui-gtk/abrt-gtk.c
@@ -29,6 +29,7 @@ static const char help_uri[] = "http://docs.fedoraproject.org/en-US/"
static GtkListStore *s_dumps_list_store;
static GtkWidget *s_treeview;
static GtkWidget *g_main_window;
+static GtkWidget *s_report_window;
enum
{
@@ -113,7 +114,7 @@ static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTre
gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir);
const char *dirname= g_value_get_string(&d_dir);
- analyze_and_report_dir(dirname);
+ analyze_and_report_dir(dirname, NOWAIT);
}
}
}
@@ -184,6 +185,53 @@ static void on_menu_help_cb(GtkMenuItem *menuitem, gpointer unused)
gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL);
}
+static void on_button_send_cb(GtkWidget *button, gpointer data)
+{
+ GtkTextView *tev = GTK_TEXT_VIEW(data);
+ GtkTextBuffer *buf = gtk_text_view_get_buffer(tev);
+ GtkTextIter it_start;
+ GtkTextIter it_end;
+ gtk_text_buffer_get_start_iter(buf, &it_start);
+ gtk_text_buffer_get_end_iter(buf, &it_end);
+ gchar *text = gtk_text_buffer_get_text(buf,
+ &it_start,
+ &it_end,
+ false);
+
+ problem_data_t *pd = new_problem_data();
+
+ if (strlen(text) > 0)
+ {
+ add_to_problem_data(pd, "description", text);
+ }
+
+ /* why it doesn't want to hide before report ends? */
+ gtk_widget_destroy(s_report_window);
+
+ int status = report(pd);
+ VERB1 log("Reporting finished with status: %i", status);
+ free_problem_data(pd);
+}
+
+static void on_menu_report_cb(GtkMenuItem *menuitem, gpointer unused)
+{
+
+ s_report_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(s_report_window), _("Problem description"));
+ gtk_window_set_default_size(GTK_WINDOW(s_report_window), 400, 400);
+ GtkWidget *vbox = gtk_vbox_new(false, 0);
+ GtkWidget *button_send = gtk_button_new_with_label(_("Send"));
+ GtkWidget *tev = gtk_text_view_new();
+ g_signal_connect(button_send, "clicked", G_CALLBACK(on_button_send_cb), tev);
+
+ gtk_box_pack_start(GTK_BOX(vbox), tev, true, true, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), button_send, false, false, 5);
+
+ gtk_container_add(GTK_CONTAINER(s_report_window), vbox);
+
+ gtk_widget_show_all(s_report_window);
+}
+
static void on_menu_about_cb(GtkMenuItem *menuitem, gpointer unused)
{
static const char copyright_str[] = "Copyright © 2009, 2010, 2011 Red Hat, Inc";
@@ -330,12 +378,15 @@ GtkWidget *create_menu(void)
/* help submenu */
GtkWidget *help_submenu = gtk_menu_new();
GtkWidget *online_help_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, NULL);
+ GtkWidget *report_problem_item = gtk_menu_item_new_with_label(_("Report problem with ABRT"));
GtkWidget *about_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), online_help_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), report_problem_item);
gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), about_item);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_item), help_submenu);
g_signal_connect(online_help_item, "activate", G_CALLBACK(on_menu_help_cb), NULL);
+ g_signal_connect(report_problem_item, "activate", G_CALLBACK(on_menu_report_cb), NULL);
g_signal_connect(about_item, "activate", G_CALLBACK(on_menu_about_cb), NULL);
return menu;
diff --git a/src/include/report/problem_data.h b/src/include/report/problem_data.h
index 1481654f..c805c37a 100644
--- a/src/include/report/problem_data.h
+++ b/src/include/report/problem_data.h
@@ -51,6 +51,8 @@ typedef GHashTable problem_data_t;
problem_data_t *new_problem_data(void);
+void add_basics_to_problem_data(problem_data_t *pd);
+
static inline void free_problem_data(problem_data_t *problem_data)
{
if (problem_data)
diff --git a/src/include/report/report.h b/src/include/report/report.h
index 11d19687..f57d5277 100644
--- a/src/include/report/report.h
+++ b/src/include/report/report.h
@@ -21,16 +21,22 @@
#include "problem_data.h"
+enum {
+ NOWAIT = 0,
+ WAIT = (1 << 0), /* wait for report to finish and reload the problem data */
+};
+
+
/* analyzes AND reports a problem saved on disk
* - takes user through all the steps in reporting wizard
*/
-int analyze_and_report_dir(const char* dirname);
+int analyze_and_report_dir(const char* dirname, int flags);
/* analyzes AND reports a problem stored in problem_data_t
* it's first saved to /tmp and then processed as a dump_dir
* - takes user through all the steps in reporting wizard
*/
-int analyze_and_report(problem_data_t *pd);
+int analyze_and_report(problem_data_t *pd, int flags);
/* reports a problem saved on disk
* - shows only reporter selector and progress
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 42dc770d..657044bb 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -57,6 +57,38 @@ problem_data_t *new_problem_data(void)
free, free_problem_item);
}
+void add_basics_to_problem_data(problem_data_t *pd)
+{
+ const char *analyzer = get_problem_item_content_or_NULL(pd, FILENAME_ANALYZER);
+ if (analyzer == NULL)
+ add_to_problem_data(pd, "analyzer", "libreport");
+
+ pid_t pid = getpid();
+ if (pid > 0)
+ {
+ char buf[PATH_MAX+1];
+ char *exe = xasprintf("/proc/%u/exe", pid);
+ ssize_t read = readlink(exe, buf, PATH_MAX);
+ if (read > 0)
+ {
+ buf[read] = 0;
+ VERB2 log("reporting initiated from: %s\n", buf);
+ add_to_problem_data(pd, FILENAME_EXECUTABLE, buf);
+ }
+ free(exe);
+
+//#ifdef WITH_RPM
+ /* FIXME: component should be taken from rpm using
+ * rpm -qf executable
+ */
+ /* Fedora/RHEL rpm specific piece of code */
+ const char *component = get_problem_item_content_or_NULL(pd, FILENAME_ANALYZER);
+ if(component == NULL) // application didn't specify component
+ add_to_problem_data(pd, FILENAME_COMPONENT, "abrt");
+//#endif
+ }
+}
+
void add_to_problem_data_ext(problem_data_t *problem_data,
const char *name,
const char *content,
diff --git a/src/lib/report.c b/src/lib/report.c
index a3ba6e96..1a0125ec 100644
--- a/src/lib/report.c
+++ b/src/lib/report.c
@@ -18,12 +18,46 @@
*/
#include "abrtlib.h"
+#include "report.h"
-int analyze_and_report_dir(const char* dirname)
+static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput)
{
+ unsigned char hash_bytes[SHA1_RESULT_LEN];
+ sha1_ctx_t sha1ctx;
+ sha1_begin(&sha1ctx);
+ sha1_hash(&sha1ctx, pInput, strlen(pInput));
+ sha1_end(&sha1ctx, hash_bytes);
+
+ unsigned len = SHA1_RESULT_LEN;
+ unsigned char *s = hash_bytes;
+ char *d = hash_str;
+ while (len)
+ {
+ *d++ = "0123456789abcdef"[*s >> 4];
+ *d++ = "0123456789abcdef"[*s & 0xf];
+ s++;
+ len--;
+ }
+ *d = '\0';
+ //log("hash:%s str:'%s'", hash_str, pInput);
+}
+
+static void generate_hash_for_all(gpointer key, gpointer value, gpointer user_data)
+{
+ problem_item *pi = (problem_item *)value;
+ char *hash_str = (char *)user_data;
+ create_hash(hash_str, pi->content);
+}
+
+static int run_reporter_ui(char **args, int flags)
+{
+ char path[PATH_MAX+1];
/*
- if is isatty -> run cli reporter
+ if is isatty
+ -> run cli reporter
+ path = "cli"
*/
+
pid_t pid = vfork();
if (pid == 0)
{
@@ -34,66 +68,135 @@ int analyze_and_report_dir(const char* dirname)
* Note that we do it in the child, so the parent is never affected.
*/
signal(SIGCHLD, SIG_DFL); // applet still set it to SIG_IGN
- VERB1 log("Executing: %s %s", "bug-reporting-wizard", dirname);
- execl(BIN_DIR"/bug-reporting-wizard", "bug-reporting-wizard", "--", dirname, NULL);
- // note the -o in options which means --report-only
+ strncpy(path, BIN_DIR"/bug-reporting-wizard", PATH_MAX);
+ path[PATH_MAX] = 0;
+ VERB1 log("Executing: %s", path);
+ execv(path, args);
/* Did not find abrt-gui in installation directory. Oh well */
/* Trying to find it in PATH */
- execlp("bug-reporting-wizard", "bug-reporting-wizard", "--", dirname, NULL);
+ strncpy(path, "bug-reporting-wizard", PATH_MAX);
+ execvp(path, args);
perror_msg_and_die("Can't execute %s", "bug-reporting-wizard");
}
+ else if(pid > 0)
+ {
+ if (flags & WAIT)
+ {
+ int status = 0;
+ pid_t p = waitpid(pid, &status, WUNTRACED);
+ if(p == -1)
+ {
+ error_msg("can't waitpid");
+ return EXIT_FAILURE;
+ }
+ if (WIFEXITED(status))
+ {
+ VERB2 log("reporting finished with exitcode: status=%d\n", WEXITSTATUS(status));
+ return WEXITSTATUS(status);
+ }
+ else if (WIFSIGNALED(status))
+ {
+ VERB2 log("reporting killed by signal %d\n", WTERMSIG(status));
+ }
+ else if (WIFSTOPPED(status))
+ {
+ /* should parent continue when the reporting is stopped??*/
+ VERB2 log("reporting stopped by signal %d\n", WSTOPSIG(status));
+ }
+ else if (WIFCONTINUED(status))
+ {
+ VERB2 log("continued\n");
+ }
+ }
+ }
+ return 0;
+}
+
+int analyze_and_report_dir(const char* dirname, int flags)
+{
+ char *args[4];
+
+ args[0] = (char *)"bug-reporting-wizard";
+ args[1] = (char *)"--";
+ args[2] = (char *)dirname;
+ args[3] = NULL;
+
+ run_reporter_ui(args, flags);
return 0;
}
/* analyzes AND reports a problem saved on disk
* - takes user through all the steps in reporting wizard
*/
-int analyze_and_report(problem_data_t *pd)
+int analyze_and_report(problem_data_t *pd, int flags)
{
+ int result = 0;
struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */);
if (!dd)
return -1;
char *dir_name = strdup(dd->dd_dirname);
dd_close(dd);
VERB2 log("Temp problem dir: '%s'\n", dir_name);
- analyze_and_report_dir(dir_name);
+ result = analyze_and_report_dir(dir_name, flags);
+
+ /* if we wait for reporter to finish, we can try to clean the tmp dir */
+ if (flags & WAIT)
+ {
+ dd = dd_opendir(dir_name, 0);
+ if (dd)
+ {
+ if (dd_delete(dd) != 0)
+ {
+ error_msg("Can't remove tmp dir: %s", dd->dd_dirname);
+ }
+ }
+ }
free(dir_name);
- return 0;
+ return result;
}
+/* report() and report_dir() don't take flags, because in all known use-cases
+ * it doesn't make sense to not wait for the result
+ *
+*/
+
/* reports a problem saved on disk
* - shows only reporter selector and progress
*/
int report_dir(const char* dirname)
{
- pid_t pid = vfork();
- if (pid == 0)
- {
- /* Some callers set SIGCHLD to SIG_IGN.
- * However, reporting spawns chils processes.
- * Suppressing chil death notification terribly confuses some of them.
- * Just in case, undo it.
- * Note that we do it in the child, so the parent is never affected.
- */
- signal(SIGCHLD, SIG_DFL); // applet still set it to SIG_IGN
- VERB1 log("Executing: %s %s", "bug-reporting-wizard", dirname);
- execl(BIN_DIR"/bug-reporting-wizard", "bug-reporting-wizard",
- "-o", "--", dirname, NULL);
- // note the -o in options which means --report-only
- /* Did not find abrt-gui in installation directory. Oh well */
- /* Trying to find it in PATH */
- execlp("bug-reporting-wizard", "bug-reporting-wizard",
- "-o", "--", dirname, NULL);
- perror_msg_and_die("Can't execute %s", "bug-reporting-wizard");
- }
+ char *args[5];
+
+ args[0] = (char *)"bug-reporting-wizard";
+ args[1] = (char *)"--report-only";
+ args[2] = (char *)"--";
+ args[3] = (char *)dirname;
+ args[4] = NULL;
+
+ int flags = WAIT;
+ run_reporter_ui(args, flags);
return 0;
}
int report(problem_data_t *pd)
{
+ /* create hash from all components, so we at least eliminate the exact same
+ * reports
+ */
+ char hash_str[SHA1_RESULT_LEN*2 + 1];
+ g_hash_table_foreach(pd, &generate_hash, hash_str);
+ add_to_problem_data(pd, FILENAME_DUPHASH, hash_str);
+
+ /* adds:
+ * analyzer:libreport
+ * executable:readlink(/proc/<pid>/exe)
+ * tries to guess component
+ */
+ add_basics_to_problem_data(pd);
struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */);
if (!dd)
return -1;
+ dd_create_basic_files(dd, getuid());
char *dir_name = xstrdup(dd->dd_dirname);
dd_close(dd);
VERB2 log("Temp problem dir: '%s'\n", dir_name);
@@ -102,4 +205,3 @@ int report(problem_data_t *pd)
return 0;
}
-