From 57895ccd0c6289faada8e5f3327e276ffded46b5 Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Thu, 19 Mar 2015 08:35:38 +0100 Subject: [PATCH] applet: get the list of problems through D-Bus service The default dump location directory is not iterable for regular users. v2: problem_create_app_from_env() will return NULL if envp is NULL, so there is no need to check pi->envp to NULL. V3: unref g_problems_proxy Signed-off-by: Jakub Filak --- src/applet/applet.c | 143 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/src/applet/applet.c b/src/applet/applet.c index d6d581a..b471dbc 100644 --- a/src/applet/applet.c +++ b/src/applet/applet.c @@ -36,6 +36,14 @@ #include "libabrt.h" #include "problem_api.h" +/* 5s timeout*/ +#define ORG_FREEDESKTOP_PROBLEMS_CALL_DEFAULT_TIMEOUT 5000 + +#define ORG_FREEDESKTOP_PROBLEMS_BUS "org.freedesktop.problems" +#define ORG_FREEDESKTOP_PROBLEMS_OBJECT "/org/freedesktop/problems" +#define ORG_FREEDESKTOP_PROBLEMS_INTERFACE "org.freedesktop.problems" +#define ORG_FREEDESKTOP_PROBLEMS_NAMESPACE(member) "org.freedesktop.problems."member + /* libnotify action keys */ #define A_REPORT_REPORT "REPORT" #define A_RESTART_APPLICATION "RESTART" @@ -44,8 +52,8 @@ #define NOTIFICATION_ICON_NAME "face-sad-symbolic" +static GDBusProxy *g_problems_proxy; static GNetworkMonitor *netmon; -static char **s_dirs; static GList *g_deferred_crash_queue; static guint g_deferred_timeout; static bool g_gnome_abrt_available; @@ -110,7 +118,6 @@ typedef struct problem_info { bool foreign; guint count; bool is_packaged; - char *command_line; char **envp; pid_t pid; bool known; @@ -129,6 +136,11 @@ static const char *problem_info_get_dir(problem_info_t *pi) return problem_data_get_content_or_NULL(pi->problem_data, CD_DUMPDIR); } +static const char *problem_info_get_command_line(problem_info_t *pi) +{ + return problem_data_get_content_or_NULL(pi->problem_data, FILENAME_CMDLINE); +} + static void problem_info_set_dir(problem_info_t *pi, const char *dir) { problem_data_add_text_noteditable(pi->problem_data, CD_DUMPDIR, dir); @@ -186,7 +198,6 @@ static void problem_info_unref(gpointer data) return; problem_data_free(pi->problem_data); - g_free(pi->command_line); if (pi->envp) g_strfreev(pi->envp); g_free(pi); @@ -200,6 +211,57 @@ static problem_info_t* problem_info_ref(problem_info_t *pi) return pi; } +static GVariant *dbus_call_sync(GDBusProxy *proxy, const gchar *method, GVariant *args) +{ + GError *error = NULL; + GVariant *const resp = g_dbus_proxy_call_sync(proxy, + method, + args, + G_DBUS_PROXY_FLAGS_NONE, + ORG_FREEDESKTOP_PROBLEMS_CALL_DEFAULT_TIMEOUT, + /* GCancellable */ NULL, + &error); + if (error) + { + error_msg(_("Can't call method '%s' over DBus on path '%s' interface '%s': %s"), + method, + g_dbus_proxy_get_object_path(proxy), + g_dbus_proxy_get_interface_name(proxy), + error->message); + g_error_free(error); + /* resp is NULL in this case */ + } + + + return resp; +} + +static int ofd_problems_get_problems(GList **problems) +{ + /* GetProblems ( IN , OUT as) */ + GVariant *dbus_res = dbus_call_sync(g_problems_proxy, "GetProblems", NULL); + + if (dbus_res == NULL) + return -1; + + GVariant *resp = g_variant_get_child_value(dbus_res, 0); + g_variant_unref(dbus_res); + + const gsize n_results = g_variant_n_children(resp); + for (gsize child = 0; child < n_results; ++child) + { + GVariant *const problem_id = g_variant_get_child_value(resp, child); + + *problems = g_list_prepend(*problems, g_variant_dup_string(problem_id, NULL)); + + g_variant_unref(problem_id); + } + + g_variant_unref(resp); + + return 0; +} + static void run_event_async(problem_info_t *pi, const char *event_name); struct event_processing_state @@ -230,29 +292,6 @@ static void free_event_processing_state(struct event_processing_state *p) g_free(p); } -static GList *add_dirs_to_dirlist(GList *dirlist, const char *dirname) -{ - DIR *dir = opendir(dirname); - if (!dir) - return dirlist; - - struct dirent *dent; - while ((dent = readdir(dir)) != NULL) - { - if (dot_or_dotdot(dent->d_name)) - continue; - char *full_name = concat_path_file(dirname, dent->d_name); - struct stat statbuf; - if (lstat(full_name, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) - dirlist = g_list_prepend(dirlist, full_name); - else - free(full_name); - } - closedir(dir); - - return g_list_reverse(dirlist); -} - /* Compares the problem directories to list saved in * $XDG_CACHE_HOME/abrt/applet_dirlist and updates the applet_dirlist * with updated list. @@ -263,12 +302,10 @@ static GList *add_dirs_to_dirlist(GList *dirlist, const char *dirname) static void new_dir_exists(GList **new_dirs) { GList *dirlist = NULL; - char **pp = s_dirs; - while (*pp) + if (ofd_problems_get_problems(&dirlist) != 0) { - log_notice("Looking for crashes in %s", *pp); - dirlist = add_dirs_to_dirlist(dirlist, *pp); - pp++; + error_msg(_("Failed to get the problem list from Problems D-Bus service.")); + return; } const char *cachedir = g_get_user_cache_dir(); @@ -484,7 +521,7 @@ static void action_restart(NotifyNotification *notification, gchar *action, gpoi } problem_info_t *pi = (problem_info_t *)user_data; - app = problem_create_app_from_cmdline (pi->command_line); + app = problem_create_app_from_cmdline (problem_info_get_command_line(pi)); g_assert (app); if (!g_app_info_launch(G_APP_INFO(app), NULL, NULL, &err)) @@ -575,8 +612,9 @@ static void notify_problem_list(GList *problems) } app = problem_create_app_from_env ((const char **)pi->envp, pi->pid); + if (!app) - app = problem_create_app_from_cmdline (pi->command_line); + app = problem_create_app_from_cmdline (problem_info_get_command_line(pi)); /* For each problem we'll need to know: * - Whether or not the crash happened in an “app” @@ -653,7 +691,7 @@ static void notify_problem_list(GList *problems) } else { - char *binary = problem_get_argv0 (pi->command_line); + char *binary = problem_get_argv0 (problem_info_get_command_line(pi)); notify_body = g_strdup_printf (_("We're sorry, it looks like %s crashed. Please contact the developer if you want to report the issue."), binary); g_free (binary); @@ -950,10 +988,11 @@ static void Crash(GVariant *parameters) problem_data_add_text_noteditable(pi->problem_data, FILENAME_DUPHASH, duphash); if (package_name != NULL && package_name[0] != '\0') problem_data_add_text_noteditable(pi->problem_data, FILENAME_COMPONENT, package_name); + if (command_line != NULL) + problem_data_add_text_noteditable(pi->problem_data, FILENAME_CMDLINE, command_line); pi->foreign = foreign_problem; pi->count = count; pi->is_packaged = (package_name != NULL); - pi->command_line = g_strdup(command_line); pi->envp = (env != NULL) ? g_strsplit (env, "\n", -1) : NULL; pi->pid = (pid != NULL) ? atoi (pid) : -1; free(command_line); @@ -1017,7 +1056,7 @@ name_acquired_handler (GDBusConnection *connection, if (!dd_exist(dd, FILENAME_REPORTED_TO)) { problem_info_t *pi = problem_info_new(new_dirs->data); - const char *elements[] = {FILENAME_UUID, FILENAME_DUPHASH, FILENAME_COMPONENT, FILENAME_NOT_REPORTABLE}; + const char *elements[] = {FILENAME_UUID, FILENAME_DUPHASH, FILENAME_COMPONENT, FILENAME_NOT_REPORTABLE, FILENAME_CMDLINE}; for (size_t i = 0; i < sizeof(elements)/sizeof(*elements); ++i) { @@ -1125,19 +1164,6 @@ int main(int argc, char** argv) load_event_config_data(); load_user_settings("abrt-applet"); - const char *default_dirs[] = { - g_settings_dump_location, - NULL, - NULL, - }; - argv += optind; - if (!argv[0]) - { - default_dirs[1] = concat_path_file(g_get_user_cache_dir(), "abrt/spool"); - argv = (char**)default_dirs; - } - s_dirs = argv; - /* Initialize our (dbus_abrt) machinery by filtering * for signals: * signal sender=:1.73 -> path=/org/freedesktop/problems; interface=org.freedesktop.problems; member=Crash @@ -1151,14 +1177,27 @@ int main(int argc, char** argv) perror_msg_and_die("Can't connect to system dbus: %s", error->message); guint filter_id = g_dbus_connection_signal_subscribe(system_conn, NULL, - "org.freedesktop.problems", + ORG_FREEDESKTOP_PROBLEMS_BUS, "Crash", - "/org/freedesktop/problems", + ORG_FREEDESKTOP_PROBLEMS_OBJECT, NULL, G_DBUS_SIGNAL_FLAGS_NONE, handle_message, NULL, NULL); + g_problems_proxy = g_dbus_proxy_new_sync(system_conn, + G_DBUS_PROXY_FLAGS_NONE, + /* GDBusInterfaceInfo */ NULL, + ORG_FREEDESKTOP_PROBLEMS_BUS, + ORG_FREEDESKTOP_PROBLEMS_OBJECT, + ORG_FREEDESKTOP_PROBLEMS_INTERFACE, + /* GCancellable */ NULL, + &error); + if (g_problems_proxy == NULL) + perror_msg_and_die(_("Can't connect ot DBus bus '"ORG_FREEDESKTOP_PROBLEMS_BUS \ + "' path '"ORG_FREEDESKTOP_PROBLEMS_OBJECT \ + "' interface '"ORG_FREEDESKTOP_PROBLEMS_INTERFACE"': %s"), error->message); + guint name_own_id = g_bus_own_name (G_BUS_TYPE_SESSION, ABRT_DBUS_NAME".applet", G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, @@ -1198,6 +1237,8 @@ int main(int argc, char** argv) */ new_dir_exists(/* new dirs list */ NULL); + g_object_unref(g_problems_proxy); + if (notify_is_initted()) notify_uninit(); -- 2.3.2