From dc41728b9c4ec35fb7bd41cdc646b77dcb41f6dd Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 Oct 2017 15:45:01 -0400 Subject: [PATCH 06/13] daemon: add new HasMultipleUsers and HasNoUsers properties Every gnome-shell instance wants to know if the system has multiple users or not, in order to know whether or not to show the 'Switch User' feature in the menu. accountsservice doesn't provide this information directly, though, so libaccountsservice instead requests a list of all users on the system and counts the provided list, filtering out system users. This is a lot of work for every gnome-shell instance to do, when it doesn't actually need the list of users at all. This adds a new property HasMultipleUsers which libaccountsservice can watch for instead. For good measure, this commit also adds a HasNoUsers boolean which can be used to know whether or not to start gnome-initial-setup. --- data/org.freedesktop.Accounts.xml | 20 ++++++++++++++++++++ src/daemon.c | 24 +++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/data/org.freedesktop.Accounts.xml b/data/org.freedesktop.Accounts.xml index 692540a..ed7db50 100644 --- a/data/org.freedesktop.Accounts.xml +++ b/data/org.freedesktop.Accounts.xml @@ -197,32 +197,52 @@ Emitted when a user is added. Object path of the user that was deleted. Emitted when a user is deleted. The version of the running daemon. + + + + + Whether or not the system has no users + + + + + + + + + + Whether or not the system has multiple users + + + + + diff --git a/src/daemon.c b/src/daemon.c index 6e3e4b3..a4e18df 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -35,60 +35,61 @@ #include #include #include #include #include #include #include #include #include #include "user-classify.h" #include "wtmp-helper.h" #include "daemon.h" #include "util.h" #define PATH_PASSWD "/etc/passwd" #define PATH_SHADOW "/etc/shadow" #define PATH_GROUP "/etc/group" #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" enum { PROP_0, PROP_DAEMON_VERSION }; struct DaemonPrivate { GDBusConnection *bus_connection; GHashTable *users; + gsize number_of_normal_users; GList *explicitly_requested_users; User *autologin; GFileMonitor *passwd_monitor; GFileMonitor *shadow_monitor; GFileMonitor *group_monitor; GFileMonitor *gdm_monitor; GFileMonitor *wtmp_monitor; guint reload_id; guint autologin_id; PolkitAuthority *authority; GHashTable *extension_ifaces; }; typedef struct passwd * (* EntryGeneratorFunc) (Daemon *, GHashTable *, gpointer *, struct spwd **shadow_entry); static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface); G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init)); #define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate)) static const GDBusErrorEntry accounts_error_entries[] = { { ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" }, { ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" }, { ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" }, @@ -395,98 +396,115 @@ load_entries (Daemon *daemon, /* freeze & update users not already in the new list */ g_object_freeze_notify (G_OBJECT (user)); user_update_from_pwent (user, pwent, spent); g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user); g_debug ("loaded user: %s", user_get_user_name (user)); } if (!explicitly_requested) { user_set_cached (user, TRUE); } } /* Generator should have cleaned up */ g_assert (generator_state == NULL); } static GHashTable * create_users_hash_table (void) { return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } static void reload_users (Daemon *daemon) { + AccountsAccounts *accounts = ACCOUNTS_ACCOUNTS (daemon); + gboolean had_no_users, has_no_users, had_multiple_users, has_multiple_users; GHashTable *users; GHashTable *old_users; GHashTable *local; GHashTableIter iter; + gsize number_of_normal_users = 0; gpointer name; User *user; /* Track the users that we saw during our (re)load */ users = create_users_hash_table (); /* * NOTE: As we load data from all the sources, notifies are * frozen in load_entries() and then thawed as we process * them below. */ /* Load the local users into our hash table */ load_entries (daemon, users, FALSE, entry_generator_fgetpwent); local = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_iter_init (&iter, users); while (g_hash_table_iter_next (&iter, &name, NULL)) g_hash_table_add (local, name); /* and add users to hash table that were explicitly requested */ load_entries (daemon, users, TRUE, entry_generator_requested_users); /* Now add/update users from other sources, possibly non-local */ load_entries (daemon, users, FALSE, entry_generator_cachedir); wtmp_helper_update_login_frequencies (users); - /* Mark which users are local, which are not */ + /* Count the non-system users. Mark which users are local, which are not. */ g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) + while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { + if (!user_get_system_account (user)) + number_of_normal_users++; user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL); - + } g_hash_table_destroy (local); + had_no_users = accounts_accounts_get_has_no_users (accounts); + has_no_users = number_of_normal_users == 0; + + if (had_no_users != has_no_users) + accounts_accounts_set_has_no_users (accounts, has_no_users); + + had_multiple_users = accounts_accounts_get_has_multiple_users (accounts); + has_multiple_users = number_of_normal_users > 1; + + if (had_multiple_users != has_multiple_users) + accounts_accounts_set_has_multiple_users (accounts, has_multiple_users); + /* Swap out the users */ old_users = daemon->priv->users; daemon->priv->users = users; /* Remove all the old users */ g_hash_table_iter_init (&iter, old_users); while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { User *refreshed_user; refreshed_user = g_hash_table_lookup (users, name); if (!refreshed_user || !user_get_cached (refreshed_user)) { user_unregister (user); accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon), user_get_object_path (user)); } } /* Register all the new users */ g_hash_table_iter_init (&iter, users); while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { User *stale_user; stale_user = g_hash_table_lookup (old_users, name); if (!stale_user || !user_get_cached (stale_user) && user_get_cached (user)) { user_register (user); accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon), user_get_object_path (user)); } -- 2.14.1