On Tue, Oct 15, 2013 at 02:30:02PM +0200, David Herrmann wrote:
> Instead of spawning weston-launch from the launcher-util, we now try to
> connect to logind first. If logind provides session-devices, we use them.
> If not, we fall back to the old weston-launch facility.
> ---
>  configure.ac           |   1 +
>  src/Makefile.am        |   8 +
>  src/compositor-drm.c   |   2 +-
>  src/compositor-fbdev.c |   2 +-
>  src/compositor-rpi.c   |   2 +-
>  src/launcher-util.c    |  40 ++-
>  src/launcher-util.h    |   3 +-
>  src/logind-util.c      | 913 
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/logind-util.h      |  94 +++++
>  9 files changed, 1054 insertions(+), 11 deletions(-)
>  create mode 100644 src/logind-util.c
>  create mode 100644 src/logind-util.h

I applied the whole patch series and stubbed out the call to
sd_session_get_vt() (instead of updating systemd), but I then get

[11:35:04.658] logind: cannot take control over session 4

in the weston log and journalctl tells me

Oct 15 11:34:52 tokamak.local dbus-daemon[444]: dbus[444]: [system] Rejected 
send message, 2 matched rules; type="method_call", sender=":1.75" (uid=1000 
pid=17613 comm="weston --tty=2 ") interface="org.freedesktop.login1.Session" 
member="TakeControl" error name="(unset)" requested_reply="0" 
destination="org.freedesktop.login1" (uid=0 pid=441 
comm="/usr/lib/systemd/systemd-logind ")
Oct 15 11:34:52 tokamak.local dbus[444]: [system] Rejected send message, 2 
matched rules; type="method_call", sender=":1.75" (uid=1000 pid=17613 
comm="weston --tty=2 ") interface="org.freedesktop.login1.Session" 
member="TakeControl" error name="(unset)" requested_reply="0" 
destination="org.freedesktop.login1" (uid=0 pid=441 
comm="/usr/lib/systemd/systemd-logind ")

Also, logind-util.c does all the vt setup and teardown, but I wonder
what happens if weston crashes.  Will logind reset the vt (unmute,
KD_TEXT etc) or will the system get stuck?  One of the benefits of the
recent weston-launch rewrite was that weston-launch will clean up if
weston crashes, which is much more reliable.

Kristian

