[gnome-session] Add a systemd implementation of GsmSystem



commit 371d254a38ab04b9e88530c2eca5837293f90a97
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Jan 24 18:21:31 2012 -0500

    Add a systemd implementation of GsmSystem
    
    https://bugzilla.gnome.org/show_bug.cgi?id=666891

 gnome-session/Makefile.am   |    4 +
 gnome-session/gsm-system.c  |   10 +
 gnome-session/gsm-systemd.c |  405 +++++++++++++++++++++++++++++++++++++++++++
 gnome-session/gsm-systemd.h |   61 +++++++
 4 files changed, 480 insertions(+), 0 deletions(-)
---
diff --git a/gnome-session/Makefile.am b/gnome-session/Makefile.am
index 36a56ad..b6ff85f 100644
--- a/gnome-session/Makefile.am
+++ b/gnome-session/Makefile.am
@@ -30,6 +30,8 @@ gnome_session_SOURCES =				\
 	gsm-system.c				\
 	gsm-consolekit.c			\
 	gsm-consolekit.h			\
+	gsm-systemd.h				\
+	gsm-systemd.c				\
 	gsm-logout-dialog.h			\
 	gsm-logout-dialog.c			\
 	gsm-icon-names.h			\
@@ -71,6 +73,7 @@ gnome_session_CPPFLAGS =			\
 	$(ICE_CFLAGS)				\
 	$(XEXT_CFLAGS)				\
 	$(GCONF_CFLAGS)				\
+	$(SYSTEMD_CFLAGS)			\
 	-I$(top_srcdir)/egg			\
 	-DLOCALE_DIR=\""$(datadir)/locale"\"	\
 	-DDATA_DIR=\""$(datadir)/gnome-session"\" \
@@ -90,6 +93,7 @@ gnome_session_LDADD =				\
 	$(XEXT_LIBS)				\
 	$(GNOME_SESSION_LIBS)			\
 	$(GCONF_LIBS)				\
+	$(SYSTEMD_LIBS)				\
 	$(EXECINFO_LIBS)
 
 libgsmutil_la_SOURCES =				\
diff --git a/gnome-session/gsm-system.c b/gnome-session/gsm-system.c
index da91d9f..bc7d6a9 100644
--- a/gnome-session/gsm-system.c
+++ b/gnome-session/gsm-system.c
@@ -25,6 +25,7 @@
 
 #include "gsm-system.h"
 #include "gsm-consolekit.h"
