[gnome-session] Add a systemd implementation of GsmSystem
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-session] Add a systemd implementation of GsmSystem
- Date: Mon, 30 Jan 2012 17:46:31 +0000 (UTC)
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]