[systemd-devel] [PATCH 00/10] Device Management for systemd-logind

David Herrmann dh.herrmann at gmail.com
Sun Aug 25 05:46:05 PDT 2013


Hi

This series implements device management for logind. A session can now request
device access directly via logind dbus APIs. It extends the
org.freedesktop.login1.Session interface. The already existing interface is
described at:
        http://www.freedesktop.org/wiki/Software/systemd/logind/

The reason for this series and the basic idea is discussed on:
        http://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/

If someone is not familiar with session-management and, more importantly,
session-switching, I summarized it at:
        http://dvdhrm.wordpress.com/2013/08/24/session-management-on-linux/
        http://dvdhrm.wordpress.com/2013/08/24/how-vt-switching-works/

Ok, feel free to dismiss the rest of this mail and look directly at the patches.
The commit-messages explain everything in detail. For all who are not familiar
with the systemd code-base, a summary can be found below.

Feedback welcome! I am open for any suggestions.

Tests, examples and more will be available at https://github.com/dvdhrm/libnovt
once the API stabilized.

Regards
David

CC: wayland-devel at fdo for weston-launch development.



The following calls are introduced by this series. They are added to the logind
dbus API for sessions. Hence, each call implicitly operates on a given session
and thus does not have to be passed as argument.

These methods are added:

RequestDevice(const char *node, int *fd_out, bool *paused_out):
        logind tries to open a device node in /dev/ (@node) for the caller. It
        checks that it is assigned to the seat of the caller, has the uaccess
        flags set and then opens the fd and passes it back via @fd_out. The
        @paused_out field will notify the caller whether the device is currently
        paused or active.
        Remarks:
          - you cannot open a node twice in parallel
          - you must use the canonical device-node (the one from devtmpfs) and
            returned by udev_device_get_devnode(). No other nodes can be
            supported; clients could trigger OOM otherwise
          - logind keeps a copy of @fd internally to revoke access once the
            session becomes inactive

ReleaseDevice(const char *node):
        logind closes the device that was previously requested via
        RequestDevice(). It revokes access from the fd and closes it internally.
        The caller still has their own fd, but it will be useless. But they
        obviously need to close() it theirself.
        You may call RequestDevice() on the same node again, once you released
        it.

As long as a process owns a device, it is notified via dbus signals about state
changes:

PauseDevice(const char *node, const char *type):
        logind sends this event whenever the device is paused or released. @node
        contains the device-node passed to RequestDevice() and is unique. @type
        is "gone" if the device was closed or removed from the seat. A
        compositor normally gets a udev "remove" event at the same time. They
        should treat it similarly.
        @type is "force" if the device was forcibly paused by logind. A
        compositor normally gets EACCES or EPERM simultaneously from any
        syscalls it tries on the fd. Hence, it is adviced to handle EACCES/EPERM
        the same as a PauseDevice("force") signal from systemd.
        Last but not least, there is "pause" as @type. This is a kind request by
        logind to the compositor to pause the device. A compositor gets a short
        timeout to react to this event, cleanup everything and acknowledge the
        signal via a call to PauseDeviceComplete(). If it doesn't react in a
        timely manner, a PauseDevice("force") event will be sent.

ResumeDevice(const char *node, int *fd_out):
        For every device requested via RequestDevice(), logind sends this event
        whenever the device is resumed. It also puts a new file-descriptor into
        @fd_out. A compositor is advised to close its old fd and use the new
        one. For some device-types (namely evdev) it *must* use the new fd, as
        the old one is revoked. For other device-types (namely DRM) both will
        actually be the same as access can be restored.
        Compositors are allowed to rely on this behavior for DRM. That is, if
        it's a DRM device, they can close the new fd and keep the old one
        (they're actually just dup()'ed). This allows them to retain their DRM
        state.

Methods to acknowledge some signals are:

PauseDeviceComplete(const char *node):
        As mentioned above in PauseDevice, this is a method that can be called
        by compositors to react to a PauseDevice("pause") request. After it is
        called, the given device will be paused.

Note that device-management is available on all sessions regardless their type
and state. Moreover, device-state follows session-state but might also be paused
for other reasons that are currently not defined. This means, whenever a session
is inactive, all devices on this session are inactive, too. However, when a
session is active, a device might stay inactive (for instance if reactivation
failed). But logind guarantees that a device can never be used by anyone else
than the foreground session. Compositors can rely on that for security reasons.

logind itselfs takes care of revoking device access for inactive sessions
(synchronized with session-switches!). It also tries to resume every device
when a session is activated. But session-devices must not be used to watch
session state! A compositor has to use the PropertiesChanged() signal plus the
"Active" property of sessions for that! Session-devices do not replace this! On
sessions with VTs, this is obviously replaced by the VT_SETMODE interface as
usual.

Now additionally to the interface mentioned above, this series introduces
session-controllers. These try to prevent multiple compositors from running in
parallel. That is, when a compositor starts up, it calls RequestControl() on the
session in question. If there is already another compositor running, this will
fail.
The new device-management functions are limited to the active controller. No
other functions make use of controllers.

Note that the RequestControl() call might get a "scope" argument. So you can
have a controller with scope "graphics" and one for scope "sound", for example.
On each scope only a single controller is allowed, but the scopes don't
interfere. So logind makes sure that RequestDevice() on a graphics or input
device requires the "graphics" scope.

But now the API:

RequestControl(bool force):
        For now this misses a "scope" argument, so it currently implies
        "graphics" scope. This function will make the caller the new controller
        of the given session. logind watches the system bus and automatically
        drops the controller once it disconnects.
        If there is already a controller for the given scope, this returns
        EBUSY. If @force is true, the active controller will be dropped and the
        caller will get the new controller.
        This function is restricted to callers with the same UID as the "User"
        of the given session. If @force is true, the caller must be root.
        So this call in combination with RequestDevice() allows us to run a
        compositor in a session as normal user. Yay!

DropControl():
        Drop control again. If the caller is not the current controller, this
        does nothing. Note that this call is optional. logind watches the bus
        for disconnect events and invokes this implicitly if a controller exits.

David Herrmann (10):
  logind: listen actively for session devices
  logind: add infrastructure to watch busnames
  logind: add session controllers
  logind: make Session.Activate() lazy
  logind: introduce session-devices
  logind: rename vtconsole to seat0
  logind: fix seat_can_tty() to check for VTs
  logind: fix session_activate(vtnr = 0)
  logind: extract has_vts() from can_multi_session()
  logind: implement generic multi-session

 Makefile.am                       |   2 +
 src/login/logind-dbus.c           |  35 ++-
 src/login/logind-device.c         |  39 ++-
 src/login/logind-device.h         |   5 +-
 src/login/logind-seat.c           |  73 ++++--
 src/login/logind-seat.h           |   6 +-
 src/login/logind-session-dbus.c   | 156 ++++++++++++
 src/login/logind-session-device.c | 517 ++++++++++++++++++++++++++++++++++++++
 src/login/logind-session-device.h |  58 +++++
 src/login/logind-session.c        | 112 ++++++++-
 src/login/logind-session.h        |   8 +
 src/login/logind.c                | 151 +++++++++--
 src/login/logind.h                |  12 +-
 13 files changed, 1109 insertions(+), 65 deletions(-)
 create mode 100644 src/login/logind-session-device.c
 create mode 100644 src/login/logind-session-device.h

-- 
1.8.3.4



More information about the systemd-devel mailing list