> diff --git a/configure.ac b/configure.ac
> index 643209c..ace1305 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -325,6 +325,7 @@ PKG_CHECK_MODULES(SYSTEMD_LOGIN_207, [libsystemd-login >= 
> 207],
>                    [have_systemd_login_207=yes], [have_systemd_login_207=no])
>  AS_IF([test "x$have_systemd_login_207" = "xyes"],
>        [AC_DEFINE([HAVE_SYSTEMD_LOGIN_207], [1], [Have systemd-login >= 
> 207])])
> +AM_CONDITIONAL(HAVE_SYSTEMD_LOGIN_207, test "x$have_systemd_login_207" = 
> "xyes")
>  
>  PKG_CHECK_MODULES(LAUNCHER_UTIL, [libsystemd-login],,)
>  PKG_CHECK_MODULES(WESTON_LAUNCH, [libdrm libsystemd-login],,)
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 44ebfc2..bdfef9f 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -54,6 +54,14 @@ weston_SOURCES +=                          \
>       dbus.c
>  weston_CFLAGS += $(DBUS_CFLAGS)
>  weston_LDADD += $(DBUS_LIBS)
> +
> +if HAVE_SYSTEMD_LOGIN_207
> +weston_SOURCES +=                            \
> +     logind-util.h                           \
> +     logind-util.c
> +weston_CFLAGS += $(SYSTEMD_LOGIN_207_CFLAGS)
> +weston_LDADD += $(SYSTEMD_LOGIN_207_LIBS)
> +endif
>  endif
>  
>  git-version.h : .FORCE
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index 25c34f8..052d594 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -2599,7 +2599,7 @@ drm_compositor_create(struct wl_display *display,
>       }
>  
>       /* Check if we run drm-backend using weston-launch */
> -     ec->base.launcher = weston_launcher_connect(&ec->base, tty);
> +     ec->base.launcher = weston_launcher_connect(&ec->base, tty, seat_id);
>       if (ec->base.launcher == NULL) {
>               weston_log("fatal: drm backend should be run "
>                          "using weston-launch binary or as root\n");
> diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
> index 4376345..80e708d 100644
> --- a/src/compositor-fbdev.c
> +++ b/src/compositor-fbdev.c
> @@ -894,7 +894,7 @@ fbdev_compositor_create(struct wl_display *display, int 
> *argc, char *argv[],
>       wl_signal_add(&compositor->base.session_signal,
>                     &compositor->session_listener);
>       compositor->base.launcher =
> -             weston_launcher_connect(&compositor->base, param->tty);
> +             weston_launcher_connect(&compositor->base, param->tty, "seat0");
>       if (!compositor->base.launcher) {
>               weston_log("fatal: fbdev backend should be run "
>                          "using weston-launch binary or as root\n");
> diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
> index 05667fb..07816a5 100644
> --- a/src/compositor-rpi.c
> +++ b/src/compositor-rpi.c
> @@ -752,7 +752,7 @@ rpi_compositor_create(struct wl_display *display, int 
> *argc, char *argv[],
>       wl_signal_add(&compositor->base.session_signal,
>                     &compositor ->session_listener);
>       compositor->base.launcher =
> -             weston_launcher_connect(&compositor->base, param->tty);
> +             weston_launcher_connect(&compositor->base, param->tty, "seat0");
>       if (!compositor->base.launcher) {
>               weston_log("Failed to initialize tty.\n");
>               goto out_udev;
> diff --git a/src/launcher-util.c b/src/launcher-util.c
> index 30e62fc..2a431a8 100644
> --- a/src/launcher-util.c
> +++ b/src/launcher-util.c
> @@ -43,6 +43,7 @@
>  
>  #include "compositor.h"
>  #include "launcher-util.h"
> +#include "logind-util.h"
>  #include "weston-launch.h"
>  
>  #ifndef KDSKBMUTE
> @@ -57,6 +58,7 @@ union cmsg_data { unsigned char b[4]; int fd; };
>  
>  struct weston_launcher {
>       struct weston_compositor *compositor;
> +     struct weston_logind *logind;
>       struct passwd *pw;
>       struct weston_process launcher;
>       int fd, event_fd;
> @@ -87,6 +89,9 @@ weston_launcher_open(struct weston_launcher *launcher,
>       ssize_t len;
>       struct weston_launcher_open *message;
>  
> +     if (launcher->logind)
> +             return weston_logind_open(launcher->logind, path, flags);
> +
>       n = sizeof(*message) + strlen(path) + 1;
>       message = malloc(n);
>       if (!message)
> @@ -140,6 +145,9 @@ weston_launcher_open(struct weston_launcher *launcher,
>  void
>  weston_launcher_close(struct weston_launcher *launcher, int fd)
>  {
> +     if (launcher->logind)
> +             return weston_logind_close(launcher->logind, fd);
> +
>       close(fd);
>  }
>  
> @@ -148,6 +156,9 @@ weston_launcher_restore(struct weston_launcher *launcher)
>  {
>       struct vt_mode mode = { 0 };
>  
> +     if (launcher->logind)
> +             return weston_logind_restore(launcher->logind);
> +
>       ioctl(launcher->tty, KDSKBMUTE, 0);
>       ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode);
>       ioctl(launcher->tty, KDSETMODE, KD_TEXT);
> @@ -197,6 +208,9 @@ weston_launcher_activate_vt(struct weston_launcher 
> *launcher, int vt)
>       ssize_t len;
>       struct weston_launcher_switchvt message;
>  
> +     if (launcher->logind)
> +             return weston_logind_activate_vt(launcher->logind, vt);
> +
>       /* VT_ACTIVATE is a privileged ioctl so ask weston-launch */
>  
>       message.header.opcode = WESTON_LAUNCHER_SWITCHVT;
> @@ -398,7 +412,8 @@ setup_tty(struct weston_launcher *wl, int ttyid)
>  }
>  
>  struct weston_launcher *
> -weston_launcher_connect(struct weston_compositor *compositor, int tty)
> +weston_launcher_connect(struct weston_compositor *compositor, int tty,
> +                     const char *seat_id)
>  {
>       struct weston_launcher *launcher;
>       struct wl_event_loop *loop;
> @@ -414,6 +429,12 @@ weston_launcher_connect(struct weston_compositor 
> *compositor, int tty)
>       launcher->fd = -1;
>       launcher->event_fd = -1;
>  
> +     r = weston_logind_connect(&launcher->logind, compositor, seat_id, tty);
> +     if (r >= 0)
> +             return launcher;
> +
> +     launcher->logind = NULL;
> +
>       r = setup_tty(launcher, tty);
>       if (r < 0)
>               goto err_free;
> @@ -448,11 +469,16 @@ err_free:
>  void
>  weston_launcher_destroy(struct weston_launcher *launcher)
>  {
> -     wl_list_remove(&launcher->launcher.link);
> -     wl_event_source_remove(launcher->source);
> -     close(launcher->event_fd);
> -     close(launcher->fd);
> -     weston_launcher_restore(launcher);
> -     close(launcher->tty);
> +     if (launcher->logind) {
> +             weston_logind_destroy(launcher->logind);
> +     } else {
> +             wl_list_remove(&launcher->launcher.link);
> +             wl_event_source_remove(launcher->source);
> +             close(launcher->event_fd);
> +             close(launcher->fd);
> +             weston_launcher_restore(launcher);
> +             close(launcher->tty);
> +     }
> +
>       free(launcher);
>  }
> diff --git a/src/launcher-util.h b/src/launcher-util.h
> index 9de5237..d5b2fc9 100644
> --- a/src/launcher-util.h
> +++ b/src/launcher-util.h
> @@ -30,7 +30,8 @@
>  struct weston_launcher;
>  
>  struct weston_launcher *
> -weston_launcher_connect(struct weston_compositor *compositor, int tty);
> +weston_launcher_connect(struct weston_compositor *compositor, int tty,
> +                     const char *seat_id);
>  
>  void
>  weston_launcher_destroy(struct weston_launcher *launcher);
> diff --git a/src/logind-util.c b/src/logind-util.c
> new file mode 100644
> index 0000000..066f751
> --- /dev/null
> +++ b/src/logind-util.c
> @@ -0,0 +1,913 @@
> +/*
> + * Copyright © 2013 David Herrmann
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include "config.h"
> +
> +#include <errno.h>
> +#include <dbus.h>
> +#include <fcntl.h>
> +#include <linux/vt.h>
> +#include <linux/kd.h>
> +#include <linux/major.h>
> +#include <signal.h>
> +#include <stdarg.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <sys/signalfd.h>
> +#include <sys/stat.h>
> +#include <systemd/sd-login.h>
> +#include <unistd.h>
> +
> +#include "compositor.h"
> +#include "dbus.h"
> +#include "logind-util.h"
> +
> +#ifndef KDSKBMUTE
> +#define KDSKBMUTE    0x4B51
> +#endif
> +
> +struct weston_logind {
> +     struct weston_compositor *compositor;
> +     char *seat;
> +     char *sid;
> +     unsigned int vtnr;
> +     int vt;
> +     int kb_mode;
> +     int sfd;
> +     struct wl_event_source *sfd_source;
> +
> +     DBusConnection *dbus;
> +     struct wl_event_source *dbus_ctx;
> +     char *spath;
> +     DBusPendingCall *pending_active;
> +};
> +
> +static int
> +weston_logind_take_device(struct weston_logind *wl, uint32_t major,
> +                       uint32_t minor, bool *paused_out)
> +{
> +     DBusMessage *m, *reply;
> +     bool b, paused;
> +     int r, fd;
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.login1.Session",
> +                                      "TakeDevice");
> +     if (!m)
> +             return -ENOMEM;
> +
> +     b = dbus_message_append_args(m,
> +                                  DBUS_TYPE_UINT32, &major,
> +                                  DBUS_TYPE_UINT32, &minor,
> +                                  DBUS_TYPE_INVALID);
> +     if (!b) {
> +             r = -ENOMEM;
> +             goto err_unref;
> +     }
> +
> +     reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
> +                                                       -1, NULL);
> +     if (!reply) {
> +             r = -ENODEV;
> +             goto err_unref;
> +     }
> +
> +     b = dbus_message_get_args(reply, NULL,
> +                               DBUS_TYPE_UNIX_FD, &fd,
> +                               DBUS_TYPE_BOOLEAN, &paused,
> +                               DBUS_TYPE_INVALID);
> +     if (!b) {
> +             r = -ENODEV;
> +             goto err_reply;
> +     }
> +
> +     r = fd;
> +     if (paused_out)
> +             *paused_out = paused;
> +
> +err_reply:
> +     dbus_message_unref(reply);
> +err_unref:
> +     dbus_message_unref(m);
> +     return r;
> +}
> +
> +static void
> +weston_logind_release_device(struct weston_logind *wl, uint32_t major,
> +                          uint32_t minor)
> +{
> +     DBusMessage *m;
> +     bool b;
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.login1.Session",
> +                                      "ReleaseDevice");
> +     if (m) {
> +             b = dbus_message_append_args(m,
> +                                          DBUS_TYPE_UINT32, &major,
> +                                          DBUS_TYPE_UINT32, &minor,
> +                                          DBUS_TYPE_INVALID);
> +             if (b)
> +                     dbus_connection_send(wl->dbus, m, NULL);
> +             dbus_message_unref(m);
> +     }
> +}
> +
> +static void
> +weston_logind_pause_device_complete(struct weston_logind *wl, uint32_t major,
> +                                 uint32_t minor)
> +{
> +     DBusMessage *m;
> +     bool b;
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.login1.Session",
> +                                      "PauseDeviceComplete");
> +     if (m) {
> +             b = dbus_message_append_args(m,
> +                                          DBUS_TYPE_UINT32, &major,
> +                                          DBUS_TYPE_UINT32, &minor,
> +                                          DBUS_TYPE_INVALID);
> +             if (b)
> +                     dbus_connection_send(wl->dbus, m, NULL);
> +             dbus_message_unref(m);
> +     }
> +}
> +
> +WL_EXPORT int
> +weston_logind_open(struct weston_logind *wl, const char *path,
> +                int flags)
> +{
> +     struct stat st;
> +     int fl, r, fd;
> +
> +     r = stat(path, &st);
> +     if (r < 0)
> +             return -errno;
> +     if (!S_ISCHR(st.st_mode))
> +             return -ENODEV;
> +
> +     fd = weston_logind_take_device(wl, major(st.st_rdev),
> +                                    minor(st.st_rdev), NULL);
> +     if (fd < 0)
> +             return fd;
> +
> +     /* Compared to weston_launcher_open() we cannot specify the open-mode
> +      * directly. Instead, logind passes us an fd with sane default modes.
> +      * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
> +      * something else, we need to change it afterwards. We currently
> +      * only support dropping FD_CLOEXEC and setting O_NONBLOCK. Changing
> +      * access-modes is not possible so accept whatever logind passes us. */
> +
> +     fl = fcntl(fd, F_GETFL);
> +     if (fl < 0) {
> +             r = -errno;
> +             goto err_close;
> +     }
> +
> +     if (flags & O_NONBLOCK)
> +             fl |= O_NONBLOCK;
> +
> +     r = fcntl(fd, F_SETFL, fl);
> +     if (r < 0) {
> +             r = -errno;
> +             goto err_close;
> +     }
> +
> +     fl = fcntl(fd, F_GETFD);
> +     if (fl < 0) {
> +             r = -errno;
> +             goto err_close;
> +     }
> +
> +     if (!(flags & O_CLOEXEC))
> +             fl &= ~FD_CLOEXEC;
> +
> +     r = fcntl(fd, F_SETFD, fl);
> +     if (r < 0) {
> +             r = -errno;
> +             goto err_close;
> +     }
> +
> +     return fd;
> +
> +err_close:
> +     close(fd);
> +     weston_logind_release_device(wl, major(st.st_rdev),
> +                                  minor(st.st_rdev));
> +     return r;
> +}
> +
> +WL_EXPORT void
> +weston_logind_close(struct weston_logind *wl, int fd)
> +{
> +     struct stat st;
> +     int r;
> +
> +     r = fstat(fd, &st);
> +     if (r < 0) {
> +             weston_log("logind: cannot fstat fd: %m\n");
> +             return;
> +     }
> +
> +     if (!S_ISCHR(st.st_mode)) {
> +             weston_log("logind: invalid device passed\n");
> +             return;
> +     }
> +
> +     weston_logind_release_device(wl, major(st.st_rdev),
> +                                  minor(st.st_rdev));
> +}
> +
> +WL_EXPORT void
> +weston_logind_restore(struct weston_logind *wl)
> +{
> +     struct vt_mode mode = { 0 };
> +
> +     ioctl(wl->vt, KDSETMODE, KD_TEXT);
> +     ioctl(wl->vt, KDSKBMUTE, 0);
> +     ioctl(wl->vt, KDSKBMODE, wl->kb_mode);
> +     mode.mode = VT_AUTO;
> +     ioctl(wl->vt, VT_SETMODE, &mode);
> +}
> +
> +WL_EXPORT int
> +weston_logind_activate_vt(struct weston_logind *wl, int vt)
> +{
> +     int r;
> +
> +     r = ioctl(wl->vt, VT_ACTIVATE, vt);
> +     if (r < 0)
> +             return -errno;
> +
> +     return 0;
> +}
> +
> +static void
> +weston_logind_set_active(struct weston_logind *wl, bool active)
> +{
> +     if (active)
> +             wl->compositor->session_active = 1;
> +     else
> +             wl->compositor->session_active = 0;
> +
> +     wl_signal_emit(&wl->compositor->session_signal,
> +                    wl->compositor);
> +}
> +
> +static void
> +get_active_cb(DBusPendingCall *pending, void *data)
> +{
> +     struct weston_logind *wl = data;
> +     DBusMessage *m;
> +     DBusMessageIter iter, sub;
> +     int type;
> +     bool b;
> +
> +     dbus_pending_call_unref(wl->pending_active);
> +     wl->pending_active = NULL;
> +
> +     m = dbus_pending_call_steal_reply(pending);
> +     if (!m)
> +             return;
> +
> +     type = dbus_message_get_type(m);
> +     if (type != DBUS_MESSAGE_TYPE_METHOD_RETURN)
> +             goto err_unref;
> +
> +     if (!dbus_message_iter_init(m, &iter) ||
> +         dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
> +             goto err_unref;
> +
> +     dbus_message_iter_recurse(&iter, &sub);
> +
> +     if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
> +             goto err_unref;
> +
> +     dbus_message_iter_get_basic(&sub, &b);
> +     weston_logind_set_active(wl, b);
> +
> +err_unref:
> +     dbus_message_unref(m);
> +}
> +
> +static void
> +weston_logind_get_active(struct weston_logind *wl)
> +{
> +     DBusPendingCall *pending;
> +     DBusMessage *m;
> +     bool b;
> +     const char *iface, *name;
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.DBus.Properties",
> +                                      "Get");
> +     if (!m)
> +             return;
> +
> +     iface = "org.freedesktop.login1.Session";
> +     name = "Active";
> +     b = dbus_message_append_args(m,
> +                                  DBUS_TYPE_STRING, &iface,
> +                                  DBUS_TYPE_STRING, &name,
> +                                  DBUS_TYPE_INVALID);
> +     if (!b)
> +             goto err_unref;
> +
> +     b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
> +     if (!b)
> +             goto err_unref;
> +
> +     b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
> +     if (!b) {
> +             dbus_pending_call_cancel(pending);
> +             dbus_pending_call_unref(pending);
> +             goto err_unref;
> +     }
> +
> +     if (wl->pending_active) {
> +             dbus_pending_call_cancel(wl->pending_active);
> +             dbus_pending_call_unref(wl->pending_active);
> +     }
> +     wl->pending_active = pending;
> +     return;
> +
> +err_unref:
> +     dbus_message_unref(m);
> +}
> +
> +static void
> +disconnected_dbus(struct weston_logind *wl)
> +{
> +     weston_log("logind: dbus connection lost, exiting..\n");
> +     weston_logind_restore(wl);
> +     exit(-1);
> +}
> +
> +static void
> +session_removed(struct weston_logind *wl, DBusMessage *m)
> +{
> +     const char *name, *obj;
> +     bool r;
> +
> +     r = dbus_message_get_args(m, NULL,
> +                               DBUS_TYPE_STRING, &name,
> +                               DBUS_TYPE_OBJECT_PATH, &obj,
> +                               DBUS_TYPE_INVALID);
> +     if (!r) {
> +             weston_log("logind: cannot parse SessionRemoved dbus signal\n");
> +             return;
> +     }
> +
> +     if (!strcmp(name, wl->sid)) {
> +             weston_log("logind: our session got closed, exiting..\n");
> +             weston_logind_restore(wl);
> +             exit(-1);
> +     }
> +}
> +
> +static void
> +property_changed(struct weston_logind *wl, DBusMessage *m)
> +{
> +     DBusMessageIter iter, sub, entry;
> +     const char *interface, *name;
> +     dbus_bool_t b;
> +
> +     if (!dbus_message_iter_init(m, &iter) ||
> +         dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
> +             goto error;
> +
> +     dbus_message_iter_get_basic(&iter, &interface);
> +
> +     if (!dbus_message_iter_next(&iter) ||
> +         dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
> +             goto error;
> +
> +     dbus_message_iter_recurse(&iter, &sub);
> +
> +     while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
> +             dbus_message_iter_recurse(&sub, &entry);
> +
> +             if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
> +                     goto error;
> +
> +             dbus_message_iter_get_basic(&entry, &name);
> +             if (!dbus_message_iter_next(&entry))
> +                     goto error;
> +
> +             if (!strcmp(name, "Active")) {
> +                     if (dbus_message_iter_get_arg_type(&entry) == 
> DBUS_TYPE_BOOLEAN) {
> +                             dbus_message_iter_get_basic(&entry, &b);
> +                             weston_logind_set_active(wl, b);
> +                             return;
> +                     }
> +             }
> +
> +             dbus_message_iter_next(&sub);
> +     }
> +
> +     if (!dbus_message_iter_next(&iter) ||
> +         dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
> +             goto error;
> +
> +     dbus_message_iter_recurse(&iter, &sub);
> +
> +     while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
> +             dbus_message_iter_get_basic(&sub, &name);
> +
> +             if (!strcmp(name, "Active")) {
> +                     weston_logind_get_active(wl);
> +                     return;
> +             }
> +
> +             dbus_message_iter_next(&sub);
> +     }
> +
> +     return;
> +
> +error:
> +     weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
> +}
> +
> +static void
> +device_paused(struct weston_logind *wl, DBusMessage *m)
> +{
> +     bool r;
> +     const char *type;
> +     uint32_t major, minor;
> +
> +     r = dbus_message_get_args(m, NULL,
> +                               DBUS_TYPE_UINT32, &major,
> +                               DBUS_TYPE_UINT32, &minor,
> +                               DBUS_TYPE_STRING, &type,
> +                               DBUS_TYPE_INVALID);
> +     if (!r) {
> +             weston_log("logind: cannot parse PauseDevice dbus signal\n");
> +             return;
> +     }
> +
> +     /* "pause" means synchronous pausing. Acknowledge it unconditionally
> +      * as we support asynchronous device shutdowns, anyway.
> +      * "force" means asynchronous pausing. We ignore it as the following
> +      * session-deactivation will suffice as notification.
> +      * "gone" means the device is gone. We ignore it as we receive a
> +      * udev notification, anyway. */
> +
> +     if (!strcmp(type, "pause"))
> +             weston_logind_pause_device_complete(wl, major, minor);
> +}
> +
> +static void
> +device_resumed(struct weston_logind *wl, DBusMessage *m)
> +{
> +     /*
> +      * DeviceResumed messages provide us a new file-descriptor for
> +      * resumed devices. For DRM devices it's the same as before, for evdev
> +      * devices it's a new open-file. As we reopen evdev devices, anyway,
> +      * there is no need for us to handle this event. If we ever optimize
> +      * our evdev code to support resuming devices, this event can be
> +      * parsed like this:
> +      * r = dbus_message_get_args(m, NULL,
> +      *                        DBUS_TYPE_UINT32, &major,
> +      *                        DBUS_TYPE_UINT32, &minor,
> +      *                        DBUS_TYPE_UNIX_FD, &fd,
> +      *                        DBUS_TYPE_INVALID);
> +      */
> +}
> +
> +static DBusHandlerResult
> +filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
> +{
> +     struct weston_logind *wl = data;
> +
> +     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
> +             disconnected_dbus(wl);
> +     } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
> +                                       "SessionRemoved")) {
> +             session_removed(wl, m);
> +     } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
> +                                       "PropertiesChanged")) {
> +             property_changed(wl, m);
> +     } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
> +                                       "PauseDevice")) {
> +             device_paused(wl, m);
> +     } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
> +                                       "ResumeDevice")) {
> +             device_resumed(wl, m);
> +     }
> +
> +     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
> +}
> +
> +static int
> +weston_logind_setup_dbus(struct weston_logind *wl)
> +{
> +     bool b;
> +     int r;
> +
> +     r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
> +                  wl->sid);
> +     if (r < 0)
> +             return -ENOMEM;
> +
> +     b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
> +     if (!b) {
> +             weston_log("logind: cannot add dbus filter\n");
> +             r = -ENOMEM;
> +             goto err_spath;
> +     }
> +
> +     r = weston_dbus_add_match_signal(wl->dbus,
> +                                      "org.freedesktop.login1",
> +                                      "org.freedesktop.login1.Manager",
> +                                      "SessionRemoved",
> +                                      "/org/freedesktop/login1");
> +     if (r < 0) {
> +             weston_log("logind: cannot add dbus match\n");
> +             goto err_spath;
> +     }
> +
> +     r = weston_dbus_add_match_signal(wl->dbus,
> +                                     "org.freedesktop.login1",
> +                                     "org.freedesktop.login1.Session",
> +                                     "PauseDevice",
> +                                     wl->spath);
> +     if (r < 0) {
> +             weston_log("logind: cannot add dbus match\n");
> +             goto err_spath;
> +     }
> +
> +     r = weston_dbus_add_match_signal(wl->dbus,
> +                                     "org.freedesktop.login1",
> +                                     "org.freedesktop.login1.Session",
> +                                     "ResumeDevice",
> +                                     wl->spath);
> +     if (r < 0) {
> +             weston_log("logind: cannot add dbus match\n");
> +             goto err_spath;
> +     }
> +
> +     r = weston_dbus_add_match_signal(wl->dbus,
> +                                     "org.freedesktop.login1",
> +                                     "org.freedesktop.DBus.Properties",
> +                                     "PropertiesChanged",
> +                                     wl->spath);
> +     if (r < 0) {
> +             weston_log("logind: cannot add dbus match\n");
> +             goto err_spath;
> +     }
> +
> +     return 0;
> +
> +err_spath:
> +     /* don't remove any dbus-match as the connection is closed, anyway */
> +     free(wl->spath);
> +     return r;
> +}
> +
> +static void
> +weston_logind_destroy_dbus(struct weston_logind *wl)
> +{
> +     /* don't remove any dbus-match as the connection is closed, anyway */
> +     free(wl->spath);
> +}
> +
> +static int
> +weston_logind_take_control(struct weston_logind *wl)
> +{
> +     DBusError err;
> +     DBusMessage *m, *reply;
> +     dbus_bool_t force;
> +     bool b;
> +     int r;
> +
> +     dbus_error_init(&err);
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.login1.Session",
> +                                      "TakeControl");
> +     if (!m)
> +             return -ENOMEM;
> +
> +     force = false;
> +     b = dbus_message_append_args(m,
> +                                  DBUS_TYPE_BOOLEAN, &force,
> +                                  DBUS_TYPE_INVALID);
> +     if (!b) {
> +             r = -ENOMEM;
> +             goto err_unref;
> +     }
> +
> +     reply = dbus_connection_send_with_reply_and_block(wl->dbus,
> +                                                       m, -1, &err);
> +     if (!reply) {
> +             if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
> +                     weston_log("logind: old systemd version detected\n");
> +             else
> +                     weston_log("logind: cannot take control over session 
> %s\n", wl->sid);
> +
> +             dbus_error_free(&err);
> +             r = -EIO;
> +             goto err_unref;
> +     }
> +
> +     dbus_message_unref(reply);
> +     dbus_message_unref(m);
> +     return 0;
> +
> +err_unref:
> +     dbus_message_unref(m);
> +     return r;
> +}
> +
> +static void
> +weston_logind_release_control(struct weston_logind *wl)
> +{
> +     DBusMessage *m;
> +
> +     m = dbus_message_new_method_call("org.freedesktop.login1",
> +                                      wl->spath,
> +                                      "org.freedesktop.login1.Session",
> +                                      "ReleaseControl");
> +     if (m) {
> +             dbus_connection_send(wl->dbus, m, NULL);
> +             dbus_message_unref(m);
> +     }
> +}
> +
> +static int
> +signal_event(int fd, uint32_t mask, void *data)
> +{
> +     struct weston_logind *wl = data;
> +     struct signalfd_siginfo sig;
> +
> +     if (read(fd, &sig, sizeof sig) != sizeof sig) {
> +             weston_log("logind: cannot read signalfd: %m\n");
> +             return 0;
> +     }
> +
> +     switch (sig.ssi_signo) {
> +     case SIGUSR1:
> +             ioctl(wl->vt, VT_RELDISP, 1);
> +             break;
> +     case SIGUSR2:
> +             ioctl(wl->vt, VT_RELDISP, VT_ACKACQ);
> +             break;
> +     }
> +
> +     return 0;
> +}
> +
> +static int
> +weston_logind_setup_vt(struct weston_logind *wl)
> +{
> +     struct stat st;
> +     char buf[64];
> +     struct vt_mode mode = { 0 };
> +     int r;
> +     sigset_t mask;
> +     struct wl_event_loop *loop;
> +
> +     snprintf(buf, sizeof(buf), "/dev/tty%d", wl->vtnr);
> +     buf[sizeof(buf) - 1] = 0;
> +
> +     wl->vt = open(buf, O_RDWR|O_CLOEXEC|O_NONBLOCK);
> +
> +     if (wl->vt < 0) {
> +             r = -errno;
> +             weston_log("logind: cannot open VT %s: %m\n", buf);
> +             return r;
> +     }
> +
> +     if (fstat(wl->vt, &st) == -1 ||
> +         major(st.st_rdev) != TTY_MAJOR || minor(st.st_rdev) <= 0 ||
> +         minor(st.st_rdev) >= 64) {
> +             r = -EINVAL;
> +             weston_log("logind: TTY %s is no virtual terminal\n", buf);
> +             goto err_close;
> +     }
> +
> +     r = setsid();
> +     if (r < 0 && errno != EPERM) {
> +             r = -errno;
> +             weston_log("logind: setsid() failed: %m\n");
> +             goto err_close;
> +     }
> +
> +     r = ioctl(wl->vt, TIOCSCTTY, 0);
> +     if (r < 0)
> +             weston_log("logind: VT %s already in use\n", buf);
> +
> +     if (ioctl(wl->vt, KDGKBMODE, &wl->kb_mode) < 0) {
> +             weston_log("logind: cannot read keyboard mode on %s: %m\n",
> +                        buf);
> +             wl->kb_mode = K_UNICODE;
> +     } else if (wl->kb_mode == K_OFF) {
> +             wl->kb_mode = K_UNICODE;
> +     }
> +
> +     if (ioctl(wl->vt, KDSKBMUTE, 1) < 0 &&
> +         ioctl(wl->vt, KDSKBMODE, K_OFF) < 0) {
> +             r = -errno;
> +             weston_log("logind: cannot set K_OFF KB-mode on %s: %m\n",
> +                        buf);
> +             goto err_close;
> +     }
> +
> +     if (ioctl(wl->vt, KDSETMODE, KD_GRAPHICS) < 0) {
> +             r = -errno;
> +             weston_log("logind: cannot set KD_GRAPHICS mode on %s: %m\n",
> +                        buf);
> +             goto err_kbmode;
> +     }
> +
> +     sigemptyset(&mask);
> +     sigaddset(&mask, SIGUSR1);
> +     sigaddset(&mask, SIGUSR2);
> +     sigprocmask(SIG_BLOCK, &mask, NULL);
> +
> +     wl->sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
> +     if (wl->sfd < 0) {
> +             r = -errno;
> +             weston_log("logind: cannot create signalfd: %m\n");
> +             goto err_mode;
> +     }
> +
> +     loop = wl_display_get_event_loop(wl->compositor->wl_display);
> +     wl->sfd_source = wl_event_loop_add_fd(loop, wl->sfd,
> +                                           WL_EVENT_READABLE,
> +                                           signal_event, wl);
> +     if (!wl->sfd_source) {
> +             r = -errno;
> +             weston_log("logind: cannot create signalfd source: %m\n");
> +             goto err_sfd;
> +     }
> +
> +     mode.mode = VT_PROCESS;
> +     mode.relsig = SIGUSR1;
> +     mode.acqsig = SIGUSR2;
> +     if (ioctl(wl->vt, VT_SETMODE, &mode) < 0) {
> +             r = -errno;
> +             weston_log("logind: cannot take over VT: %m\n");
> +             goto err_sfd_source;
> +     }
> +
> +     weston_log("logind: using VT %s\n", buf);
> +     return 0;
> +
> +err_sfd_source:
> +     wl_event_source_remove(wl->sfd_source);
> +err_sfd:
> +     close(wl->sfd);
> +err_mode:
> +     ioctl(wl->vt, KDSETMODE, KD_TEXT);
> +err_kbmode:
> +     ioctl(wl->vt, KDSKBMUTE, 0);
> +     ioctl(wl->vt, KDSKBMODE, wl->kb_mode);
> +err_close:
> +     close(wl->vt);
> +     return r;
> +}
> +
> +static void
> +weston_logind_destroy_vt(struct weston_logind *wl)
> +{
> +     weston_logind_restore(wl);
> +     wl_event_source_remove(wl->sfd_source);
> +     close(wl->sfd);
> +     close(wl->vt);
> +}
> +
> +WL_EXPORT int
> +weston_logind_connect(struct weston_logind **out,
> +                   struct weston_compositor *compositor,
> +                   const char *seat_id, int tty)
> +{
> +     struct weston_logind *wl;
> +     struct wl_event_loop *loop;
> +     char *t;
> +     int r;
> +
> +     wl = calloc(1, sizeof(*wl));
> +     if (!wl) {
> +             r = -ENOMEM;
> +             goto err_out;
> +     }
> +
> +     wl->compositor = compositor;
> +
> +     wl->seat = strdup(seat_id);
> +     if (!wl->seat) {
> +             r = -ENOMEM;
> +             goto err_wl;
> +     }
> +
> +     r = sd_pid_get_session(getpid(), &wl->sid);
> +     if (r < 0) {
> +             weston_log("logind: not running in a systemd session\n");
> +             goto err_seat;
> +     }
> +
> +     t = NULL;
> +     r = sd_session_get_seat(wl->sid, &t);
> +     if (r < 0 || strcmp(seat_id, t)) {
> +             weston_log("logind: weston's seat '%s' differs from 
> session-seat '%s'\n",
> +                        seat_id, t);
> +             free(t);
> +             goto err_session;
> +     }
> +     free(t);
> +
> +     r = sd_session_get_vt(wl->sid, &wl->vtnr);
> +     if (r < 0) {
> +             weston_log("logind: session not running on a VT\n");
> +             goto err_session;
> +     } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
> +             weston_log("logind: requested VT --tty=%d differs from real 
> session VT %u\n",
> +                        tty, wl->vtnr);
> +             goto err_session;
> +     }
> +
> +     loop = wl_display_get_event_loop(compositor->wl_display);
> +     r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
> +     if (r < 0) {
> +             weston_log("logind: cannot connect to system dbus\n");
> +             goto err_session;
> +     }
> +
> +     r = weston_logind_setup_dbus(wl);
> +     if (r < 0)
> +             goto err_dbus;
> +
> +     r = weston_logind_take_control(wl);
> +     if (r < 0)
> +             goto err_dbus_cleanup;
> +
> +     r = weston_logind_setup_vt(wl);
> +     if (r < 0)
> +             goto err_control;
> +
> +     weston_log("logind: session control granted\n");
> +     *out = wl;
> +     return 0;
> +
> +err_control:
> +     weston_logind_release_control(wl);
> +err_dbus_cleanup:
> +     weston_logind_destroy_dbus(wl);
> +err_dbus:
> +     weston_dbus_close(wl->dbus, wl->dbus_ctx);
> +err_session:
> +     free(wl->sid);
> +err_seat:
> +     free(wl->seat);
> +err_wl:
> +     free(wl);
> +err_out:
> +     weston_log("logind: cannot setup systemd-logind helper (%d), using 
> legacy fallback\n", r);
> +     return r;
> +}
> +
> +WL_EXPORT void
> +weston_logind_destroy(struct weston_logind *wl)
> +{
> +     if (wl->pending_active) {
> +             dbus_pending_call_cancel(wl->pending_active);
> +             dbus_pending_call_unref(wl->pending_active);
> +     }
> +
> +     weston_logind_destroy_vt(wl);
> +     weston_logind_release_control(wl);
> +     weston_logind_destroy_dbus(wl);
> +     weston_dbus_close(wl->dbus, wl->dbus_ctx);
> +     free(wl->sid);
> +     free(wl->seat);
> +     free(wl);
> +}
> diff --git a/src/logind-util.h b/src/logind-util.h
> new file mode 100644
> index 0000000..3fc7fe4
> --- /dev/null
> +++ b/src/logind-util.h
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright © 2013 David Herrmann
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include "config.h"
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "compositor.h"
> +
> +struct weston_logind;
> +
> +#if defined(HAVE_SYSTEMD_LOGIN_207) && defined(HAVE_DBUS)
> +
> +int
> +weston_logind_open(struct weston_logind *wl, const char *path,
> +                int flags);
> +
> +void
> +weston_logind_close(struct weston_logind *wl, int fd);
> +
> +void
> +weston_logind_restore(struct weston_logind *wl);
> +
> +int
> +weston_logind_activate_vt(struct weston_logind *wl, int vt);
> +
> +int
> +weston_logind_connect(struct weston_logind **out,
> +                   struct weston_compositor *compositor,
> +                   const char *seat_id, int tty);
> +
> +void
> +weston_logind_destroy(struct weston_logind *wl);
> +
> +#else /* defined(HAVE_SYSTEMD_LOGIN_207) && defined(HAVE_DBUS) */
> +
> +static inline int
> +weston_logind_open(struct weston_logind *wl, const char *path,
> +                int flags)
> +{
> +     return -ENOSYS;
> +}
> +
> +static inline void
> +weston_logind_close(struct weston_logind *wl, int fd)
> +{
> +}
> +
> +static inline void
> +weston_logind_restore(struct weston_logind *wl)
> +{
> +}
> +
> +static inline int
> +weston_logind_activate_vt(struct weston_logind *wl, int vt)
> +{
> +     return -ENOSYS;
> +}
> +
> +static inline int
> +weston_logind_connect(struct weston_logind **out,
> +                   struct weston_compositor *compositor,
> +                   const char *seat_id, int tty)
> +{
> +     return -ENOSYS;
> +}
> +
> +static inline void
> +weston_logind_destroy(struct weston_logind *wl)
> +{
> +}
> +
> +#endif /* defined(HAVE_SYSTEMD_LOGIN_207) && defined(HAVE_DBUS) */
> -- 
> 1.8.4
> 
_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to