From 7e19d433643bd94cd485a1b6dbf7bf042adba48e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 28 Mar 2014 22:17:05 -0500 Subject: don't create menuitems for phantom users. --- src/service.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/service.c b/src/service.c index 68fbc50..a153306 100644 --- a/src/service.c +++ b/src/service.c @@ -576,12 +576,20 @@ create_switch_section (IndicatorSessionService * self, int profile) for (i=0; ilen; ++i) { const IndicatorSessionUser * u = g_ptr_array_index (users, i); + const char * label; GVariant * serialized_icon; if (profile == PROFILE_LOCKSCREEN && u->is_current_user) continue; - item = g_menu_item_new (get_user_label (u), NULL); + /* Sometimes we get a user without a username? bus hiccup. + I can't reproduce it, but let's not confuse users with + a meaningless menuitem. (see bug #1263228) */ + label = get_user_label (u); + if (!label || !*label) + continue; + + item = g_menu_item_new (label, NULL); g_menu_item_set_action_and_target (item, "indicator.switch-to-user", "s", u->user_name); g_menu_item_set_attribute (item, "x-canonical-type", "s", "indicator.user-menu-item"); -- cgit v1.2.3 From 8401862ae66ac619f517cd4bb37a07c6847f625c Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 28 Mar 2014 22:21:35 -0500 Subject: silence compiler warning --- src/service.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/service.c b/src/service.c index a153306..b3b0641 100644 --- a/src/service.c +++ b/src/service.c @@ -250,15 +250,15 @@ on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, static void maybe_add_users (IndicatorSessionService * self) { - if (!show_user_list (self)) - return; - - GList * uids, * l; + if (show_user_list (self)) + { + GList * uids, * l; - uids = indicator_session_users_get_uids (self->priv->backend_users); - for (l=uids; l!=NULL; l=l->next) - add_user (self, GPOINTER_TO_UINT(l->data)); - g_list_free (uids); + uids = indicator_session_users_get_uids (self->priv->backend_users); + for (l=uids; l!=NULL; l=l->next) + add_user (self, GPOINTER_TO_UINT(l->data)); + g_list_free (uids); + } } -- cgit v1.2.3 From f84deabcfd27e09695249eaed6295e3d5fea19d3 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 2 Apr 2014 10:02:26 -0500 Subject: copy recoverable-problem.[ch] from url-dispatcher 0.1+14.04.20140331.1-0ubuntu1 --- src/CMakeLists.txt | 2 + src/recoverable-problem.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++ src/recoverable-problem.h | 26 ++++++++ 3 files changed, 195 insertions(+) create mode 100644 src/recoverable-problem.c create mode 100644 src/recoverable-problem.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a00b6f1..9528f7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ add_library (libindicatorsessionservice STATIC actions.h guest.c guest.h + recoverable-problem.c + recoverable-problem.h service.c service.h users.c diff --git a/src/recoverable-problem.c b/src/recoverable-problem.c new file mode 100644 index 0000000..7aff163 --- /dev/null +++ b/src/recoverable-problem.c @@ -0,0 +1,167 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Ted Gould + */ + +#include "recoverable-problem.h" +#include +#include +#include + +/* Helpers to ensure we write nicely */ +static void +write_string (int fd, + const gchar *string) +{ + int res; + do + res = write (fd, string, strlen (string)); + while (G_UNLIKELY (res == -1 && errno == EINTR)); +} + +/* Make NULLs fast and fun! */ +static void +write_null (int fd) +{ + int res; + do + res = write (fd, "", 1); + while (G_UNLIKELY (res == -1 && errno == EINTR)); +} + +/* Child watcher */ +static gboolean +apport_child_watch (GPid pid G_GNUC_UNUSED, gint status G_GNUC_UNUSED, gpointer user_data) +{ + g_main_loop_quit((GMainLoop *)user_data); + return FALSE; +} + +static gboolean +apport_child_timeout (gpointer user_data) +{ + g_warning("Recoverable Error Reporter Timeout"); + g_main_loop_quit((GMainLoop *)user_data); + return FALSE; +} + +/* Code to report an error */ +void +report_recoverable_problem (const gchar * signature, GPid report_pid, gboolean wait, gchar * additional_properties[]) +{ + GSpawnFlags flags; + gboolean first; + GError * error = NULL; + gint error_stdin = 0; + GPid pid = 0; + gchar * pid_str = NULL; + gchar ** argv = NULL; + gchar * argv_nopid[2] = { + "/usr/share/apport/recoverable_problem", + NULL + }; + gchar * argv_pid[4] = { + "/usr/share/apport/recoverable_problem", + "-p", + NULL, /* put pid_str when allocated here */ + NULL + }; + + + argv = (gchar **)argv_nopid; + + if (report_pid != 0) { + pid_str = g_strdup_printf("%d", report_pid); + argv_pid[2] = pid_str; + argv = (gchar**)argv_pid; + } + + flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; + if (wait) { + flags |= G_SPAWN_DO_NOT_REAP_CHILD; + } + + g_spawn_async_with_pipes(NULL, /* cwd */ + argv, + NULL, /* envp */ + flags, + NULL, NULL, /* child setup func */ + &pid, + &error_stdin, + NULL, /* stdout */ + NULL, /* stderr */ + &error); + + if (error != NULL) { + g_warning("Unable to report a recoverable error: %s", error->message); + g_error_free(error); + } + + first = TRUE; + + if (error_stdin != 0 && signature != NULL) { + write_string(error_stdin, "DuplicateSignature"); + write_null(error_stdin); + write_string(error_stdin, signature); + + first = FALSE; + } + + if (error_stdin != 0 && additional_properties != NULL) { + gint i; + for (i = 0; additional_properties[i] != NULL; i++) { + if (!first) { + write_null(error_stdin); + } else { + first = FALSE; + } + + write_string(error_stdin, additional_properties[i]); + } + } + + if (error_stdin != 0) { + close(error_stdin); + } + + if (wait && pid != 0) { + GSource * child_source, * timeout_source; + GMainContext * context = g_main_context_new(); + GMainLoop * loop = g_main_loop_new(context, FALSE); + + child_source = g_child_watch_source_new(pid); + g_source_attach(child_source, context); + g_source_set_callback(child_source, (GSourceFunc)apport_child_watch, loop, NULL); + + timeout_source = g_timeout_source_new_seconds(5); + g_source_attach(timeout_source, context); + g_source_set_callback(timeout_source, apport_child_timeout, loop, NULL); + + g_main_loop_run(loop); + + g_source_destroy(timeout_source); + g_source_destroy(child_source); + g_main_loop_unref(loop); + g_main_context_unref(context); + + g_spawn_close_pid(pid); + } + + g_free(pid_str); + + return; +} diff --git a/src/recoverable-problem.h b/src/recoverable-problem.h new file mode 100644 index 0000000..e5fadab --- /dev/null +++ b/src/recoverable-problem.h @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Ted Gould + */ + +#include + +void report_recoverable_problem (const gchar * signature, + GPid report_pid, + gboolean wait, + gchar * additional_properties[]); + -- cgit v1.2.3 From 8416dc9bee649ce728678e6cdadfd08a38aee548 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 2 Apr 2014 10:02:59 -0500 Subject: if we encounter a user for whom we can't find a name, report it to apport as a recoverable error. --- debian/control | 1 + src/service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/debian/control b/debian/control index fb067cc..eb148bf 100644 --- a/debian/control +++ b/debian/control @@ -32,6 +32,7 @@ Recommends: indicator-applet (>= 0.2) | indicator-renderer, unity-control-center | gnome-control-center, unity-control-center-signon | gnome-control-center-signon Suggests: lightdm, + apport, zenity Description: indicator showing session management, status and user switching This indicator is designed to be placed on the right side of a panel and diff --git a/src/service.c b/src/service.c index b3b0641..7484134 100644 --- a/src/service.c +++ b/src/service.c @@ -21,6 +21,7 @@ #include #include "backend.h" +#include "recoverable-problem.h" #include "service.h" #define BUS_NAME "com.canonical.indicator.session" @@ -104,6 +105,7 @@ struct _IndicatorSessionServicePrivate GSimpleAction * user_switcher_action; GSimpleAction * guest_switcher_action; GHashTable * users; + GHashTable * reported_users; guint rebuild_id; int rebuild_flags; GDBusConnection * conn; @@ -488,6 +490,49 @@ serialize_icon_file (const gchar * filename) return serialized_icon; } +static void +report_unusable_user (IndicatorSessionService * self, const IndicatorSessionUser * u) +{ + const priv_t * const p = self->priv; + gpointer key; + + g_return_if_fail(u != NULL); + + key = GUINT_TO_POINTER(u->uid); + + if (!g_hash_table_contains (p->reported_users, key)) + { + gchar * uid_str; + GPtrArray * additional; + const gchar * const error_name = "indicator-session-unknown-user-error"; + + /* don't spam apport with duplicates */ + g_hash_table_add (p->reported_users, key); + + uid_str = g_strdup_printf("%u", u->uid); + + additional = g_ptr_array_new (); /* null-terminated key/value pair strs */ + g_ptr_array_add (additional, "uid"); + g_ptr_array_add (additional, uid_str); + g_ptr_array_add (additional, "icon_file"); + g_ptr_array_add (additional, u->icon_file ? u->icon_file : "(null)"); + g_ptr_array_add (additional, "is_current_user"); + g_ptr_array_add (additional, u->is_current_user ? "true" : "false"); + g_ptr_array_add (additional, "is_logged_in"); + g_ptr_array_add (additional, u->is_logged_in ? "true" : "false"); + g_ptr_array_add (additional, "real_name"); + g_ptr_array_add (additional, u->real_name ? u->real_name : "(null)"); + g_ptr_array_add (additional, "user_name"); + g_ptr_array_add (additional, u->user_name ? u->user_name : "(null)"); + g_ptr_array_add (additional, NULL); /* null termination */ + report_recoverable_problem(error_name, (GPid)0, FALSE, (gchar**)additional->pdata); + + /* cleanup */ + g_free (uid_str); + g_ptr_array_free (additional, TRUE); + } +} + static GMenuModel * create_switch_section (IndicatorSessionService * self, int profile) { @@ -587,7 +632,10 @@ create_switch_section (IndicatorSessionService * self, int profile) a meaningless menuitem. (see bug #1263228) */ label = get_user_label (u); if (!label || !*label) + { + report_unusable_user (self, u); continue; + } item = g_menu_item_new (label, NULL); g_menu_item_set_action_and_target (item, "indicator.switch-to-user", "s", u->user_name); @@ -1103,6 +1151,9 @@ indicator_session_service_init (IndicatorSessionService * self) g_direct_equal, NULL, (GDestroyNotify)indicator_session_user_free); + + p->reported_users = g_hash_table_new (g_direct_hash, g_direct_equal); + maybe_add_users (self); init_gactions (self); @@ -1243,6 +1294,7 @@ my_dispose (GObject * o) } g_clear_pointer (&p->users, g_hash_table_destroy); + g_clear_pointer (&p->reported_users, g_hash_table_destroy); g_clear_object (&p->backend_users); g_clear_object (&p->backend_guest); g_clear_object (&p->backend_actions); -- cgit v1.2.3