]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-terminal/idev-evdev.c
terminal: add evdev elements to idev
[thirdparty/systemd.git] / src / libsystemd-terminal / idev-evdev.c
CommitLineData
c93e5a62
DH
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <fcntl.h>
23#include <inttypes.h>
24#include <libevdev/libevdev.h>
25#include <libudev.h>
26#include <stdbool.h>
27#include <stdlib.h>
28#include <systemd/sd-bus.h>
29#include <systemd/sd-event.h>
30#include <unistd.h>
31#include "bus-util.h"
32#include "hashmap.h"
33#include "idev.h"
34#include "idev-internal.h"
35#include "macro.h"
36#include "udev-util.h"
37#include "util.h"
38
39typedef struct idev_evdev idev_evdev;
40typedef struct unmanaged_evdev unmanaged_evdev;
41typedef struct managed_evdev managed_evdev;
42
43struct idev_evdev {
44 struct idev_element element;
45 struct libevdev *evdev;
46 int fd;
47 sd_event_source *fd_src;
48 sd_event_source *idle_src;
49
50 bool unsync : 1; /* not in-sync with kernel */
51 bool resync : 1; /* re-syncing with kernel */
52};
53
54struct unmanaged_evdev {
55 struct idev_evdev evdev;
56 char *devnode;
57};
58
59struct managed_evdev {
60 struct idev_evdev evdev;
61 dev_t devnum;
62
63 sd_bus_slot *slot_pause_device;
64 sd_bus_slot *slot_resume_device;
65 sd_bus_slot *slot_take_device;
66
67 bool requested : 1; /* TakeDevice() was sent */
68 bool acquired : 1; /* TakeDevice() was successful */
69};
70
71#define idev_evdev_from_element(_e) container_of((_e), idev_evdev, element)
72#define unmanaged_evdev_from_element(_e) \
73 container_of(idev_evdev_from_element(_e), unmanaged_evdev, evdev)
74#define managed_evdev_from_element(_e) \
75 container_of(idev_evdev_from_element(_e), managed_evdev, evdev)
76
77#define IDEV_EVDEV_INIT(_vtable, _session) ((idev_evdev){ \
78 .element = IDEV_ELEMENT_INIT((_vtable), (_session)), \
79 .fd = -1, \
80 })
81
82#define IDEV_EVDEV_NAME_MAX (8 + DECIMAL_STR_MAX(unsigned) * 2)
83
84static const idev_element_vtable unmanaged_evdev_vtable;
85static const idev_element_vtable managed_evdev_vtable;
86
87static int idev_evdev_resume(idev_evdev *evdev, int dev_fd);
88static void idev_evdev_pause(idev_evdev *evdev, bool release);
89
90/*
91 * Virtual Evdev Element
92 * The virtual evdev element is the base class of all other evdev elements. It
93 * uses libevdev to access the kernel evdev API. It supports asynchronous
94 * access revocation, re-syncing if events got dropped and more.
95 * This element cannot be used by itself. There must be a wrapper around it
96 * which opens a file-descriptor and passes it to the virtual evdev element.
97 */
98
99static void idev_evdev_name(char *out, dev_t devnum) {
100 /* @out must be at least of size IDEV_EVDEV_NAME_MAX */
101 sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum));
102}
103
104static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) {
105 idev_data data = {
106 .type = IDEV_DATA_EVDEV,
107 .resync = evdev->resync,
108 .evdev = {
109 .event = *event,
110 },
111 };
112
113 return idev_element_feed(&evdev->element, &data);
114}
115
116static void idev_evdev_hup(idev_evdev *evdev) {
117 /*
118 * On HUP, we close the current fd via idev_evdev_pause(). This drops
119 * the event-sources from the main-loop and effectively puts the
120 * element asleep. If the HUP is part of a hotplug-event, a following
121 * udev-notification will destroy the element. Otherwise, the HUP is
122 * either result of access-revokation or a serious error.
123 * For unmanaged devices, we should never receive HUP (except for
124 * unplug-events). But if we do, something went seriously wrong and we
125 * shouldn't try to be clever.
126 * Instead, we simply stay asleep and wait for the device to be
127 * disabled and then re-enabled (or closed and re-opened). This will
128 * re-open the device node and restart the device.
129 * For managed devices, a HUP usually means our device-access was
130 * revoked. In that case, we simply put the device asleep and wait for
131 * logind to notify us once the device is alive again. logind also
132 * passes us a new fd. Hence, we don't have to re-enable the device.
133 *
134 * Long story short: The only thing we have to do here, is close() the
135 * file-descriptor and remove it from the main-loop. Everything else is
136 * handled via additional events we receive.
137 */
138
139 idev_evdev_pause(evdev, true);
140}
141
142static int idev_evdev_io(idev_evdev *evdev) {
143 idev_element *e = &evdev->element;
144 struct input_event ev;
145 unsigned int flags;
146 int r, error = 0;
147
148 /*
149 * Read input-events via libevdev until the input-queue is drained. In
150 * case we're disabled, don't do anything. The input-queue might
151 * overflow, but we don't care as we have to resync after wake-up,
152 * anyway.
153 * TODO: libevdev should give us a hint how many events to read. We
154 * really want to avoid starvation, so we shouldn't read forever in
155 * case we cannot keep up with the kernel.
156 * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless
157 * whether any event was synced afterwards.
158 * TODO: Forward SYN_DROPPED to attached devices.
159 */
160
161 flags = LIBEVDEV_READ_FLAG_NORMAL;
162 while (e->enabled) {
163 if (evdev->unsync) {
164 /* immediately resync, even if in sync right now */
165 evdev->unsync = false;
166 evdev->resync = false;
167 flags = LIBEVDEV_READ_FLAG_NORMAL;
168 r = libevdev_next_event(evdev->evdev, flags | LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
169 if (r < 0 && r != -EAGAIN) {
170 r = 0;
171 goto error;
172 } else if (r != LIBEVDEV_READ_STATUS_SYNC) {
173 log_debug("idev-evdev: %s/%s: cannot force resync: %d",
174 e->session->name, e->name, r);
175 }
176 } else {
177 r = libevdev_next_event(evdev->evdev, flags, &ev);
178 }
179
180 if (evdev->resync && r == -EAGAIN) {
181 /* end of re-sync */
182 evdev->resync = false;
183 flags = LIBEVDEV_READ_FLAG_NORMAL;
184 } else if (r == -EAGAIN) {
185 /* no data available */
186 break;
187 } else if (r < 0) {
188 /* read error */
189 goto error;
190 } else if (r == LIBEVDEV_READ_STATUS_SYNC) {
191 if (evdev->resync) {
192 /* sync-event */
193 r = idev_evdev_raise(evdev, &ev);
194 if (r != 0) {
195 error = r;
196 break;
197 }
198 } else {
199 /* start of sync */
200 evdev->resync = true;
201 flags = LIBEVDEV_READ_FLAG_SYNC;
202 }
203 } else {
204 /* normal event */
205 r = idev_evdev_raise(evdev, &ev);
206 if (r != 0) {
207 error = r;
208 break;
209 }
210 }
211 }
212
213 if (error < 0)
214 log_debug("idev-evdev: %s/%s: error on data event: %s",
215 e->session->name, e->name, strerror(-error));
216 return error;
217
218error:
219 idev_evdev_hup(evdev);
220 return r;
221}
222
223static int idev_evdev_event_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
224 idev_evdev *evdev = userdata;
225
226 /* fetch data as long as EPOLLIN is signalled */
227 if (revents & EPOLLIN)
228 return idev_evdev_io(evdev);
229
230 if (revents & (EPOLLHUP | EPOLLERR))
231 idev_evdev_hup(evdev);
232
233 return 0;
234}
235
236static int idev_evdev_idle_fn(sd_event_source *s, void *userdata) {
237 idev_evdev *evdev = userdata;
238
239 /*
240 * The idle-event is raised whenever we have to re-sync the libevdev
241 * state from the kernel. We simply call into idev_evdev_io() which
242 * flushes the state and re-syncs it if @unsync is set.
243 * State has to be synced whenever our view of the kernel device is
244 * out of date. This is the case when we open the device, if the
245 * kernel's receive buffer overflows, or on other exceptional
246 * situations. Events during re-syncs must be forwarded to the upper
247 * layers so they can update their view of the device. However, such
248 * events must only be handled passively, as they might be out-of-order
249 * and/or re-ordered. Therefore, we mark them as 'sync' events.
250 */
251
252 if (!evdev->unsync)
253 return 0;
254
255 return idev_evdev_io(evdev);
256}
257
258static void idev_evdev_destroy(idev_evdev *evdev) {
259 assert(evdev);
260 assert(evdev->fd < 0);
261
262 libevdev_free(evdev->evdev);
263 evdev->evdev = NULL;
264}
265
266static void idev_evdev_enable(idev_evdev *evdev) {
267 assert(evdev);
268 assert(evdev->fd_src);
269 assert(evdev->idle_src);
270
271 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON);
272 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT);
273}
274
275static void idev_evdev_disable(idev_evdev *evdev) {
276 assert(evdev);
277 assert(evdev->fd_src);
278 assert(evdev->idle_src);
279
280 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
281 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
282}
283
284static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
285 idev_element *e = &evdev->element;
286 _cleanup_close_ int fd = dev_fd;
287 int r, flags;
288
289 if (fd < 0 || evdev->fd == fd) {
290 fd = -1;
291 if (evdev->fd >= 0 && e->n_open > 0 && e->enabled)
292 idev_evdev_enable(evdev);
293
294 return 0;
295 }
296
297 idev_evdev_pause(evdev, true);
298 log_debug("idev-evdev: %s/%s: resume", e->session->name, e->name);
299
300 r = fd_nonblock(fd, true);
301 if (r < 0)
302 return r;
303
304 r = fd_cloexec(fd, true);
305 if (r < 0)
306 return r;
307
308 flags = fcntl(fd, F_GETFL, 0);
309 if (flags < 0)
310 return r;
311
312 flags &= O_ACCMODE;
313 if (flags == O_WRONLY)
314 return -EACCES;
315
316 evdev->element.readable = true;
317 evdev->element.writable = true;
318 if (flags == O_RDONLY)
319 evdev->element.writable = false;
320 else if (flags == O_WRONLY)
321 evdev->element.readable = false;
322
323 /*
324 * TODO: We *MUST* re-sync the device so we get a delta of the changed
325 * state while we didn't read events from the device. This works just
326 * fine with libevdev_change_fd(), however, libevdev_new_from_fd() (or
327 * libevdev_set_fd()) don't pass us events for the initial device
328 * state. So even if we force a re-sync, we will not get the delta for
329 * the initial device state.
330 * We really need to fix libevdev to support that!
331 */
332 if (evdev->evdev)
333 r = libevdev_change_fd(evdev->evdev, fd);
334 else
335 r = libevdev_new_from_fd(fd, &evdev->evdev);
336
337 if (r < 0)
338 return r;
339
340 r = sd_event_add_io(e->session->context->event,
341 &evdev->fd_src,
342 fd,
343 EPOLLHUP | EPOLLERR | EPOLLIN,
344 idev_evdev_event_fn,
345 evdev);
346 if (r < 0)
347 return r;
348
349 r = sd_event_add_defer(e->session->context->event,
350 &evdev->idle_src,
351 idev_evdev_idle_fn,
352 evdev);
353 if (r < 0) {
354 evdev->fd_src = sd_event_source_unref(evdev->fd_src);
355 return r;
356 }
357
358 if (e->n_open < 1 || !e->enabled) {
359 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
360 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
361 }
362
363 evdev->unsync = true;
364 evdev->fd = fd;
365
366 fd = -1;
367 return 0;
368}
369
370static void idev_evdev_pause(idev_evdev *evdev, bool release) {
371 idev_element *e = &evdev->element;
372
373 if (evdev->fd < 0)
374 return;
375
376 log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name);
377
378 if (release) {
379 evdev->idle_src = sd_event_source_unref(evdev->idle_src);
380 evdev->fd_src = sd_event_source_unref(evdev->fd_src);
381 evdev->fd = safe_close(evdev->fd);
382 } else {
383 idev_evdev_disable(evdev);
384 }
385}
386
387/*
388 * Unmanaged Evdev Element
389 * The unmanaged evdev element opens the evdev node for a given input device
390 * directly (/dev/input/eventX) and thus needs sufficient privileges. It opens
391 * the device only if we really require it and releases it as soon as we're
392 * disabled or closed.
393 * The unmanaged element can be used in all situations where you have direct
394 * access to input device nodes. Unlike managed evdev elements, it can be used
395 * outside of user sessions and in emergency situations where logind is not
396 * available.
397 */
398
399static void unmanaged_evdev_resume(idev_element *e) {
400 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
401 int r, fd;
402
403 /*
404 * Unmanaged devices can be acquired on-demand. Therefore, don't
405 * acquire it unless someone opened the device *and* we're enabled.
406 */
407 if (e->n_open < 1 || !e->enabled)
408 return;
409
410 fd = eu->evdev.fd;
411 if (fd < 0) {
412 fd = open(eu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
413 if (fd < 0) {
414 if (errno != EACCES && errno != EPERM) {
415 log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
416 e->session->name, e->name, eu->devnode);
417 return;
418 }
419
420 fd = open(eu->devnode, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
421 if (fd < 0) {
422 log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
423 e->session->name, e->name, eu->devnode);
424 return;
425 }
426
427 e->readable = true;
428 e->writable = false;
429 } else {
430 e->readable = true;
431 e->writable = true;
432 }
433 }
434
435 r = idev_evdev_resume(&eu->evdev, fd);
436 if (r < 0)
437 log_debug("idev-evdev: %s/%s: cannot resume: %s",
438 e->session->name, e->name, strerror(-r));
439}
440
441static void unmanaged_evdev_pause(idev_element *e) {
442 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
443
444 /*
445 * Release the device if the device is disabled or there is no-one who
446 * opened it. This guarantees we stay only available if we're opened
447 * *and* enabled.
448 */
449
450 idev_evdev_pause(&eu->evdev, true);
451}
452
453static int unmanaged_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
454 _cleanup_(idev_element_freep) idev_element *e = NULL;
455 char name[IDEV_EVDEV_NAME_MAX];
456 unmanaged_evdev *eu;
457 const char *devnode;
458 dev_t devnum;
459 int r;
460
461 assert_return(s, -EINVAL);
462 assert_return(ud, -EINVAL);
463
464 devnode = udev_device_get_devnode(ud);
465 devnum = udev_device_get_devnum(ud);
466 if (!devnode || devnum == 0)
467 return -ENODEV;
468
469 idev_evdev_name(name, devnum);
470
471 eu = new0(unmanaged_evdev, 1);
472 if (!eu)
473 return -ENOMEM;
474
475 e = &eu->evdev.element;
476 eu->evdev = IDEV_EVDEV_INIT(&unmanaged_evdev_vtable, s);
477
478 eu->devnode = strdup(devnode);
479 if (!eu->devnode)
480 return -ENOMEM;
481
482 r = idev_element_add(e, name);
483 if (r < 0)
484 return r;
485
486 if (out)
487 *out = e;
488 e = NULL;
489 return 0;
490}
491
492static void unmanaged_evdev_free(idev_element *e) {
493 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
494
495 idev_evdev_destroy(&eu->evdev);
496 free(eu->devnode);
497 free(eu);
498}
499
500static const idev_element_vtable unmanaged_evdev_vtable = {
501 .free = unmanaged_evdev_free,
502 .enable = unmanaged_evdev_resume,
503 .disable = unmanaged_evdev_pause,
504 .open = unmanaged_evdev_resume,
505 .close = unmanaged_evdev_pause,
506};
507
508/*
509 * Managed Evdev Element
510 * The managed evdev element uses systemd-logind to acquire evdev devices. This
511 * means, we do not open the device node /dev/input/eventX directly. Instead,
512 * logind passes us a file-descriptor whenever our session is activated. Thus,
513 * we don't need access to the device node directly.
514 * Furthermore, whenever the session is put asleep, logind revokes the
515 * file-descriptor so we loose access to the device.
516 * Managed evdev elements should be preferred over unmanaged elements whenever
517 * you run inside a user session with exclusive device access.
518 */
519
520static int managed_evdev_take_device_fn(sd_bus *bus,
521 sd_bus_message *reply,
522 void *userdata,
523 sd_bus_error *ret_error) {
524 managed_evdev *em = userdata;
525 idev_element *e = &em->evdev.element;
526 idev_session *s = e->session;
527 int r, paused, fd;
528
529 em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
530
531 if (sd_bus_message_is_method_error(reply, NULL)) {
532 const sd_bus_error *error = sd_bus_message_get_error(reply);
533
534 log_debug("idev-evdev: %s/%s: TakeDevice failed: %s: %s",
535 s->name, e->name, error->name, error->message);
536 return 0;
537 }
538
539 em->acquired = true;
540
541 r = sd_bus_message_read(reply, "hb", &fd, &paused);
542 if (r < 0) {
543 log_debug("idev-evdev: %s/%s: erroneous TakeDevice reply", s->name, e->name);
544 return 0;
545 }
546
547 /* If the device is paused, ignore it; we will get the next fd via
548 * ResumeDevice signals. */
549 if (paused)
550 return 0;
551
552 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
553 if (fd < 0) {
554 log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name);
555 return 0;
556 }
557
558 r = idev_evdev_resume(&em->evdev, fd);
559 if (r < 0)
560 log_debug("idev-evdev: %s/%s: cannot resume: %s",
561 s->name, e->name, strerror(-r));
562
563 return 0;
564}
565
566static void managed_evdev_resume(idev_element *e) {
567 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
568 managed_evdev *em = managed_evdev_from_element(e);
569 idev_session *s = e->session;
570 idev_context *c = s->context;
571 int r;
572
573 /*
574 * Acquiring managed devices is heavy, so do it only once we're
575 * enabled *and* opened by someone.
576 */
577 if (e->n_open < 1 || !e->enabled)
578 return;
579
580 /* bail out if already pending */
581 if (em->requested)
582 return;
583
584 r = sd_bus_message_new_method_call(c->sysbus,
585 &m,
586 "org.freedesktop.login1",
587 s->path,
588 "org.freedesktop.login1.Session",
589 "TakeDevice");
590 if (r < 0)
591 goto error;
592
593 r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
594 if (r < 0)
595 goto error;
596
597 r = sd_bus_call_async(c->sysbus,
598 &em->slot_take_device,
599 m,
600 managed_evdev_take_device_fn,
601 em,
602 0);
603 if (r < 0)
604 goto error;
605
606 em->requested = true;
607 return;
608
609error:
610 log_debug("idev-evdev: %s/%s: cannot send TakeDevice request: %s",
611 s->name, e->name, strerror(-r));
612}
613
614static void managed_evdev_pause(idev_element *e) {
615 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
616 managed_evdev *em = managed_evdev_from_element(e);
617 idev_session *s = e->session;
618 idev_context *c = s->context;
619 int r;
620
621 /*
622 * Releasing managed devices is heavy. Once acquired, we get
623 * notifications for sleep/wake-up events, so there's no reason to
624 * release it if disabled but opened. However, if a device is closed,
625 * we release it immediately as we don't care for sleep/wake-up events
626 * then (even if we're actually enabled).
627 */
628
629 idev_evdev_pause(&em->evdev, false);
630
631 if (e->n_open > 0 || !em->requested)
632 return;
633
634 /*
635 * If TakeDevice() is pending or was successful, make sure to
636 * release the device again. We don't care for return-values,
637 * so send it without waiting or callbacks.
638 * If a failed TakeDevice() is pending, but someone else took
639 * the device on the same bus-connection, we might incorrectly
640 * release their device. This is an unlikely race, though.
641 * Furthermore, you really shouldn't have two users of the
642 * controller-API on the same session, on the same devices, *AND* on
643 * the same bus-connection. So we don't care for that race..
644 */
645
646 idev_evdev_pause(&em->evdev, true);
647 em->requested = false;
648
649 if (!em->acquired && !em->slot_take_device)
650 return;
651
652 em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
653 em->acquired = false;
654
655 r = sd_bus_message_new_method_call(c->sysbus,
656 &m,
657 "org.freedesktop.login1",
658 s->path,
659 "org.freedesktop.login1.Session",
660 "ReleaseDevice");
661 if (r >= 0) {
662 r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
663 if (r >= 0)
664 r = sd_bus_send(c->sysbus, m, NULL);
665 }
666
667 if (r < 0 && r != -ENOTCONN)
668 log_debug("idev-evdev: %s/%s: cannot send ReleaseDevice: %s",
669 s->name, e->name, strerror(-r));
670}
671
672static int managed_evdev_pause_device_fn(sd_bus *bus,
673 sd_bus_message *signal,
674 void *userdata,
675 sd_bus_error *ret_error) {
676 managed_evdev *em = userdata;
677 idev_element *e = &em->evdev.element;
678 idev_session *s = e->session;
679 idev_context *c = s->context;
680 uint32_t major, minor;
681 const char *mode;
682 int r;
683
684 /*
685 * We get PauseDevice() signals from logind whenever a device we
686 * requested was, or is about to be, paused. Arguments are major/minor
687 * number of the device and the mode of the operation.
688 * In case the event is not about our device, we ignore it. Otherwise,
689 * we treat it as asynchronous access-revocation (as if we got HUP on
690 * the device fd). Note that we might have already treated the HUP
691 * event via EPOLLHUP, whichever comes first.
692 *
693 * @mode can be one of the following:
694 * "pause": The device is about to be paused. We must react
695 * immediately and respond with PauseDeviceComplete(). Once
696 * we replied, logind will pause the device. Note that
697 * logind might apply any kind of timeout and force pause
698 * the device if we don't respond in a timely manner. In
699 * this case, we will receive a second PauseDevice event
700 * with @mode set to "force" (or similar).
701 * "force": The device was disabled forecfully by logind. Access is
702 * already revoked. This is just an asynchronous
703 * notification so we can put the device asleep (in case
704 * we didn't already notice the access revocation).
705 * "gone": This is like "force" but is sent if the device was
706 * paused due to a device-removal event.
707 *
708 * We always handle PauseDevice signals as "force" as we properly
709 * support asynchronous access revocation, anyway. But in case logind
710 * sent mode "pause", we also call PauseDeviceComplete() to immediately
711 * acknowledge the request.
712 */
713
714 r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
715 if (r < 0) {
716 log_debug("idev-evdev: %s/%s: erroneous PauseDevice signal",
717 s->name, e->name);
718 return 0;
719 }
720
721 /* not our device? */
722 if (makedev(major, minor) != em->devnum)
723 return 0;
724
725 idev_evdev_pause(&em->evdev, true);
726
727 if (streq(mode, "pause")) {
728 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
729
730 /*
731 * Sending PauseDeviceComplete() is racy if logind triggers the
732 * timeout. That is, if we take too long and logind pauses the
733 * device by sending a forced PauseDevice, our
734 * PauseDeviceComplete call will be stray. That's fine, though.
735 * logind ignores such stray calls. Only if logind also sent a
736 * further PauseDevice() signal, it might match our call
737 * incorrectly to the newer PauseDevice(). That's fine, too, as
738 * we handle that event asynchronously, anyway. Therefore,
739 * whatever happens, we're fine. Yay!
740 */
741
742 r = sd_bus_message_new_method_call(c->sysbus,
743 &m,
744 "org.freedesktop.login1",
745 s->path,
746 "org.freedesktop.login1.Session",
747 "PauseDeviceComplete");
748 if (r >= 0) {
749 r = sd_bus_message_append(m, "uu", major, minor);
750 if (r >= 0)
751 r = sd_bus_send(c->sysbus, m, NULL);
752 }
753
754 if (r < 0)
755 log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s",
756 s->name, e->name, strerror(-r));
757 }
758
759 return 0;
760}
761
762static int managed_evdev_resume_device_fn(sd_bus *bus,
763 sd_bus_message *signal,
764 void *userdata,
765 sd_bus_error *ret_error) {
766 managed_evdev *em = userdata;
767 idev_element *e = &em->evdev.element;
768 idev_session *s = e->session;
769 uint32_t major, minor;
770 int r, fd;
771
772 /*
773 * We get ResumeDevice signals whenever logind resumed a previously
774 * paused device. The arguments contain the major/minor number of the
775 * related device and a new file-descriptor for the freshly opened
776 * device-node.
777 * If the signal is not about our device, we simply ignore it.
778 * Otherwise, we take the file-descriptor and immediately resume the
779 * device.
780 */
781
782 r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
783 if (r < 0) {
784 log_debug("idev-evdev: %s/%s: erroneous ResumeDevice signal",
785 s->name, e->name);
786 return 0;
787 }
788
789 /* not our device? */
790 if (makedev(major, minor) != em->devnum)
791 return 0;
792
793 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
794 if (fd < 0) {
795 log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
796 s->name, e->name);
797 return 0;
798 }
799
800 r = idev_evdev_resume(&em->evdev, fd);
801 if (r < 0)
802 log_debug("idev-evdev: %s/%s: cannot resume: %s",
803 s->name, e->name, strerror(-r));
804
805 return 0;
806}
807
808static int managed_evdev_setup_bus(managed_evdev *em) {
809 idev_element *e = &em->evdev.element;
810 idev_session *s = e->session;
811 idev_context *c = s->context;
812 _cleanup_free_ char *match = NULL;
813 int r;
814
815 match = strjoin("type='signal',"
816 "sender='org.freedesktop.login1',"
817 "interface='org.freedesktop.login1.Session',"
818 "member='PauseDevice',"
819 "path='", s->path, "'",
820 NULL);
821 if (!match)
822 return -ENOMEM;
823
824 r = sd_bus_add_match(c->sysbus,
825 &em->slot_pause_device,
826 match,
827 managed_evdev_pause_device_fn,
828 em);
829 if (r < 0)
830 return r;
831
832 free(match);
833 match = strjoin("type='signal',"
834 "sender='org.freedesktop.login1',"
835 "interface='org.freedesktop.login1.Session',"
836 "member='ResumeDevice',"
837 "path='", s->path, "'",
838 NULL);
839 if (!match)
840 return -ENOMEM;
841
842 r = sd_bus_add_match(c->sysbus,
843 &em->slot_resume_device,
844 match,
845 managed_evdev_resume_device_fn,
846 em);
847 if (r < 0)
848 return r;
849
850 return 0;
851}
852
853static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
854 _cleanup_(idev_element_freep) idev_element *e = NULL;
855 char name[IDEV_EVDEV_NAME_MAX];
856 managed_evdev *em;
857 dev_t devnum;
858 int r;
859
860 assert_return(s, -EINVAL);
861 assert_return(s->context->sysbus, -EINVAL);
862 assert_return(s->managed, -EINVAL);
863 assert_return(s->context->sysbus, -EINVAL);
864 assert_return(ud, -EINVAL);
865
866 devnum = udev_device_get_devnum(ud);
867 if (devnum == 0)
868 return -ENODEV;
869
870 idev_evdev_name(name, devnum);
871
872 em = new0(managed_evdev, 1);
873 if (!em)
874 return -ENOMEM;
875
876 e = &em->evdev.element;
877 em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s);
878 em->devnum = devnum;
879
880 r = managed_evdev_setup_bus(em);
881 if (r < 0)
882 return r;
883
884 r = idev_element_add(e, name);
885 if (r < 0)
886 return r;
887
888 if (out)
889 *out = e;
890 e = NULL;
891 return 0;
892}
893
894static void managed_evdev_free(idev_element *e) {
895 managed_evdev *em = managed_evdev_from_element(e);
896
897 em->slot_resume_device = sd_bus_slot_unref(em->slot_resume_device);
898 em->slot_pause_device = sd_bus_slot_unref(em->slot_pause_device);
899 idev_evdev_destroy(&em->evdev);
900 free(em);
901}
902
903static const idev_element_vtable managed_evdev_vtable = {
904 .free = managed_evdev_free,
905 .enable = managed_evdev_resume,
906 .disable = managed_evdev_pause,
907 .open = managed_evdev_resume,
908 .close = managed_evdev_pause,
909};
910
911/*
912 * Generic Constructor
913 * Instead of relying on the caller to choose between managed and unmanaged
914 * evdev devices, the idev_evdev_new() constructor does that for you (by
915 * looking at s->managed).
916 */
917
918bool idev_is_evdev(idev_element *e) {
919 return e && (e->vtable == &unmanaged_evdev_vtable ||
920 e->vtable == &managed_evdev_vtable);
921}
922
923idev_element *idev_find_evdev(idev_session *s, dev_t devnum) {
924 char name[IDEV_EVDEV_NAME_MAX];
925
926 assert_return(s, NULL);
927 assert_return(devnum != 0, NULL);
928
929 idev_evdev_name(name, devnum);
930 return idev_find_element(s, name);
931}
932
933int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
934 assert_return(s, -EINVAL);
935 assert_return(ud, -EINVAL);
936
937 return s->managed ? managed_evdev_new(out, s, ud) : unmanaged_evdev_new(out, s, ud);
938}