2 This file is part of systemd.
4 Copyright 2013 David Herrmann
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/input.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
28 #include "alloc-util.h"
31 #include "logind-session-device.h"
33 #include "parse-util.h"
34 #include "sd-daemon.h"
37 enum SessionDeviceNotifications
{
38 SESSION_DEVICE_RESUME
,
39 SESSION_DEVICE_TRY_PAUSE
,
41 SESSION_DEVICE_RELEASE
,
44 static int session_device_notify(SessionDevice
*sd
, enum SessionDeviceNotifications type
) {
45 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
46 _cleanup_free_
char *path
= NULL
;
48 uint32_t major
, minor
;
53 major
= major(sd
->dev
);
54 minor
= minor(sd
->dev
);
56 if (!sd
->session
->controller
)
59 path
= session_bus_path(sd
->session
);
63 r
= sd_bus_message_new_signal(
64 sd
->session
->manager
->bus
,
66 "org.freedesktop.login1.Session",
67 (type
== SESSION_DEVICE_RESUME
) ? "ResumeDevice" : "PauseDevice");
71 r
= sd_bus_message_set_destination(m
, sd
->session
->controller
);
76 case SESSION_DEVICE_RESUME
:
77 r
= sd_bus_message_append(m
, "uuh", major
, minor
, sd
->fd
);
81 case SESSION_DEVICE_TRY_PAUSE
:
84 case SESSION_DEVICE_PAUSE
:
87 case SESSION_DEVICE_RELEASE
:
95 r
= sd_bus_message_append(m
, "uus", major
, minor
, t
);
100 return sd_bus_send(sd
->session
->manager
->bus
, m
, NULL
);
103 static int sd_eviocrevoke(int fd
) {
109 r
= ioctl(fd
, EVIOCREVOKE
, NULL
);
112 if (r
== -EINVAL
&& !warned
) {
114 log_warning("kernel does not support evdev-revocation");
121 static int sd_drmsetmaster(int fd
) {
126 r
= ioctl(fd
, DRM_IOCTL_SET_MASTER
, 0);
133 static int sd_drmdropmaster(int fd
) {
138 r
= ioctl(fd
, DRM_IOCTL_DROP_MASTER
, 0);
145 static int session_device_open(SessionDevice
*sd
, bool active
) {
148 assert(sd
->type
!= DEVICE_TYPE_UNKNOWN
);
150 /* open device and try to get an udev_device from it */
151 fd
= open(sd
->node
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
156 case DEVICE_TYPE_DRM
:
158 /* Weird legacy DRM semantics might return an error
159 * even though we're master. No way to detect that so
160 * fail at all times and let caller retry in inactive
162 r
= sd_drmsetmaster(fd
);
168 /* DRM-Master is granted to the first user who opens a
169 * device automatically (ughh, racy!). Hence, we just
170 * drop DRM-Master in case we were the first. */
171 sd_drmdropmaster(fd
);
174 case DEVICE_TYPE_EVDEV
:
178 case DEVICE_TYPE_UNKNOWN
:
180 /* fallback for devices wihout synchronizations */
187 static int session_device_start(SessionDevice
*sd
) {
191 assert(session_is_active(sd
->session
));
197 case DEVICE_TYPE_DRM
:
198 /* Device is kept open. Simply call drmSetMaster() and hope
199 * there is no-one else. In case it fails, we keep the device
200 * paused. Maybe at some point we have a drmStealMaster(). */
201 r
= sd_drmsetmaster(sd
->fd
);
205 case DEVICE_TYPE_EVDEV
:
206 /* Evdev devices are revoked while inactive. Reopen it and we
208 r
= session_device_open(sd
, true);
211 /* For evdev devices, the file descriptor might be left
212 * uninitialized. This might happen while resuming into a
213 * session and logind has been restarted right before. */
217 case DEVICE_TYPE_UNKNOWN
:
219 /* fallback for devices wihout synchronizations */
227 static void session_device_stop(SessionDevice
*sd
) {
234 case DEVICE_TYPE_DRM
:
235 /* On DRM devices we simply drop DRM-Master but keep it open.
236 * This allows the user to keep resources allocated. The
237 * CAP_SYS_ADMIN restriction to DRM-Master prevents users from
238 * circumventing this. */
239 sd_drmdropmaster(sd
->fd
);
241 case DEVICE_TYPE_EVDEV
:
242 /* Revoke access on evdev file-descriptors during deactivation.
243 * This will basically prevent any operations on the fd and
244 * cannot be undone. Good side is: it needs no CAP_SYS_ADMIN
245 * protection this way. */
246 sd_eviocrevoke(sd
->fd
);
248 case DEVICE_TYPE_UNKNOWN
:
250 /* fallback for devices without synchronization */
257 static DeviceType
detect_device_type(struct udev_device
*dev
) {
258 const char *sysname
, *subsystem
;
261 sysname
= udev_device_get_sysname(dev
);
262 subsystem
= udev_device_get_subsystem(dev
);
263 type
= DEVICE_TYPE_UNKNOWN
;
265 if (streq_ptr(subsystem
, "drm")) {
266 if (startswith(sysname
, "card"))
267 type
= DEVICE_TYPE_DRM
;
268 } else if (streq_ptr(subsystem
, "input")) {
269 if (startswith(sysname
, "event"))
270 type
= DEVICE_TYPE_EVDEV
;
276 static int session_device_verify(SessionDevice
*sd
) {
277 struct udev_device
*dev
, *p
= NULL
;
278 const char *sp
, *node
;
281 dev
= udev_device_new_from_devnum(sd
->session
->manager
->udev
, 'c', sd
->dev
);
285 sp
= udev_device_get_syspath(dev
);
286 node
= udev_device_get_devnode(dev
);
292 /* detect device type so we can find the correct sysfs parent */
293 sd
->type
= detect_device_type(dev
);
294 if (sd
->type
== DEVICE_TYPE_UNKNOWN
) {
297 } else if (sd
->type
== DEVICE_TYPE_EVDEV
) {
298 /* for evdev devices we need the parent node as device */
300 dev
= udev_device_get_parent_with_subsystem_devtype(p
, "input", NULL
);
305 sp
= udev_device_get_syspath(dev
);
306 } else if (sd
->type
!= DEVICE_TYPE_DRM
) {
307 /* Prevent opening unsupported devices. Especially devices of
308 * subsystem "input" must be opened via the evdev node as
309 * we require EVIOCREVOKE. */
314 /* search for an existing seat device and return it if available */
315 sd
->device
= hashmap_get(sd
->session
->manager
->devices
, sp
);
317 /* The caller might have gotten the udev event before we were
318 * able to process it. Hence, fake the "add" event and let the
319 * logind-manager handle the new device. */
320 r
= manager_process_seat_device(sd
->session
->manager
, dev
);
324 /* if it's still not available, then the device is invalid */
325 sd
->device
= hashmap_get(sd
->session
->manager
->devices
, sp
);
332 if (sd
->device
->seat
!= sd
->session
->seat
) {
337 sd
->node
= strdup(node
);
345 udev_device_unref(p
? : dev
);
349 int session_device_new(Session
*s
, dev_t dev
, bool open_device
, SessionDevice
**out
) {
359 sd
= new0(SessionDevice
, 1);
366 sd
->type
= DEVICE_TYPE_UNKNOWN
;
368 r
= session_device_verify(sd
);
372 r
= hashmap_put(s
->devices
, &sd
->dev
, sd
);
379 /* Open the device for the first time. We need a valid fd to pass back
380 * to the caller. If the session is not active, this _might_ immediately
381 * revoke access and thus invalidate the fd. But this is still needed
382 * to pass a valid fd back. */
383 sd
->active
= session_is_active(s
);
384 r
= session_device_open(sd
, sd
->active
);
386 /* EINVAL _may_ mean a master is active; retry inactive */
387 if (sd
->active
&& r
== -EINVAL
) {
389 r
= session_device_open(sd
, false);
397 LIST_PREPEND(sd_by_device
, sd
->device
->session_devices
, sd
);
403 hashmap_remove(s
->devices
, &sd
->dev
);
409 void session_device_free(SessionDevice
*sd
) {
412 session_device_stop(sd
);
413 session_device_notify(sd
, SESSION_DEVICE_RELEASE
);
414 close_nointr(sd
->fd
);
416 LIST_REMOVE(sd_by_device
, sd
->device
->session_devices
, sd
);
418 hashmap_remove(sd
->session
->devices
, &sd
->dev
);
424 void session_device_complete_pause(SessionDevice
*sd
) {
431 session_device_stop(sd
);
433 /* if not all devices are paused, wait for further completion events */
434 HASHMAP_FOREACH(iter
, sd
->session
->devices
, i
)
438 /* complete any pending session switch */
439 seat_complete_switch(sd
->session
->seat
);
442 void session_device_resume_all(Session
*s
) {
448 HASHMAP_FOREACH(sd
, s
->devices
, i
) {
450 if (session_device_start(sd
) < 0)
452 if (session_device_save(sd
) < 0)
454 session_device_notify(sd
, SESSION_DEVICE_RESUME
);
459 void session_device_pause_all(Session
*s
) {
465 HASHMAP_FOREACH(sd
, s
->devices
, i
) {
467 session_device_stop(sd
);
468 session_device_notify(sd
, SESSION_DEVICE_PAUSE
);
473 unsigned int session_device_try_pause_all(Session
*s
) {
476 unsigned int num_pending
= 0;
480 HASHMAP_FOREACH(sd
, s
->devices
, i
) {
482 session_device_notify(sd
, SESSION_DEVICE_TRY_PAUSE
);
490 int session_device_save(SessionDevice
*sd
) {
491 _cleanup_free_
char *state
= NULL
;
496 /* Store device fd in PID1. It will send it back to us on
497 * restart so revocation will continue to work. To make things
498 * simple, send fds for all type of devices even if they don't
499 * support the revocation mechanism so we don't have to handle
500 * them differently later.
502 * Note: for device supporting revocation, PID1 will drop a
503 * stored fd automatically if the corresponding device is
505 r
= asprintf(&state
, "FDSTORE=1\n"
506 "FDNAME=session-%s", sd
->session
->id
);
510 return sd_pid_notify_with_fds(0, false, state
, &sd
->fd
, 1);
513 void session_device_attach_fd(SessionDevice
*sd
, int fd
, bool active
) {