diff options
author | João Paulo Rechi Vita <jprvita@endlessm.com> | 2019-04-15 13:38:59 -0700 |
---|---|---|
committer | João Paulo Rechi Vita <jprvita@endlessm.com> | 2019-04-17 11:53:44 -0700 |
commit | e88a50bd031b816e47200885f6a6e1cc1c1ff4d1 (patch) | |
tree | 0827411ff16ea1f375e5b4d83e8d39200db49eed | |
parent | f381c68321758d81c496d152cdfd6838aeb2f01b (diff) |
daemon: Wait for reload before servicing list_cached_users
When /etc/passwd, /etc/shadow or /etc/group are changed outside of
AccountsService, the cache reload is delayed by 500 ms so subsequent
changes to these files are process seen together and AccountsService has
a consistent view of the data (since after one of these files is changed
the others may change too).
If ListCachedUsers is called in this 500 ms window,
finish_list_cached_users will be executed before reload_users_timeout
has been dispatched, since its added to the mainloop as an idler and at
point there is nothing preventing it from being executed. This makes
finish_list_cached_users only be attached to the mainloop after
reload_users_timeout has been dispatched.
This bug was introduced by commit 4e3fad33 when the 500 ms delay was
implemented.
Closes: #71
-rw-r--r-- | src/daemon.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/src/daemon.c b/src/daemon.c index 2a9e1b5..c52bda3 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -72,6 +72,8 @@ typedef struct { GFileMonitor *gdm_monitor; GFileMonitor *wtmp_monitor; + GQueue *pending_list_cached_users; + guint reload_id; guint autologin_id; @@ -81,6 +83,15 @@ typedef struct { typedef struct passwd * (* EntryGeneratorFunc) (Daemon *, GHashTable *, gpointer *, struct spwd **shadow_entry); +typedef struct { + Daemon *daemon; + GDBusMethodInvocation *context; +} ListUserData; + +static void finish_list_cached_users (ListUserData *data); + +static void list_user_data_free (ListUserData *data); + static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface); G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_ADD_PRIVATE (Daemon) G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init)); @@ -546,6 +557,10 @@ reload_users_timeout (Daemon *daemon) reload_users (daemon); priv->reload_id = 0; + g_queue_foreach (priv->pending_list_cached_users, + (GFunc) finish_list_cached_users, NULL); + g_queue_clear (priv->pending_list_cached_users); + return FALSE; } @@ -716,6 +731,8 @@ daemon_init (Daemon *daemon) priv->users = create_users_hash_table (); + priv->pending_list_cached_users = g_queue_new (); + priv->passwd_monitor = setup_monitor (daemon, PATH_PASSWD, on_users_monitor_changed); @@ -751,6 +768,9 @@ daemon_finalize (GObject *object) if (priv->bus_connection != NULL) g_object_unref (priv->bus_connection); + g_queue_free_full (priv->pending_list_cached_users, + (GDestroyNotify) list_user_data_free); + g_list_free_full (priv->explicitly_requested_users, g_free); g_hash_table_destroy (priv->users); @@ -946,12 +966,6 @@ daemon_find_user_by_name (AccountsAccounts *accounts, return TRUE; } -typedef struct { - Daemon *daemon; - GDBusMethodInvocation *context; -} ListUserData; - - static ListUserData * list_user_data_new (Daemon *daemon, GDBusMethodInvocation *context) @@ -973,10 +987,9 @@ list_user_data_free (ListUserData *data) g_free (data); } -static gboolean -finish_list_cached_users (gpointer user_data) +static void +finish_list_cached_users (ListUserData *data) { - ListUserData *data = user_data; DaemonPrivate *priv = daemon_get_instance_private (data->daemon); g_autoptr(GPtrArray) object_paths = NULL; GHashTableIter iter; @@ -1012,8 +1025,6 @@ finish_list_cached_users (gpointer user_data) accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata); list_user_data_free (data); - - return FALSE; } static gboolean @@ -1027,8 +1038,8 @@ daemon_list_cached_users (AccountsAccounts *accounts, data = list_user_data_new (daemon, context); if (priv->reload_id > 0) { - /* reload in progress, wait a bit */ - g_idle_add (finish_list_cached_users, data); + /* reload pending -- finish call in reload_users_timeout */ + g_queue_push_tail (priv->pending_list_cached_users, data); } else { finish_list_cached_users (data); |