340 lines
11 KiB
Diff
340 lines
11 KiB
Diff
From bef4aa0d07924e22c0689d5308802b576d756e19 Mon Sep 17 00:00:00 2001
|
|
From: Ray Strode <rstrode@redhat.com>
|
|
Date: Fri, 24 Mar 2023 12:16:46 -0400
|
|
Subject: [PATCH] daemon: Fix boot delay
|
|
|
|
commit 836a9135fe2d8fdc7d6de3a6d11fb9a5fd05f926 made accountsservice
|
|
reload wtmp less aggressively.
|
|
|
|
Unfortunately, if wtmp is modified during boot, that added latency
|
|
and delay the user list getting loaded.
|
|
|
|
This commit addresses the problem by tracking how pressing the queued
|
|
reload operation is, and makes it happen sooner if a higher priority
|
|
request comes in.
|
|
---
|
|
src/daemon.c | 25 +++++++++++++++++++++++++
|
|
1 file changed, 25 insertions(+)
|
|
|
|
diff --git a/src/daemon.c b/src/daemon.c
|
|
index 151f294..9209976 100644
|
|
--- a/src/daemon.c
|
|
+++ b/src/daemon.c
|
|
@@ -43,79 +43,89 @@
|
|
#include <glib-object.h>
|
|
#include <glib/gstdio.h>
|
|
#include <gio/gio.h>
|
|
#include <polkit/polkit.h>
|
|
|
|
#include "user-classify.h"
|
|
#include "wtmp-helper.h"
|
|
#include "daemon.h"
|
|
#include "util.h"
|
|
#include "user.h"
|
|
#include "accounts-user-generated.h"
|
|
|
|
#define PATH_PASSWD "passwd"
|
|
#define PATH_SHADOW "shadow"
|
|
#define PATH_GROUP "/etc/group"
|
|
#define PATH_DM "/etc/systemd/system/display-manager.service"
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_DAEMON_VERSION
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
DISPLAY_MANAGER_TYPE_NONE = -1,
|
|
DISPLAY_MANAGER_TYPE_GDM,
|
|
DISPLAY_MANAGER_TYPE_LIGHTDM
|
|
} DisplayManagerType;
|
|
|
|
+typedef enum
|
|
+{
|
|
+ USER_RELOAD_TYPE_NONE = 0,
|
|
+ USER_RELOAD_TYPE_IMMEDIATELY,
|
|
+ USER_RELOAD_TYPE_SOON,
|
|
+ USER_RELOAD_TYPE_EVENTUALLY
|
|
+} UserReloadType;
|
|
+
|
|
typedef struct
|
|
{
|
|
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 *dm_monitor;
|
|
GFileMonitor *wtmp_monitor;
|
|
|
|
GQueue *pending_list_cached_users;
|
|
|
|
+ UserReloadType reload_type;
|
|
guint reload_id;
|
|
+
|
|
guint autologin_id;
|
|
|
|
PolkitAuthority *authority;
|
|
GHashTable *extension_ifaces;
|
|
} DaemonPrivate;
|
|
|
|
typedef struct passwd * (* EntryGeneratorFunc) (Daemon *,
|
|
GHashTable *,
|
|
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));
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (Daemon, g_object_unref)
|
|
|
|
static const GDBusErrorEntry accounts_error_entries[] =
|
|
{
|
|
@@ -598,60 +608,61 @@ reload_users (Daemon *daemon)
|
|
user_unregister (user);
|
|
}
|
|
}
|
|
|
|
/* Register all the new users */
|
|
g_hash_table_iter_init (&iter, users);
|
|
while (g_hash_table_iter_next (&iter, &name, &value)) {
|
|
User *user = value;
|
|
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));
|
|
}
|
|
g_object_thaw_notify (G_OBJECT (user));
|
|
}
|
|
|
|
g_hash_table_destroy (old_users);
|
|
}
|
|
|
|
static gboolean
|
|
reload_users_timeout (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
reload_users (daemon);
|
|
priv->reload_id = 0;
|
|
+ priv->reload_type = USER_RELOAD_TYPE_NONE;
|
|
|
|
g_queue_foreach (priv->pending_list_cached_users,
|
|
(GFunc) finish_list_cached_users, NULL);
|
|
g_queue_clear (priv->pending_list_cached_users);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean load_autologin (Daemon *daemon,
|
|
gchar **name,
|
|
gboolean *enabled,
|
|
GError **error);
|
|
|
|
static gboolean
|
|
reload_autologin_timeout (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
AccountsAccounts *accounts = ACCOUNTS_ACCOUNTS (daemon);
|
|
gboolean enabled;
|
|
g_autofree gchar *name = NULL;
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
User *user = NULL;
|
|
|
|
priv->autologin_id = 0;
|
|
|
|
if (!load_autologin (daemon, &name, &enabled, &error)) {
|
|
g_debug ("failed to load autologin conf file: %s", error->message);
|
|
return FALSE;
|
|
}
|
|
@@ -671,87 +682,100 @@ reload_autologin_timeout (Daemon *daemon)
|
|
users[0] = user_get_object_path (user);
|
|
users[1] = NULL;
|
|
accounts_accounts_set_automatic_login_users (accounts, users);
|
|
if (priv->autologin != user) {
|
|
g_object_set (user, "automatic-login", TRUE, NULL);
|
|
priv->autologin = g_object_ref (user);
|
|
g_signal_emit_by_name (priv->autologin, "changed", 0);
|
|
}
|
|
} else {
|
|
g_debug ("automatic login is disabled");
|
|
accounts_accounts_set_automatic_login_users (accounts, NULL);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
queue_reload_users_eventually (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
if (priv->reload_id > 0) {
|
|
return;
|
|
}
|
|
|
|
/* we wait 10 seconds before reloading the users, so e.g. wtmp
|
|
* parsing doesn't hammer the cpu if the user is logging in
|
|
* and out in a continuous loop.
|
|
*/
|
|
priv->reload_id = g_timeout_add_seconds (10, (GSourceFunc) reload_users_timeout, daemon);
|
|
+ priv->reload_type = USER_RELOAD_TYPE_EVENTUALLY;
|
|
}
|
|
|
|
static void
|
|
queue_reload_users_soon (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
+ if (priv->reload_type > USER_RELOAD_TYPE_SOON) {
|
|
+ g_source_remove (priv->reload_id);
|
|
+ priv->reload_id = 0;
|
|
+ }
|
|
+
|
|
if (priv->reload_id > 0) {
|
|
return;
|
|
}
|
|
|
|
/* we wait half a second or so in case /etc/passwd and
|
|
* /etc/shadow are changed at the same time, or repeatedly.
|
|
*/
|
|
priv->reload_id = g_timeout_add (500, (GSourceFunc) reload_users_timeout, daemon);
|
|
+ priv->reload_type = USER_RELOAD_TYPE_SOON;
|
|
}
|
|
|
|
static void
|
|
queue_reload_users (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
+ if (priv->reload_type > USER_RELOAD_TYPE_IMMEDIATELY) {
|
|
+ g_source_remove (priv->reload_id);
|
|
+ priv->reload_id = 0;
|
|
+ }
|
|
+
|
|
if (priv->reload_id > 0) {
|
|
return;
|
|
}
|
|
|
|
priv->reload_id = g_idle_add ((GSourceFunc) reload_users_timeout, daemon);
|
|
+ priv->reload_type = USER_RELOAD_TYPE_IMMEDIATELY;
|
|
}
|
|
|
|
static void
|
|
queue_reload_autologin (Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
if (priv->autologin_id > 0) {
|
|
return;
|
|
}
|
|
|
|
priv->autologin_id = g_idle_add ((GSourceFunc) reload_autologin_timeout, daemon);
|
|
}
|
|
|
|
static void
|
|
on_users_monitor_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
Daemon *daemon)
|
|
{
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
|
|
if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
|
|
event_type != G_FILE_MONITOR_EVENT_CREATED) {
|
|
return;
|
|
}
|
|
|
|
if (monitor == priv->wtmp_monitor) {
|
|
queue_reload_users_eventually (daemon);
|
|
@@ -1120,60 +1144,61 @@ finish_list_cached_users (ListUserData *data)
|
|
}
|
|
|
|
if (!user_get_cached (user)) {
|
|
g_debug ("user %s %ld not cached", name, (long) uid);
|
|
continue;
|
|
}
|
|
|
|
g_debug ("user %s %ld not excluded", name, (long) uid);
|
|
g_ptr_array_add (object_paths, (gpointer) user_get_object_path (user));
|
|
}
|
|
g_ptr_array_add (object_paths, NULL);
|
|
|
|
accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata);
|
|
|
|
list_user_data_free (data);
|
|
}
|
|
|
|
static gboolean
|
|
daemon_list_cached_users (AccountsAccounts *accounts,
|
|
GDBusMethodInvocation *context)
|
|
{
|
|
Daemon *daemon = (Daemon *) accounts;
|
|
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
ListUserData *data;
|
|
|
|
data = list_user_data_new (daemon, context);
|
|
|
|
if (priv->reload_id > 0) {
|
|
/* reload pending -- finish call in reload_users_timeout */
|
|
g_queue_push_tail (priv->pending_list_cached_users, data);
|
|
+ queue_reload_users (daemon);
|
|
} else {
|
|
finish_list_cached_users (data);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
sort_languages (gconstpointer element_1,
|
|
gconstpointer element_2,
|
|
GHashTable *language_frequency_map)
|
|
{
|
|
const char *language_1 = *(const char **) element_1;
|
|
const char *language_2 = *(const char **) element_2;
|
|
int count_1, count_2;
|
|
|
|
count_1 = GPOINTER_TO_INT (g_hash_table_lookup (language_frequency_map, language_1));
|
|
count_2 = GPOINTER_TO_INT (g_hash_table_lookup (language_frequency_map, language_2));
|
|
|
|
if (count_2 == count_1) {
|
|
return strcmp (language_1, language_2);
|
|
}
|
|
|
|
return count_2 - count_1;
|
|
}
|
|
|
|
static gboolean
|
|
daemon_get_users_languages (AccountsAccounts *accounts,
|
|
GDBusMethodInvocation *context)
|
|
{
|
|
--
|
|
2.39.2
|
|
|