From ddc4e15ae58ed34fb7fce2467ad5d41b19ee65e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 17 Jul 2011 03:36:57 +0200 Subject: [PATCH] history: read history data from utmpx instead of ConsoleKit Use the POSIX utmpx database instead of ConsoleKit as source for log-in data. This is more portable and much simpler. Also, it allows us to prepare accountsservice for the post-CK times. --- src/daemon.c | 265 +++++-------------------------------- src/libaccountsservice/act-user.c | 2 +- 2 files changed, 36 insertions(+), 231 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index 2a18924..a970448 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -88,7 +89,6 @@ enum { enum { USER_ADDED, USER_REMOVED, - CK_HISTORY_LOADED, LAST_SIGNAL }; @@ -108,7 +108,6 @@ struct DaemonPrivate { GFileMonitor *shadow_monitor; guint reload_id; - guint ck_history_id; guint autologin_id; PolkitAuthority *authority; @@ -205,16 +204,6 @@ daemon_class_init (DaemonClass *klass) 1, DBUS_TYPE_G_OBJECT_PATH); - signals[CK_HISTORY_LOADED] = g_signal_new ("ck-history-loaded", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - dbus_g_object_type_install_info (TYPE_DAEMON, &dbus_glib_daemon_object_info); @@ -254,222 +243,56 @@ listify_hash_values_hfunc (gpointer key, *list = g_slist_prepend (*list, value); } -static gboolean -parse_value_as_ulong (const gchar *value, - gulong *ulongval) -{ - gchar *end_of_valid_long; - glong long_value; - gulong ulong_value; - - errno = 0; - long_value = strtol (value, &end_of_valid_long, 10); - - if (*value == '\0' || *end_of_valid_long != '\0') { - return FALSE; - } - - ulong_value = long_value; - if (ulong_value != long_value || errno == ERANGE) { - return FALSE; - } - - *ulongval = ulong_value; - - return TRUE; -} - -static gboolean -parse_ck_history_line (const gchar *line, - gchar **user_namep, - gulong *frequencyp) -{ - GRegex *re; - GMatchInfo *match_info; - gboolean res; - gboolean ret; - GError *error; - - ret = FALSE; - re = NULL; - match_info = NULL; - - error = NULL; - re = g_regex_new ("(?P[0-9a-zA-Z]+)[ ]+(?P[0-9]+)", 0, 0, &error); - if (re == NULL) { - if (error != NULL) { - g_critical ("%s", error->message); - } else { - g_critical ("Error in regex call"); - } - goto out; - } - - g_regex_match (re, line, 0, &match_info); - - res = g_match_info_matches (match_info); - if (! res) { - g_warning ("Unable to parse history: %s", line); - goto out; - } - - if (user_namep != NULL) { - *user_namep = g_match_info_fetch_named (match_info, "username"); - } - - if (frequencyp != NULL) { - char *freq; - freq = g_match_info_fetch_named (match_info, "frequency"); - res = parse_value_as_ulong (freq, frequencyp); - g_free (freq); - if (! res) { - goto out; - } - } - - ret = TRUE; - - out: - if (match_info != NULL) { - g_match_info_free (match_info); - } - if (re != NULL) { - g_regex_unref (re); - } - return ret; -} - static void -process_ck_history_line (Daemon *daemon, - const gchar *line) +reload_wtmp_history (Daemon *daemon) { - gboolean res; - gchar *username; - gulong frequency; - User *user; - - frequency = 0; - username = NULL; - res = parse_ck_history_line (line, &username, &frequency); - if (! res) { - return; - } + struct utmpx *u; + GHashTable *h; + GHashTableIter i; + gpointer k, c; - if (daemon_local_user_is_excluded (daemon, username, daemon->priv->minimal_uid)) { - g_debug ("excluding user '%s'", username); - g_free (username); - return; - } + utmpxname(_PATH_WTMPX); + setutxent (); - user = daemon_local_find_user_by_name (daemon, username); - if (user == NULL) { - g_debug ("unable to lookup user '%s'", username); - g_free (username); - return; - } + h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_object_set (user, "login-frequency", (guint64) frequency, NULL); - g_free (username); -} + while ((u = getutxent ())) { + gulong counter; -static gboolean -ck_history_watch (GIOChannel *source, - GIOCondition condition, - Daemon *daemon) -{ - GIOStatus status; - gboolean done = FALSE; + if (u->ut_type != USER_PROCESS) + continue; - if (condition & G_IO_IN) { - gchar *str; - GError *error; + if (u->ut_user[0] == 0) + continue; - error = NULL; - status = g_io_channel_read_line (source, &str, NULL, NULL, &error); - if (error != NULL) { - g_warning ("unable to read line: %s", error->message); - g_error_free (error); - } - if (status == G_IO_STATUS_NORMAL) { - g_debug ("history output: %s", str); - process_ck_history_line (daemon, str); - } else if (status == G_IO_STATUS_EOF) { - done = TRUE; + if (daemon_local_user_is_excluded (daemon, u->ut_user, daemon->priv->minimal_uid)) { + g_debug ("excluding user '%s'", u->ut_user); + continue; } - g_free (str); - } else if (condition & G_IO_HUP) { - done = TRUE; - } + c = g_hash_table_lookup (h, u->ut_user); + counter = GPOINTER_TO_UINT (c) + 1; + c = GUINT_TO_POINTER(counter); - if (done) { - daemon->priv->ck_history_id = 0; - g_signal_emit (daemon, signals[CK_HISTORY_LOADED], 0); - return FALSE; + g_hash_table_replace (h, g_strdup(u->ut_user), c); } - return TRUE; -} - -static void -reload_ck_history (Daemon *daemon) -{ - gchar *command; - GError *error; - gboolean res; - gchar **argv; - gint standard_out; - GIOChannel *channel; + g_hash_table_iter_init (&i, h); + while (g_hash_table_iter_next (&i, &k, &c)) { + User *user; - command = g_strdup ("ck-history --frequent --session-type=''"); - g_debug ("running '%s'", command); - error = NULL; - if (! g_shell_parse_argv (command, NULL, &argv, &error)) { - if (error != NULL) { - g_warning ("Could not parse command: %s", error->message); - g_error_free (error); - } else { - g_warning ("Could not parse command"); + user = daemon_local_find_user_by_name (daemon, k); + if (user == NULL) { + g_debug ("unable to lookup user '%s'", (char*) k); + continue; } - goto out; - } - error = NULL; - res = g_spawn_async_with_pipes (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, /* pid */ - NULL, - &standard_out, - NULL, - &error); - g_strfreev (argv); - if (! res) { - if (error != NULL) { - g_warning ("Unable to run ck-history: %s", error->message); - g_error_free (error); - } else { - g_warning ("Unable to run ck-history"); - } - goto out; + g_object_set (user, "login-frequency", (guint64) GPOINTER_TO_UINT(c), NULL); } - channel = g_io_channel_unix_new (standard_out); - g_io_channel_set_close_on_unref (channel, TRUE); - g_io_channel_set_flags (channel, - g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, - NULL); - daemon->priv->ck_history_id = g_io_add_watch (channel, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc)ck_history_watch, - daemon); - g_io_channel_unref (channel); + g_hash_table_unref (h); - out: - g_free (command); + endutxent (); } static gint @@ -589,7 +412,7 @@ reload_data (Daemon *daemon) static void reload_users (Daemon *daemon) { - reload_ck_history (daemon); + reload_wtmp_history (daemon); reload_passwd (daemon); reload_data (daemon); } @@ -784,7 +607,7 @@ daemon_init (Daemon *daemon) } else { g_warning ("Unable to monitor %s: %s", PATH_SHADOW, error->message); g_error_free (error); - } + } queue_reload_users (daemon); queue_reload_autologin (daemon); @@ -1057,18 +880,6 @@ finish_list_cached_users (gpointer user_data) return FALSE; } -static void -on_ck_history_loaded (Daemon *daemon, - ListUserData *data) -{ - /* ck-history loaded, so finish pending ListCachedUsers call */ - g_idle_add (finish_list_cached_users, data); - - g_signal_handlers_disconnect_by_func (daemon, - on_ck_history_loaded, - data); -} - gboolean daemon_list_cached_users (Daemon *daemon, DBusGMethodInvocation *context) @@ -1077,12 +888,7 @@ daemon_list_cached_users (Daemon *daemon, data = list_user_data_new (daemon, context); - if (daemon->priv->ck_history_id > 0) { - /* loading ck-history, wait for it */ - g_signal_connect (daemon, "ck-history-loaded", - G_CALLBACK (on_ck_history_loaded), - data); - } else if (daemon->priv->reload_id > 0) { + if (daemon->priv->reload_id > 0) { /* reload in progress, wait a bit */ g_idle_add (finish_list_cached_users, data); } @@ -1484,4 +1290,3 @@ daemon_local_set_automatic_login (Daemon *daemon, return TRUE; } - diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c index 1d3c378..86f262e 100644 --- a/src/libaccountsservice/act-user.c +++ b/src/libaccountsservice/act-user.c @@ -857,7 +857,7 @@ act_user_get_x_session (ActUser *user) * or %NULL if @user doesn't have an object path associated * with it. * - * Returns: (transfer none): the primary ConsoleKit session id of the user + * Returns: (transfer none): the object path of the user */ const char * act_user_get_object_path (ActUser *user) -- 1.7.6