summaryrefslogtreecommitdiff
path: root/src/backends/native/meta-launcher.c
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2013-12-31 17:44:45 -0500
committerJasper St. Pierre <jstpierre@mecheye.net>2014-05-19 15:09:23 -0400
commitdcf64ca1678a2950842708bee146f09a063ed828 (patch)
treed3608b5b3f5ebbc58f47d73a13d9f14708260756 /src/backends/native/meta-launcher.c
parentf93fc1506b1ca2cf6e65521a22a8d27c96d363cf (diff)
downloadmutter-dcf64ca1678a2950842708bee146f09a063ed828.tar.gz
launcher: Replace mutter-launch with logind integration
This uses David Herrmann's new logind sessions interface to retrieve fds for input devices, rather than using a custom setuid helper to do the management. This vastly simplifies the interface. This requires systemd v210, at least. https://bugzilla.gnome.org/show_bug.cgi?id=724604
Diffstat (limited to 'src/backends/native/meta-launcher.c')
-rw-r--r--src/backends/native/meta-launcher.c433
1 files changed, 208 insertions, 225 deletions
diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
index 66755088e..751919464 100644
--- a/src/backends/native/meta-launcher.c
+++ b/src/backends/native/meta-launcher.c
@@ -20,9 +20,8 @@
#include "config.h"
#include "meta-launcher.h"
-#include "weston-launch.h"
-#include <gio/gunixfdmessage.h>
+#include <gio/gunixfdlist.h>
#include <clutter/clutter.h>
#include <clutter/egl/clutter-egl.h>
@@ -30,10 +29,17 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+
+#include <systemd/sd-login.h>
+
+#include "dbus-utils.h"
+#include "meta-dbus-login1.h"
#include "wayland/meta-wayland-private.h"
#include "backends/meta-backend.h"
@@ -41,153 +47,44 @@
struct _MetaLauncher
{
- GSocket *weston_launch;
- GSource *weston_launch_source;
+ Login1Session *session_proxy;
+ Login1Seat *seat_proxy;
- gboolean vt_switched;
+ gboolean session_active;
};
/* AAA BBB CCC */
-static void handle_request_vt_switch (MetaLauncher *self);
-
-static gboolean
-request_vt_switch_idle (gpointer user_data)
+static Login1Session *
+get_session_proxy (GCancellable *cancellable)
{
- handle_request_vt_switch (user_data);
+ char *proxy_path;
+ char *session_id;
+ Login1Session *session_proxy;
- return FALSE;
-}
+ if (sd_pid_get_session (getpid (), &session_id) < 0)
+ return NULL;
-static gboolean
-send_message_to_wl (MetaLauncher *self,
- void *message,
- gsize size,
- GSocketControlMessage *out_cmsg,
- GSocketControlMessage **in_cmsg,
- GError **error)
-{
- struct weston_launcher_reply reply;
- GInputVector in_iov = { &reply, sizeof (reply) };
- GOutputVector out_iov = { message, size };
- GSocketControlMessage *out_all_cmsg[2];
- GSocketControlMessage **in_all_cmsg;
- int flags = 0;
- int i;
-
- out_all_cmsg[0] = out_cmsg;
- out_all_cmsg[1] = NULL;
- if (g_socket_send_message (self->weston_launch, NULL,
- &out_iov, 1,
- out_all_cmsg, -1,
- flags, NULL, error) != (gssize)size)
- return FALSE;
-
- if (g_socket_receive_message (self->weston_launch, NULL,
- &in_iov, 1,
- &in_all_cmsg, NULL,
- &flags, NULL, error) != sizeof (reply))
- return FALSE;
+ proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
- while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
- {
- guint id;
-
- /* There were events queued */
- g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
-
- /* This can never happen, because the only time mutter-launch can queue
- this event is after confirming a VT switch, and we don't make requests
- during that time.
-
- Note that getting this event would be really bad, because we would be
- in the wrong loop/context.
- */
- g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
-
- switch (reply.header.opcode)
- {
- case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
- id = g_idle_add (request_vt_switch_idle, self);
- g_source_set_name_by_id (id, "[mutter] request_vt_switch_idle");
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- if (g_socket_receive_message (self->weston_launch, NULL,
- &in_iov, 1,
- NULL, NULL,
- &flags, NULL, error) != sizeof (reply))
- return FALSE;
- }
+ session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ "org.freedesktop.login1",
+ proxy_path,
+ cancellable, NULL);
+ free (proxy_path);
- if (reply.ret != 0)
- {
- if (reply.ret == -1)
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Got failure from weston-launch");
- else
- g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
- "Got failure from weston-launch: %s", strerror (-reply.ret));
-
- for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
- g_object_unref (in_all_cmsg[i]);
- g_free (in_all_cmsg);
-
- return FALSE;
- }
-
- if (in_all_cmsg && in_all_cmsg[0])
- {
- for (i = 1; in_all_cmsg[i]; i++)
- g_object_unref (in_all_cmsg[i]);
- *in_cmsg = in_all_cmsg[0];
- }
-
- g_free (in_all_cmsg);
- return TRUE;
+ return session_proxy;
}
-static int
-meta_launcher_open_device (MetaLauncher *self,
- const char *name,
- int flags,
- GError **error)
+static Login1Seat *
+get_seat_proxy (GCancellable *cancellable)
{
- struct weston_launcher_open *message;
- GSocketControlMessage *cmsg;
- gboolean ok;
- gsize size;
- int *fds, n_fd;
- int ret;
-
- size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
- message = g_malloc (size);
- message->header.opcode = WESTON_LAUNCHER_OPEN;
- message->flags = flags;
- strcpy (message->path, name);
- message->path[strlen(name)] = 0;
-
- ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
-
- if (ok)
- {
- g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
-
- fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
- g_assert (n_fd == 1);
-
- ret = fds[0];
- g_free (fds);
- g_object_unref (cmsg);
- }
- else
- ret = -1;
-
- g_free (message);
- return ret;
+ return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1/seat/self",
+ cancellable, NULL);
}
/* QQQ RRR SSS */
@@ -228,107 +125,190 @@ session_pause (void)
clutter_egl_freeze_master_clock ();
}
+static gboolean
+take_device (Login1Session *session_proxy,
+ int dev_major,
+ int dev_minor,
+ int *out_fd,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *fd_variant = NULL;
+ int fd = -1;
+ GUnixFDList *fd_list;
+
+ if (!login1_session_call_take_device_sync (session_proxy,
+ dev_major,
+ dev_minor,
+ NULL,
+ &fd_variant,
+ NULL, /* paused */
+ &fd_list,
+ cancellable,
+ error))
+ goto out;
+
+ fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
+ if (fd == -1)
+ goto out;
+
+ *out_fd = fd;
+ ret = TRUE;
+
+ out:
+ if (fd_variant)
+ g_variant_unref (fd_variant);
+ if (fd_list)
+ g_object_unref (fd_list);
+ return ret;
+}
+
+static gboolean
+get_device_info_from_path (const char *path,
+ int *out_major,
+ int *out_minor)
+{
+ gboolean ret = FALSE;
+ int r;
+ struct stat st;
+
+ r = stat (path, &st);
+ if (r < 0)
+ goto out;
+ if (!S_ISCHR (st.st_mode))
+ goto out;
+
+ *out_major = major (st.st_rdev);
+ *out_minor = minor (st.st_rdev);
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+static gboolean
+get_device_info_from_fd (int fd,
+ int *out_major,
+ int *out_minor)
+{
+ gboolean ret = FALSE;
+ int r;
+ struct stat st;
+
+ r = fstat (fd, &st);
+ if (r < 0)
+ goto out;
+ if (!S_ISCHR (st.st_mode))
+ goto out;
+
+ *out_major = major (st.st_rdev);
+ *out_minor = minor (st.st_rdev);
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
static int
on_evdev_device_open (const char *path,
int flags,
gpointer user_data,
GError **error)
{
- MetaLauncher *launcher = user_data;
+ MetaLauncher *self = user_data;
+ int fd;
+ int major, minor;
+
+ if (!get_device_info_from_path (path, &major, &minor))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ "Could not get device info for path %s: %m", path);
+ return -1;
+ }
+
+ if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
+ return -1;
- return meta_launcher_open_device (launcher, path, flags, error);
+ return fd;
}
static void
on_evdev_device_close (int fd,
gpointer user_data)
{
- close (fd);
+ MetaLauncher *self = user_data;
+ int major, minor;
+ GError *error = NULL;
+
+ if (!get_device_info_from_fd (fd, &major, &minor))
+ {
+ g_warning ("Could not get device info for fd %d: %m", fd);
+ return;
+ }
+
+ if (!login1_session_call_release_device_sync (self->session_proxy,
+ major, minor,
+ NULL, &error))
+ {
+ g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
+ }
}
/* TTT UUU VVV */
static void
-handle_vt_enter (MetaLauncher *launcher)
+sync_active (MetaLauncher *self)
{
- g_assert (launcher->vt_switched);
- launcher->vt_switched = FALSE;
+ gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
+
+ if (active == self->session_active)
+ return;
- session_unpause ();
+ self->session_active = active;
+
+ if (active)
+ session_unpause ();
+ else
+ session_pause ();
}
static void
-handle_request_vt_switch (MetaLauncher *launcher)
+on_active_changed (Login1Session *session,
+ GParamSpec *pspec,
+ gpointer user_data)
{
- struct weston_launcher_message message;
- GError *error;
- gboolean ok;
-
- session_pause ();
-
- message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
-
- error = NULL;
- ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
- if (!ok) {
- g_warning ("Failed to acknowledge VT switch: %s", error->message);
- g_error_free (error);
- return;
- }
-
- g_assert (!launcher->vt_switched);
- launcher->vt_switched = TRUE;
-
- session_unpause ();
+ MetaLauncher *self = user_data;
+ sync_active (self);
}
static gboolean
-on_socket_readable (GSocket *socket,
- GIOCondition condition,
- gpointer user_data)
+get_kms_fd (Login1Session *session_proxy,
+ int *fd_out)
{
- MetaLauncher *launcher = user_data;
- struct weston_launcher_event event;
- gssize read;
- GError *error;
-
- if ((condition & G_IO_IN) == 0)
- return TRUE;
+ int major, minor;
+ int fd;
+ GError *error = NULL;
- error = NULL;
- read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
- if (read < (gssize)sizeof(event))
+ /* XXX -- use udev to find the DRM master device */
+ if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
{
- g_warning ("Error reading from weston-launcher socket: %s", error->message);
- g_error_free (error);
- return TRUE;
+ g_warning ("Could not stat /dev/dri/card0: %m");
+ return FALSE;
}
- switch (event.header.opcode)
+ if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
{
- case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
- handle_request_vt_switch (launcher);
- break;
-
- case WESTON_LAUNCHER_SERVER_VT_ENTER:
- handle_vt_enter (launcher);
- break;
+ g_warning ("Could not open DRM device: %s\n", error->message);
+ g_error_free (error);
+ return FALSE;
}
- return TRUE;
-}
-
-static int
-env_get_fd (const char *env)
-{
- const char *value;
-
- value = g_getenv (env);
+ *fd_out = fd;
- if (value == NULL)
- return -1;
- else
- return g_ascii_strtoll (value, NULL, 10);
+ return TRUE;
}
/* XXX YYY ZZZ */
@@ -336,47 +316,55 @@ env_get_fd (const char *env)
MetaLauncher *
meta_launcher_new (void)
{
- MetaLauncher *self = g_slice_new0 (MetaLauncher);
+ MetaLauncher *self;
+ Login1Session *session_proxy;
GError *error = NULL;
- int launch_fd;
int kms_fd;
- launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
- if (launch_fd < 0)
- g_error ("Invalid mutter-launch socket");
+ session_proxy = get_session_proxy (NULL);
+ if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
+ {
+ g_warning ("Could not take control: %s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
- self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
+ if (!get_kms_fd (session_proxy, &kms_fd))
+ return NULL;
- self->weston_launch_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
- g_source_set_callback (self->weston_launch_source, (GSourceFunc)on_socket_readable, self, NULL);
- g_source_attach (self->weston_launch_source, NULL);
- g_source_unref (self->weston_launch_source);
+ self = g_slice_new0 (MetaLauncher);
+ self->session_proxy = session_proxy;
+ self->seat_proxy = get_seat_proxy (NULL);
- kms_fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error);
- if (error)
- g_error ("Failed to open /dev/dri/card0: %s", error->message);
+ self->session_active = TRUE;
clutter_egl_set_kms_fd (kms_fd);
clutter_evdev_set_device_callbacks (on_evdev_device_open,
on_evdev_device_close,
self);
+ g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
+
return self;
}
void
-meta_launcher_free (MetaLauncher *launcher)
+meta_launcher_free (MetaLauncher *self)
{
- g_source_destroy (launcher->weston_launch_source);
- g_object_unref (launcher->weston_launch);
- g_slice_free (MetaLauncher, launcher);
+ g_object_unref (self->seat_proxy);
+ g_object_unref (self->session_proxy);
+ g_slice_free (MetaLauncher, self);
}
gboolean
meta_launcher_activate_session (MetaLauncher *launcher,
GError **error)
{
- return meta_launcher_activate_vt (launcher, -1, error);
+ if (!login1_session_call_activate_sync (launcher->session_proxy, NULL, error))
+ return FALSE;
+
+ sync_active (launcher);
+ return TRUE;
}
gboolean
@@ -384,10 +372,5 @@ meta_launcher_activate_vt (MetaLauncher *launcher,
signed char vt,
GError **error)
{
- struct weston_launcher_activate_vt message;
-
- message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
- message.vt = vt;
-
- return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
+ return login1_seat_call_switch_to_sync (launcher->seat_proxy, vt, NULL, error);
}