+#include "gsm-systemd.h"
 
 enum {
         REQUEST_COMPLETED = 0,
@@ -111,7 +112,16 @@ gsm_get_system (void)
         static GsmSystem *system = NULL;
 
         if (system == NULL) {
+                system = GSM_SYSTEM (gsm_systemd_new ());
+                if (system != NULL) {
+                        g_debug ("Using systemd for session tracking");
+                }
+        }
+        if (system == NULL) {
                 system = GSM_SYSTEM (gsm_consolekit_new ());
+                if (system != NULL) {
+                        g_debug ("Using ConsoleKit for session tracking");
+                }
         }
 
         return g_object_ref (system);
diff --git a/gnome-session/gsm-systemd.c b/gnome-session/gsm-systemd.c
new file mode 100644
index 0000000..d87c5a6
--- /dev/null
+++ b/gnome-session/gsm-systemd.c
@@ -0,0 +1,405 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#include "config.h"
+#include "gsm-systemd.h"
+
+#ifdef HAVE_SYSTEMD
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <polkit/polkit.h>
+#include <systemd/sd-login.h>
+#include <systemd/sd-daemon.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gsm-marshal.h"
+#include "gsm-system.h"
+
+#define SD_NAME              "org.freedesktop.login1"
+#define SD_PATH              "/org/freedesktop/login1"
+#define SD_INTERFACE         "org.freedesktop.login1.Manager"
+#define SD_SEAT_INTERFACE    "org.freedesktop.login1.Seat"
+#define SD_SESSION_INTERFACE "org.freedesktop.login1.Session"
+
+struct _GsmSystemdPrivate
+{
+        GDBusProxy      *sd_proxy;
+        gchar           *session_id;
+        gchar           *session_path;
+        PolkitAuthority *authority;
+        PolkitSubject   *subject;
+};
+
+static void gsm_systemd_system_init (GsmSystemInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GsmSystemd, gsm_systemd, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GSM_TYPE_SYSTEM,
+                                                gsm_systemd_system_init))
+
+
+static void
+gsm_systemd_finalize (GObject *object)
+{
+        GsmSystemd *systemd = GSM_SYSTEMD (object);
+
+        g_clear_object (&systemd->priv->sd_proxy);
+        g_clear_object (&systemd->priv->authority);
+        g_clear_object (&systemd->priv->subject);
+        g_free (systemd->priv->session_id);
+        g_free (systemd->priv->session_path);
+
+        G_OBJECT_CLASS (gsm_systemd_parent_class)->finalize (object);
+}
+
+static void
+gsm_systemd_class_init (GsmSystemdClass *manager_class)
+{
+        GObjectClass *object_class;
+
+        object_class = G_OBJECT_CLASS (manager_class);
+
+        object_class->finalize = gsm_systemd_finalize;
+
+        g_type_class_add_private (manager_class, sizeof (GsmSystemdPrivate));
+}
+
+static void
+gsm_systemd_init (GsmSystemd *manager)
+{
+        GError *error;
+        GDBusConnection *bus;
+        GVariant *res;
+
+        manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+                                                     GSM_TYPE_SYSTEMD,
+                                                     GsmSystemdPrivate);
+
+        error = NULL;
+
+        bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+        if (bus == NULL) {
+                g_warning ("Failed to connect to system bus: %s",
+                           error->message);
+                g_error_free (error);
+        } else {
+                manager->priv->sd_proxy =
+                        g_dbus_proxy_new_sync (bus,
+                                               0,
+                                               NULL,
+                                               SD_NAME,
+                                               SD_PATH,
+                                               SD_INTERFACE,
+                                               NULL,
+                                               &error);
+
+                if (manager->priv->sd_proxy == NULL) {
+                        g_warning ("Failed to connect to systemd: %s",
+                                   error->message);
+                        g_error_free (error);
+                }
+
+                g_object_unref (bus);
+        }
+
+        manager->priv->authority = polkit_authority_get_sync (NULL, NULL);
+        manager->priv->subject = polkit_unix_session_new_for_process_sync (getpid (), NULL, NULL);
+
+        sd_pid_get_session (getpid (), &manager->priv->session_id);
+
+        res = g_dbus_proxy_call_sync (manager->priv->sd_proxy,
+                                      "GetSession",
+                                      g_variant_new ("(s)", manager->priv->session_id),
+                                      0,
+                                      G_MAXINT,
+                                      NULL,
+                                      NULL);
+        g_variant_get (res, "(o)", &manager->priv->session_path);
+        g_variant_unref (res);
+}
+
+static void
+emit_restart_complete (GsmSystemd *manager,
+                       GError     *error)
+{
+        GError *call_error;
+
+        call_error = NULL;
+
+        if (error != NULL) {
+                call_error = g_error_new_literal (GSM_SYSTEM_ERROR,
+                                                  GSM_SYSTEM_ERROR_RESTARTING,
+                                                  error->message);
+        }
+
+        g_signal_emit_by_name (G_OBJECT (manager),
+                               "request_completed", call_error);
+
+        if (call_error != NULL) {
+                g_error_free (call_error);
+        }
+}
+
+static void
+emit_stop_complete (GsmSystemd *manager,
+                    GError     *error)
+{
+        GError *call_error;
+
+        call_error = NULL;
+
+        if (error != NULL) {
+                call_error = g_error_new_literal (GSM_SYSTEM_ERROR,
+                                                  GSM_SYSTEM_ERROR_STOPPING,
+                                                  error->message);
+        }
+
+        g_signal_emit_by_name (G_OBJECT (manager),
+                               "request_completed", call_error);
+
+        if (call_error != NULL) {
+                g_error_free (call_error);
+        }
+}
+
+static void
+restart_done (GObject      *source,
+              GAsyncResult *result,
+              gpointer      user_data)
+{
+        GDBusProxy *proxy = G_DBUS_PROXY (source);
+        GsmSystemd *manager = user_data;
+        GError *error = NULL;
+        GVariant *res;
+
+        res = g_dbus_proxy_call_finish (proxy, result, &error);
+
+        if (!res) {
+                g_warning ("Unable to restart system: %s", error->message);
+                emit_restart_complete (manager, error);
+                g_error_free (error);
+        } else {
+                emit_restart_complete (manager, NULL);
+        }
+
+        g_variant_unref (res);
+}
+
+static void
+gsm_systemd_attempt_restart (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+
+        g_dbus_proxy_call (manager->priv->sd_proxy,
+                           "Reboot",
+                           g_variant_new ("(b)", TRUE),
+                           0,
+                           G_MAXINT,
+                           NULL,
+                           restart_done,
+                           NULL);
+}
+
+static void
+stop_done (GObject      *source,
+           GAsyncResult *result,
+           gpointer      user_data)
+{
+        GDBusProxy *proxy = G_DBUS_PROXY (source);
+        GsmSystemd *manager = user_data;
+        GError *error = NULL;
+        GVariant *res;
+
+        res = g_dbus_proxy_call_finish (proxy, result, &error);
+
+        if (!res) {
+                g_warning ("Unable to stop system: %s", error->message);
+                emit_stop_complete (manager, error);
+                g_error_free (error);
+        } else {
+                emit_stop_complete (manager, NULL);
+        }
+
+        g_variant_unref (res);
+}
+
+static void
+gsm_systemd_attempt_stop (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+
+        g_dbus_proxy_call (manager->priv->sd_proxy,
+                           "PowerOff",
+                           g_variant_new ("(b)", TRUE),
+                           0,
+                           G_MAXINT,
+                           NULL,
+                           stop_done,
+                           NULL);
+}
+
+static void
+gsm_systemd_set_session_idle (GsmSystem *system,
+                              gboolean   is_idle)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+        GDBusConnection *bus;
+
+        g_debug ("Updating systemd idle status: %d", is_idle);
+        bus = g_dbus_proxy_get_connection (manager->priv->sd_proxy);
+        g_dbus_connection_call (bus,
+                                SD_NAME,
+                                manager->priv->session_path,
+                                SD_SESSION_INTERFACE,
+                                "SetIdleHint",
+                                g_variant_new ("(b)", is_idle),
+                                G_VARIANT_TYPE_BOOLEAN,
+                                0,
+                                G_MAXINT,
+                                NULL, NULL, NULL);
+}
+
+static gboolean
+gsm_systemd_can_switch_user (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+        gchar *seat;
+        gint ret;
+
+        sd_session_get_seat (manager->priv->session_id, &seat);
+        ret = sd_seat_can_multi_session (seat);
+        free (seat);
+
+        return ret > 0;
+}
+
+static gboolean
+gsm_systemd_can_restart (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+        PolkitAuthorizationResult *res;
+        gboolean can_restart;
+
+        res = polkit_authority_check_authorization_sync (manager->priv->authority,
+                                                         manager->priv->subject,
+                                                         "org.freedesktop.login1.reboot",
+                                                         NULL,
+                                                         POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
+                                                         NULL,
+                                                         NULL);
+        if (res == NULL) {
+                return FALSE;
+        }
+
+        can_restart = polkit_authorization_result_get_is_authorized (res) ||
+                      polkit_authorization_result_get_is_challenge (res);
+
+        g_object_unref (res);
+
+        return can_restart;
+}
+
+static gboolean
+gsm_systemd_can_stop (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+        PolkitAuthorizationResult *res;
+        gboolean can_stop;
+
+        res = polkit_authority_check_authorization_sync (manager->priv->authority,
+                                                         manager->priv->subject,
+                                                         "org.freedesktop.login1.power-off",
+                                                         NULL,
+                                                         POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
+                                                         NULL,
+                                                         NULL);
+        if (res == NULL) {
+                return FALSE;
+        }
+
+        can_stop = polkit_authorization_result_get_is_authorized (res) ||
+                   polkit_authorization_result_get_is_challenge (res);
+
+        g_object_unref (res);
+
+        return can_stop;
+}
+
+static gboolean
+gsm_systemd_is_login_session (GsmSystem *system)
+{
+        GsmSystemd *manager = GSM_SYSTEMD (system);
+        gboolean ret;
+        gchar *service;
+
+        ret = FALSE;
+
+        sd_session_get_service (manager->priv->session_id, &service);
+        ret = (g_strcmp0 (service, "gdm-welcome") == 0);
+        free (service);
+
+        return ret;
+}
+
+static void
+gsm_systemd_system_init (GsmSystemInterface *iface)
+{
+        iface->can_switch_user = gsm_systemd_can_switch_user;
+        iface->can_stop = gsm_systemd_can_stop;
+        iface->can_restart = gsm_systemd_can_restart;
+        iface->attempt_stop = gsm_systemd_attempt_stop;
+        iface->attempt_restart = gsm_systemd_attempt_restart;
+        iface->set_session_idle = gsm_systemd_set_session_idle;
+        iface->is_login_session = gsm_systemd_is_login_session;
+}
+
+GsmSystemd *
+gsm_systemd_new (void)
+{
+        GsmSystemd *manager;
+
+        if (sd_booted () <= 0)
+                return NULL;
+
+        manager = g_object_new (GSM_TYPE_SYSTEMD, NULL);
+
+        return manager;
+}
+
+#else
+
+GsmSystemd *
+gsm_systemd_new (void)
+{
+        return NULL;
+}
+
+#endif
diff --git a/gnome-session/gsm-systemd.h b/gnome-session/gsm-systemd.h
new file mode 100644
index 0000000..a6a3827
--- /dev/null
+++ b/gnome-session/gsm-systemd.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *	Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GSM_SYSTEMD_H__
+#define __GSM_SYSTEMD_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSM_TYPE_SYSTEMD             (gsm_systemd_get_type ())
+#define GSM_SYSTEMD(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_SYSTEMD, GsmSystemd))
+#define GSM_SYSTEMD_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_SYSTEMD, GsmSystemdClass))
+#define GSM_IS_SYSTEMD(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_SYSTEMD))
+#define GSM_IS_SYSTEMD_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_SYSTEMD))
+#define GSM_SYSTEMD_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), GSM_TYPE_SYSTEMD, GsmSystemdClass))
+
+typedef struct _GsmSystemd        GsmSystemd;
+typedef struct _GsmSystemdClass   GsmSystemdClass;
+typedef struct _GsmSystemdPrivate GsmSystemdPrivate;
+
+struct _GsmSystemd
+{
+        GObject            parent;
+
+        GsmSystemdPrivate *priv;
+};
+
+struct _GsmSystemdClass
+{
+        GObjectClass parent_class;
+};
+
+GType         gsm_systemd_get_type (void);
+
+GsmSystemd   *gsm_systemd_new      (void) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __GSM_SYSTEMD_H__ */



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