[PATCH 2/2] core: runtime detect logind and ConsoleKit



If --with-session-tracking=systemd, but logind is not currently running, the code
now falls back to ConsoleKit. This is particularly useful for covering
the interim, while waiting for distros to abandon ConsoleKit completely.
---
 configure.ac                     |   1 +
 src/Makefile.am                  |  10 +-
 src/nm-session-monitor-systemd.c | 268 ----------------
 src/nm-session-monitor.c         | 641 +++++++++++++++++++++++++++++++++++++++
 src/nm-session-monitor.h         |   6 +
 5 files changed, 651 insertions(+), 275 deletions(-)
 delete mode 100644 src/nm-session-monitor-systemd.c
 create mode 100644 src/nm-session-monitor.c

diff --git a/configure.ac b/configure.ac
index a1f49c0..810c464 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AS_IF([! (echo "$with_session_tracking" | grep -q -E "^(systemd|consolekit|no)$"
 # add conditionals and subtitutions
 AM_CONDITIONAL(SESSION_TRACKING_CK, test "$with_session_tracking" = "consolekit")
 AM_CONDITIONAL(SESSION_TRACKING_SYSTEMD, test "$with_session_tracking" = "systemd")
+AM_CONDITIONAL(SESSION_TRACKING_NULL, test "$with_session_tracking" = "no")
 if test "$with_session_tracking" = "systemd"; then
        PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login])
        AC_SUBST(SYSTEMD_LOGIN_CFLAGS)
diff --git a/src/Makefile.am b/src/Makefile.am
index 113b527..20246ff 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -205,14 +205,10 @@ if WITH_CONCHECK
 NetworkManager_SOURCES += nm-connectivity.c nm-connectivity.h
 endif
 
-if SESSION_TRACKING_SYSTEMD
-NetworkManager_SOURCES += nm-session-monitor-systemd.c
-else
-if SESSION_TRACKING_CK
-NetworkManager_SOURCES += nm-session-monitor-ck.c
-else
+if SESSION_TRACKING_NULL
 NetworkManager_SOURCES += nm-session-monitor-null.c
-endif
+else
+NetworkManager_SOURCES += nm-session-monitor.c
 endif
 
 if SUSPEND_RESUME_SYSTEMD
diff --git a/src/nm-session-monitor-systemd.c b/src/nm-session-monitor-systemd.c
deleted file mode 100644
index f9fb075..0000000
--- a/src/nm-session-monitor-systemd.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * Author: Matthias Clasen
- */
-
-#include "config.h"
-#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
-#include <string.h>
-#include <glib/gstdio.h>
-#include <systemd/sd-login.h>
-#include <stdlib.h>
-
-#include "nm-session-utils.h"
-#include "nm-session-monitor.h"
-#include "nm-logging.h"
-
-/********************************************************************/
-
-typedef struct {
-       GSource source;
-       GPollFD pollfd;
-       sd_login_monitor *monitor;
-} SdSource;
-
-static gboolean
-sd_source_prepare (GSource *source, gint *timeout)
-{
-       *timeout = -1;
-       return FALSE;
-}
-
-static gboolean
-sd_source_check (GSource *source)
-{
-       SdSource *sd_source = (SdSource *) source;
-
-       return sd_source->pollfd.revents != 0;
-}
-
-static gboolean
-sd_source_dispatch (GSource     *source,
-                    GSourceFunc  callback,
-                    gpointer     user_data)
-
-{
-       SdSource *sd_source = (SdSource *)source;
-       gboolean ret;
-
-       g_warn_if_fail (callback != NULL);
-       ret = (*callback) (user_data);
-       sd_login_monitor_flush (sd_source->monitor);
-       return ret;
-}
-
-static void
-sd_source_finalize (GSource *source)
-{
-       SdSource *sd_source = (SdSource*) source;
-
-       sd_login_monitor_unref (sd_source->monitor);
-}
-
-static GSourceFuncs sd_source_funcs = {
-       sd_source_prepare,
-       sd_source_check,
-       sd_source_dispatch,
-       sd_source_finalize
-};
-
-static GSource *
-sd_source_new (void)
-{
-       GSource *source;
-       SdSource *sd_source;
-       int ret;
-
-       source = g_source_new (&sd_source_funcs, sizeof (SdSource));
-       sd_source = (SdSource *)source;
-
-       ret = sd_login_monitor_new (NULL, &sd_source->monitor);
-       if (ret < 0)
-               g_printerr ("Error getting login monitor: %d", ret);
-       else {
-               sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor);
-               sd_source->pollfd.events = G_IO_IN;
-               g_source_add_poll (source, &sd_source->pollfd);
-       }
-
-       return source;
-}
-
-struct _NMSessionMonitor {
-       GObject parent_instance;
-
-       GSource *sd_source;
-};
-
-struct _NMSessionMonitorClass {
-       GObjectClass parent_class;
-
-       void (*changed) (NMSessionMonitor *monitor);
-};
-
-
-enum {
-       CHANGED_SIGNAL,
-       LAST_SIGNAL,
-};
-static guint signals[LAST_SIGNAL] = {0};
-
-G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-sessions_changed (gpointer user_data)
-{
-       NMSessionMonitor *monitor = NM_SESSION_MONITOR (user_data);
-
-       g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
-       return TRUE;
-}
-
-
-static void
-nm_session_monitor_init (NMSessionMonitor *monitor)
-{
-       monitor->sd_source = sd_source_new ();
-       g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL);
-       g_source_attach (monitor->sd_source, NULL);
-}
-
-static void
-nm_session_monitor_finalize (GObject *object)
-{
-       NMSessionMonitor *monitor = NM_SESSION_MONITOR (object);
-
-       if (monitor->sd_source != NULL) {
-               g_source_destroy (monitor->sd_source);
-               g_source_unref (monitor->sd_source);
-       }
-
-       if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL)
-               G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object);
-}
-
-static void
-nm_session_monitor_class_init (NMSessionMonitorClass *klass)
-{
-       GObjectClass *gobject_class;
-
-       gobject_class = G_OBJECT_CLASS (klass);
-       gobject_class->finalize = nm_session_monitor_finalize;
-
-       /**
-        * NMSessionMonitor::changed:
-        * @monitor: A #NMSessionMonitor
-        *
-        * Emitted when something changes.
-        */
-       signals[CHANGED_SIGNAL] = g_signal_new ("changed",
-                                               NM_TYPE_SESSION_MONITOR,
-                                               G_SIGNAL_RUN_LAST,
-                                               G_STRUCT_OFFSET (NMSessionMonitorClass, changed),
-                                               NULL,                   /* accumulator      */
-                                               NULL,                   /* accumulator data */
-                                               g_cclosure_marshal_VOID__VOID,
-                                               G_TYPE_NONE,
-                                               0);
-}
-
-NMSessionMonitor *
-nm_session_monitor_get (void)
-{
-       static NMSessionMonitor *singleton = NULL;
-
-       if (singleton)
-               return g_object_ref (singleton);
-
-       singleton = NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL));
-       g_assert (singleton);
-       return singleton;
-}
-
-gboolean
-nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
-                                     const char *username,
-                                     uid_t *out_uid,
-                                     GError **error)
-{
-       uid_t uid;
-
-       if (!nm_session_user_to_uid (username, &uid, error))
-               return FALSE;
-
-       if (out_uid)
-               *out_uid = uid;
-
-       return nm_session_monitor_uid_has_session (monitor, uid, NULL, error);
-}
-
-gboolean
-nm_session_monitor_user_active (NMSessionMonitor *monitor,
-                                const char *username,
-                                GError **error)
-{
-       uid_t uid;
-
-       if (!nm_session_user_to_uid (username, &uid, error))
-               return FALSE;
-
-       return nm_session_monitor_uid_active (monitor, uid, error);
-}
-
-gboolean
-nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
-                                    uid_t uid,
-                                    const char **out_user,
-                                    GError **error)
-{
-       int ret;
-
-       if (!nm_session_uid_to_user (uid, out_user, error))
-               return FALSE;
-
-       ret = sd_uid_get_sessions (uid, FALSE, NULL) > 0;
-       if (ret < 0) {
-               nm_log_warn (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d",
-                            uid, ret);
-               return FALSE;
-       }
-       return ret > 0 ? TRUE : FALSE;
-}
-
-gboolean
-nm_session_monitor_uid_active (NMSessionMonitor *monitor,
-                               uid_t uid,
-                               GError **error)
-{
-       int ret;
-
-       ret = sd_uid_get_sessions (uid, TRUE, NULL) > 0;
-       if (ret < 0) {
-               nm_log_warn (LOGD_CORE, "Failed to get active systemd sessions for uid %d: %d",
-                            uid, ret);
-               return FALSE;
-       }
-       return ret > 0 ? TRUE : FALSE;
-}
diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c
new file mode 100644
index 0000000..26e66ce
--- /dev/null
+++ b/src/nm-session-monitor.c
@@ -0,0 +1,641 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#ifdef SESSION_TRACKING_SYSTEMD
+#include <systemd/sd-login.h>
+#endif
+#include <stdlib.h>
+
+#include "nm-session-utils.h"
+#include "nm-session-monitor.h"
+#include "nm-logging.h"
+
+#define CKDB_PATH "/var/run/ConsoleKit/database"
+
+/********************************************************************/
+
+#ifdef SESSION_TRACKING_SYSTEMD
+typedef struct {
+       GSource source;
+       GPollFD pollfd;
+       sd_login_monitor *monitor;
+} SdSource;
+
+static gboolean
+sd_source_prepare (GSource *source, gint *timeout)
+{
+       *timeout = -1;
+       return FALSE;
+}
+
+static gboolean
+sd_source_check (GSource *source)
+{
+       SdSource *sd_source = (SdSource *) source;
+
+       return sd_source->pollfd.revents != 0;
+}
+
+static gboolean
+sd_source_dispatch (GSource     *source,
+                    GSourceFunc  callback,
+                    gpointer     user_data)
+
+{
+       SdSource *sd_source = (SdSource *)source;
+       gboolean ret;
+
+       g_warn_if_fail (callback != NULL);
+       ret = (*callback) (user_data);
+       sd_login_monitor_flush (sd_source->monitor);
+       return ret;
+}
+
+static void
+sd_source_finalize (GSource *source)
+{
+       SdSource *sd_source = (SdSource*) source;
+
+       sd_login_monitor_unref (sd_source->monitor);
+}
+
+static GSourceFuncs sd_source_funcs = {
+       sd_source_prepare,
+       sd_source_check,
+       sd_source_dispatch,
+       sd_source_finalize
+};
+
+static GSource *
+sd_source_new (void)
+{
+       GSource *source;
+       SdSource *sd_source;
+       int ret;
+
+       source = g_source_new (&sd_source_funcs, sizeof (SdSource));
+       sd_source = (SdSource *)source;
+
+       ret = sd_login_monitor_new (NULL, &sd_source->monitor);
+       if (ret < 0)
+               g_printerr ("Error getting login monitor: %d", ret);
+       else {
+               sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor);
+               sd_source->pollfd.events = G_IO_IN;
+               g_source_add_poll (source, &sd_source->pollfd);
+       }
+
+       return source;
+}
+#endif /* SESSION_TRACKING_SYSTEMD */
+
+struct _NMSessionMonitor {
+       GObject parent_instance;
+
+       GKeyFile *database;
+       GFileMonitor *database_monitor;
+       time_t database_mtime;
+       GHashTable *sessions_by_uid;
+       GHashTable *sessions_by_user;
+
+       GSource *sd_source;
+};
+
+struct _NMSessionMonitorClass {
+       GObjectClass parent_class;
+
+       void (*changed) (NMSessionMonitor *monitor);
+};
+
+
+enum {
+       CHANGED_SIGNAL,
+       LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+       char *user;
+       uid_t uid;
+       gboolean local;
+       gboolean active;
+} Session;
+
+static void
+session_free (Session *s)
+{
+       g_free (s->user);
+       memset (s, 0, sizeof (Session));
+       g_free (s);
+}
+
+static gboolean
+check_key (GKeyFile *keyfile, const char *group, const char *key, GError **error)
+{
+       if (g_key_file_has_key (keyfile, group, key, error))
+               return TRUE;
+
+       if (!error) {
+               g_set_error (error,
+                                NM_SESSION_MONITOR_ERROR,
+                                NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE,
+                                "ConsoleKit database " CKDB_PATH " group '%s' had no '%s' key",
+                                group, key);
+       }
+       return FALSE;
+}
+
+static Session *
+session_new (GKeyFile *keyfile, const char *group, GError **error)
+{
+       GError *local = NULL;
+       Session *s;
+       const char *uname = NULL;
+
+       s = g_new0 (Session, 1);
+       g_assert (s);
+
+       s->uid = G_MAXUINT; /* paranoia */
+       if (!check_key (keyfile, group, "uid", &local))
+               goto error;
+       s->uid = (uid_t) g_key_file_get_integer (keyfile, group, "uid", &local);
+       if (local)
+               goto error;
+
+       if (!check_key (keyfile, group, "is_active", &local))
+               goto error;
+       s->active = g_key_file_get_boolean (keyfile, group, "is_active", &local);
+       if (local)
+               goto error;
+
+       if (!check_key (keyfile, group, "is_local", &local))
+               goto error;
+       s->local = g_key_file_get_boolean (keyfile, group, "is_local", &local);
+       if (local)
+               goto error;
+
+       if (!nm_session_uid_to_user (s->uid, &uname, error))
+               return FALSE;
+       s->user = g_strdup (uname);
+
+       return s;
+
+error:
+       session_free (s);
+       g_propagate_error (error, local);
+       return NULL;
+}
+
+static void
+session_merge (Session *src, Session *dest)
+{
+       g_return_if_fail (src != NULL);
+       g_return_if_fail (dest != NULL);
+
+       g_warn_if_fail (g_strcmp0 (src->user, dest->user) == 0);
+       g_warn_if_fail (src->uid == dest->uid);
+
+       dest->local = (dest->local || src->local);
+       dest->active = (dest->active || src->active);
+}
+
+static void
+free_database (NMSessionMonitor *self)
+{
+       if (self->database != NULL) {
+               g_key_file_free (self->database);
+               self->database = NULL;
+       }
+
+       g_hash_table_remove_all (self->sessions_by_uid);
+       g_hash_table_remove_all (self->sessions_by_user);
+}
+
+static gboolean
+reload_database (NMSessionMonitor *self, GError **error)
+{
+       struct stat statbuf;
+       char **groups = NULL;
+       gsize len = 0, i;
+       Session *s;
+
+       free_database (self);
+
+       errno = 0;
+       if (stat (CKDB_PATH, &statbuf) != 0) {
+               g_set_error (error,
+                            NM_SESSION_MONITOR_ERROR,
+                            errno == ENOENT ? NM_SESSION_MONITOR_ERROR_NO_DATABASE : 
NM_SESSION_MONITOR_ERROR_IO_ERROR,
+                            "Error statting file " CKDB_PATH ": %s",
+                            strerror (errno));
+               goto error;
+       }
+       self->database_mtime = statbuf.st_mtime;
+
+       self->database = g_key_file_new ();
+       if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error))
+               goto error;
+
+       groups = g_key_file_get_groups (self->database, &len);
+       if (!groups) {
+               g_set_error_literal (error,
+                                    NM_SESSION_MONITOR_ERROR,
+                                    NM_SESSION_MONITOR_ERROR_IO_ERROR,
+                                    "Could not load groups from " CKDB_PATH "");
+               goto error;
+       }
+
+       for (i = 0; i < len; i++) {
+               Session *found;
+
+               if (!g_str_has_prefix (groups[i], "Session "))
+                       continue;
+
+               s = session_new (self->database, groups[i], error);
+               if (!s)
+                       goto error;
+
+               found = g_hash_table_lookup (self->sessions_by_user, (gpointer) s->user);
+               if (found) {
+                       session_merge (s, found);
+                       session_free (s);
+               } else {
+                       /* Entirely new user */
+                       g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s);
+                       g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s);
+               }
+       }
+
+       g_strfreev (groups);
+       return TRUE;
+
+error:
+       if (groups)
+               g_strfreev (groups);
+       free_database (self);
+       return FALSE;
+}
+
+static gboolean
+ensure_database (NMSessionMonitor *self, GError **error)
+{
+       gboolean ret = FALSE;
+
+       if (self->database != NULL) {
+               struct stat statbuf;
+
+               errno = 0;
+               if (stat (CKDB_PATH, &statbuf) != 0) {
+                       g_set_error (error,
+                                    NM_SESSION_MONITOR_ERROR,
+                                    errno == ENOENT ? NM_SESSION_MONITOR_ERROR_NO_DATABASE : 
NM_SESSION_MONITOR_ERROR_IO_ERROR,
+                                    "Error statting file " CKDB_PATH " to check timestamp: %s",
+                                    strerror (errno));
+                       goto out;
+               }
+
+               if (statbuf.st_mtime == self->database_mtime) {
+                       ret = TRUE;
+                       goto out;
+               }
+       }
+
+       ret = reload_database (self, error);
+
+out:
+       return ret;
+}
+
+static void
+on_file_monitor_changed (GFileMonitor *    file_monitor,
+                         GFile *           file,
+                         GFile *           other_file,
+                         GFileMonitorEvent event_type,
+                         gpointer          user_data)
+{
+       NMSessionMonitor *self = NM_SESSION_MONITOR (user_data);
+
+       /* throw away cache */
+       free_database (self);
+
+       g_signal_emit (self, signals[CHANGED_SIGNAL], 0);
+}
+
+#ifdef SESSION_TRACKING_SYSTEMD
+static gboolean
+sessions_changed (gpointer user_data)
+{
+       NMSessionMonitor *monitor = NM_SESSION_MONITOR (user_data);
+
+       g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
+       return TRUE;
+}
+#endif /* SESSION_TRACKING_SYSTEMD */
+
+
+static void
+nm_session_monitor_init (NMSessionMonitor *monitor)
+{
+       GError *error;
+       GFile *file;
+
+       monitor->sd_source = NULL;
+       monitor->database = NULL;
+       monitor->database_monitor = NULL;
+       monitor->sessions_by_uid = NULL;
+       monitor->sessions_by_user = NULL;
+
+#ifdef SESSION_TRACKING_SYSTEMD
+       if (LOGIND_RUNNING())
+       {
+               monitor->sd_source = sd_source_new ();
+               g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL);
+               g_source_attach (monitor->sd_source, NULL);
+               return;
+       }
+       /* fall through */
+#endif /* SESSION_TRACKING_SYSTEMD */
+
+       error = NULL;
+
+       /* Sessions-by-user is responsible for destroying the Session objects */
+       monitor->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal,
+                       NULL, (GDestroyNotify) session_free);
+       monitor->sessions_by_uid = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+
+       error = NULL;
+       if (!ensure_database (monitor, &error)) {
+               /* Ignore the first error if the CK database isn't found yet */
+               if (g_error_matches (error,
+                                    NM_SESSION_MONITOR_ERROR,
+                                    NM_SESSION_MONITOR_ERROR_NO_DATABASE) == FALSE) {
+                       nm_log_err (LOGD_CORE, "Error loading " CKDB_PATH ": %s", error->message);
+               }
+               g_error_free (error);
+       }
+
+       error = NULL;
+       file = g_file_new_for_path (CKDB_PATH);
+       monitor->database_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
+       g_object_unref (file);
+       if (monitor->database_monitor == NULL) {
+               nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message);
+               g_error_free (error);
+       } else {
+               g_signal_connect (monitor->database_monitor,
+                                 "changed",
+                                 G_CALLBACK (on_file_monitor_changed),
+                                 monitor);
+       }
+}
+
+static void
+nm_session_monitor_finalize (GObject *object)
+{
+       NMSessionMonitor *monitor = NM_SESSION_MONITOR (object);
+
+       if (monitor->sd_source != NULL) {
+               g_source_destroy (monitor->sd_source);
+               g_source_unref (monitor->sd_source);
+       }
+
+       if (monitor->database_monitor != NULL)
+               g_object_unref (monitor->database_monitor);
+
+       free_database (monitor);
+
+       if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL)
+               G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object);
+}
+
+static void
+nm_session_monitor_class_init (NMSessionMonitorClass *klass)
+{
+       GObjectClass *gobject_class;
+
+       gobject_class = G_OBJECT_CLASS (klass);
+       gobject_class->finalize = nm_session_monitor_finalize;
+
+       /**
+        * NMSessionMonitor::changed:
+        * @monitor: A #NMSessionMonitor
+        *
+        * Emitted when something changes.
+        */
+       signals[CHANGED_SIGNAL] = g_signal_new (NM_SESSION_MONITOR_CHANGED,
+                                               NM_TYPE_SESSION_MONITOR,
+                                               G_SIGNAL_RUN_LAST,
+                                               G_STRUCT_OFFSET (NMSessionMonitorClass, changed),
+                                               NULL,                   /* accumulator      */
+                                               NULL,                   /* accumulator data */
+                                               g_cclosure_marshal_VOID__VOID,
+                                               G_TYPE_NONE,
+                                               0);
+}
+
+NMSessionMonitor *
+nm_session_monitor_get (void)
+{
+       static NMSessionMonitor *singleton = NULL;
+
+       if (singleton)
+               return g_object_ref (singleton);
+
+       singleton = NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL));
+       g_assert (singleton);
+       return singleton;
+}
+
+gboolean
+nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
+                                     const char *username,
+                                     uid_t *out_uid,
+                                     GError **error)
+{
+#ifdef SESSION_TRACKING_SYSTEMD
+       if (LOGIND_RUNNING())
+       {
+               uid_t uid;
+
+               if (!nm_session_user_to_uid (username, &uid, error))
+                       return FALSE;
+
+               if (out_uid)
+                       *out_uid = uid;
+
+               return nm_session_monitor_uid_has_session (monitor, uid, NULL, error);
+       }
+       /* fall through */
+#endif /* SESSION_TRACKING_SYSTEMD */
+
+       Session *s;
+
+       if (!ensure_database (monitor, error))
+               return FALSE;
+
+       s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username);
+       if (!s) {
+               g_set_error (error,
+                            NM_SESSION_MONITOR_ERROR,
+                            NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+                            "No session found for user '%s'",
+                            username);
+               return FALSE;
+       }
+
+       if (out_uid)
+               *out_uid = s->uid;
+       return TRUE;
+}
+
+gboolean
+nm_session_monitor_user_active (NMSessionMonitor *monitor,
+                                const char *username,
+                                GError **error)
+{
+#ifdef SESSION_TRACKING_SYSTEMD
+       if (LOGIND_RUNNING())
+       {
+               uid_t uid;
+
+               if (!nm_session_user_to_uid (username, &uid, error))
+                       return FALSE;
+
+               return nm_session_monitor_uid_active (monitor, uid, error);
+       }
+       /* fall through */
+#endif
+
+       Session *s;
+
+       if (!ensure_database (monitor, error))
+               return FALSE;
+
+       s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username);
+       if (!s) {
+               g_set_error (error,
+                            NM_SESSION_MONITOR_ERROR,
+                            NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+                            "No session found for user '%s'",
+                            username);
+               return FALSE;
+       }
+
+       return s->active;
+}
+
+gboolean
+nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
+                                    uid_t uid,
+                                    const char **out_user,
+                                    GError **error)
+{
+#ifdef SESSION_TRACKING_SYSTEMD
+       if (LOGIND_RUNNING())
+       {
+               int ret;
+
+               if (!nm_session_uid_to_user (uid, out_user, error))
+                       return FALSE;
+
+               ret = sd_uid_get_sessions (uid, FALSE, NULL) > 0;
+               if (ret < 0) {
+                       nm_log_warn (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d",
+                                                uid, ret);
+                       return FALSE;
+               }
+               return ret > 0 ? TRUE : FALSE;
+       }
+       /* fall through */
+#endif
+
+       Session *s;
+
+       if (!ensure_database (monitor, error))
+               return FALSE;
+
+       s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid));
+       if (!s) {
+               g_set_error (error,
+                            NM_SESSION_MONITOR_ERROR,
+                            NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+                            "No session found for uid %d",
+                            uid);
+               return FALSE;
+       }
+
+       if (out_user)
+               *out_user = s->user;
+       return TRUE;
+}
+
+gboolean
+nm_session_monitor_uid_active (NMSessionMonitor *monitor,
+                               uid_t uid,
+                               GError **error)
+{
+#ifdef SESSION_TRACKING_SYSTEMD
+       if (LOGIND_RUNNING())
+       {
+               int ret;
+
+               ret = sd_uid_get_sessions (uid, TRUE, NULL) > 0;
+               if (ret < 0) {
+                       nm_log_warn (LOGD_CORE, "Failed to get active systemd sessions for uid %d: %d",
+                                                uid, ret);
+                       return FALSE;
+               }
+               return ret > 0 ? TRUE : FALSE;
+       }
+       /* fall through */
+#endif
+
+       Session *s;
+
+       if (!ensure_database (monitor, error))
+               return FALSE;
+
+       s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid));
+       if (!s) {
+               g_set_error (error,
+                            NM_SESSION_MONITOR_ERROR,
+                            NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+                            "No session found for uid '%d'",
+                            uid);
+               return FALSE;
+       }
+
+       return s->active;
+}
diff --git a/src/nm-session-monitor.h b/src/nm-session-monitor.h
index 77ea9a0..ac3dec5 100644
--- a/src/nm-session-monitor.h
+++ b/src/nm-session-monitor.h
@@ -21,6 +21,7 @@
 #ifndef NM_SESSION_MONITOR_H
 #define NM_SESSION_MONITOR_H
 
+#include <unistd.h>
 #include <glib-object.h>
 
 G_BEGIN_DECLS
@@ -34,6 +35,11 @@ G_BEGIN_DECLS
 
 #define NM_SESSION_MONITOR_CHANGED "changed"
 
+/* check if logind is running
+ * thanks to: https://bugzilla.gnome.org/show_bug.cgi?id=696266
+ */
+#define LOGIND_RUNNING() (access("/run/systemd/seats/", F_OK) >= 0)
+
 typedef struct _NMSessionMonitor         NMSessionMonitor;
 typedef struct _NMSessionMonitorClass    NMSessionMonitorClass;
 
-- 
1.8.1.5



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]