2 * uterm - Linux User-Space Terminal
4 * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * This uses systemd's login monitor to watch the system for new seats. When
29 * udev reports new devices, this automatically assigns the device to the right
30 * seat. Devices that are not associated to seats are ignored. If a device
31 * changes seats it is automatically removed and added again.
41 #include <sys/ioctl.h>
44 #include "shl_dlist.h"
45 #include "uterm_monitor.h"
46 #include "uterm_systemd_internal.h"
48 #define LOG_SUBSYSTEM "monitor"
50 struct uterm_monitor_dev {
51 struct shl_dlist list;
52 struct uterm_monitor_seat *seat;
59 struct uterm_monitor_seat {
60 struct shl_dlist list;
61 struct uterm_monitor *mon;
64 struct shl_dlist devices;
67 struct uterm_monitor {
69 struct ev_eloop *eloop;
74 struct ev_fd *sd_mon_fd;
77 struct udev_monitor *umon;
78 struct ev_fd *umon_fd;
80 struct shl_dlist seats;
83 static void monitor_new_seat(struct uterm_monitor *mon, const char *name);
84 static void monitor_free_seat(struct uterm_monitor_seat *seat);
86 static void monitor_refresh_seats(struct uterm_monitor *mon)
90 struct shl_dlist *iter, *tmp;
91 struct uterm_monitor_seat *seat;
93 /* Use only seat0 if multi-seat support is not available */
95 if (shl_dlist_empty(&mon->seats))
96 monitor_new_seat(mon, "seat0");
100 num = uterm_sd_get_seats(mon->sd, &seats);
102 log_warn("cannot read seat information from systemd: %d", num);
106 /* Remove all seats that are no longer present */
107 shl_dlist_for_each_safe(iter, tmp, &mon->seats) {
108 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
110 for (i = 0; i < num; ++i) {
111 if (!strcmp(seats[i], seat->name))
119 monitor_free_seat(seat);
123 /* Add all new seats */
124 for (i = 0; i < num; ++i) {
126 monitor_new_seat(mon, seats[i]);
134 static void monitor_sd_event(struct ev_fd *fd,
138 struct uterm_monitor *mon = data;
140 if (mask & (EV_HUP | EV_ERR)) {
141 log_warn("systemd login monitor closed unexpectedly");
146 uterm_sd_flush(mon->sd);
147 ev_eloop_flush_fd(mon->eloop, mon->sd_mon_fd);
149 monitor_refresh_seats(mon);
152 static void monitor_sd_poll(struct uterm_monitor *mon)
154 monitor_sd_event(mon->sd_mon_fd, EV_READABLE, mon);
157 static int monitor_sd_init(struct uterm_monitor *mon)
161 ret = uterm_sd_new(&mon->sd);
162 if (ret == -EOPNOTSUPP)
167 sfd = uterm_sd_get_fd(mon->sd);
169 log_err("cannot get systemd login monitor fd");
174 ret = ev_eloop_new_fd(mon->eloop, &mon->sd_mon_fd, sfd, EV_READABLE,
175 monitor_sd_event, mon);
182 uterm_sd_free(mon->sd);
186 static void monitor_sd_deinit(struct uterm_monitor *mon)
191 ev_eloop_rm_fd(mon->sd_mon_fd);
192 uterm_sd_free(mon->sd);
195 static void seat_new_dev(struct uterm_monitor_seat *seat,
200 struct uterm_monitor_dev *dev;
201 struct uterm_monitor_event ev;
203 dev = malloc(sizeof(*dev));
206 memset(dev, 0, sizeof(*dev));
211 dev->node = strdup(node);
215 shl_dlist_link(&seat->devices, &dev->list);
217 memset(&ev, 0, sizeof(ev));
218 ev.type = UTERM_MONITOR_NEW_DEV;
220 ev.seat_name = dev->seat->name;
221 ev.seat_data = dev->seat->data;
223 ev.dev_type = dev->type;
224 ev.dev_flags = dev->flags;
225 ev.dev_node = dev->node;
226 ev.dev_data = dev->data;
227 dev->seat->mon->cb(dev->seat->mon, &ev, dev->seat->mon->data);
229 log_debug("new device %s on %s", node, seat->name);
236 static void seat_free_dev(struct uterm_monitor_dev *dev)
238 struct uterm_monitor_event ev;
240 log_debug("free device %s on %s", dev->node, dev->seat->name);
242 shl_dlist_unlink(&dev->list);
244 memset(&ev, 0, sizeof(ev));
245 ev.type = UTERM_MONITOR_FREE_DEV;
247 ev.seat_name = dev->seat->name;
248 ev.seat_data = dev->seat->data;
250 ev.dev_type = dev->type;
251 ev.dev_flags = dev->flags;
252 ev.dev_node = dev->node;
253 ev.dev_data = dev->data;
254 dev->seat->mon->cb(dev->seat->mon, &ev, dev->seat->mon->data);
260 static struct uterm_monitor_dev *monitor_find_dev(struct uterm_monitor *mon,
261 struct udev_device *dev)
264 struct shl_dlist *iter, *iter2;
265 struct uterm_monitor_seat *seat;
266 struct uterm_monitor_dev *sdev;
268 node = udev_device_get_devnode(dev);
272 shl_dlist_for_each(iter, &mon->seats) {
273 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
275 shl_dlist_for_each(iter2, &seat->devices) {
276 sdev = shl_dlist_entry(iter2,
277 struct uterm_monitor_dev,
279 if (!strcmp(node, sdev->node))
287 static void monitor_new_seat(struct uterm_monitor *mon, const char *name)
289 struct uterm_monitor_seat *seat;
290 struct uterm_monitor_event ev;
292 seat = malloc(sizeof(*seat));
295 memset(seat, 0, sizeof(*seat));
297 shl_dlist_init(&seat->devices);
299 seat->name = strdup(name);
303 shl_dlist_link(&mon->seats, &seat->list);
305 memset(&ev, 0, sizeof(ev));
306 ev.type = UTERM_MONITOR_NEW_SEAT;
308 ev.seat_name = seat->name;
309 ev.seat_data = seat->data;
310 seat->mon->cb(seat->mon, &ev, seat->mon->data);
312 log_debug("new seat %s", name);
319 static void monitor_free_seat(struct uterm_monitor_seat *seat)
321 struct uterm_monitor_event ev;
322 struct uterm_monitor_dev *dev;
324 log_debug("free seat %s", seat->name);
326 while (seat->devices.next != &seat->devices) {
327 dev = shl_dlist_entry(seat->devices.next,
328 struct uterm_monitor_dev,
333 shl_dlist_unlink(&seat->list);
335 memset(&ev, 0, sizeof(ev));
336 ev.type = UTERM_MONITOR_FREE_SEAT;
338 ev.seat_name = seat->name;
339 ev.seat_data = seat->data;
340 seat->mon->cb(seat->mon, &ev, seat->mon->data);
346 static int get_card_id(struct udev_device *dev)
352 name = udev_device_get_sysname(dev);
355 if (strncmp(name, "card", 4) || !name[4])
358 devnum = strtol(&name[4], &end, 10);
359 if (devnum < 0 || *end)
365 static int get_fb_id(struct udev_device *dev)
371 name = udev_device_get_sysname(dev);
374 if (strncmp(name, "fb", 2) || !name[2])
377 devnum = strtol(&name[2], &end, 10);
378 if (devnum < 0 || *end)
385 * UTERM_MONITOR_DRM_BACKED:
386 * Nearly all DRM drivers do also create fbdev nodes which refer to the same
387 * hardware as the DRM devices. So we shouldn't advertise these fbdev nodes as
388 * real devices. Otherwise, the user might use these and the DRM devices
389 * simultaneously, thinking that they deal with two different hardware devices.
390 * We also report that it is a drm-device if we actually cannot verify that it
391 * is not some DRM device.
394 * Auxiliary devices are devices that are not the main GPU but rather some kind
395 * of hotpluggable helpers that provide additional display controllers. This is
396 * some kind of whitelist that tells the application that this GPU can safely be
397 * used as additional GPU together with but also independent of the primary GPU.
399 * UTERM_MONITOR_PRIMARY:
400 * A primary GPU is the main GPU in the system which is used to display boot
401 * graphics. Older systems used to have them hardwired, but especially embedded
402 * systems tend to no longer have primary GPUs so this flag cannot be guaranteed
403 * to be set for all systems.
404 * Hence, this flag shouldn't be used by default but rather as fallback if the
405 * user selects "primary GPU only" flag or similar.
408 static unsigned int get_fbdev_flags(struct uterm_monitor *mon, const char *node)
411 struct fb_fix_screeninfo finfo;
412 unsigned int flags = UTERM_MONITOR_DRM_BACKED;
414 fd = open(node, O_RDWR | O_CLOEXEC);
416 log_warning("cannot open fbdev node %s for drm-device verification (%d): %m",
421 ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
423 log_warning("cannot retrieve finfo from fbdev node %s for drm-device verification (%d): %m",
428 /* TODO: we really need some reliable flag here that tells us that we
429 * are dealing with a DRM device indirectly. Checking for "drmfb" suffix
430 * seems fine, but that may be just luck.
431 * If this turns out to not work reliably, we can also fall back to
432 * checking whether the parent udev device node does also provide a DRM
434 len = strlen(finfo.id);
435 if ((len < 5 || strcmp(&finfo.id[len - 5], "drmfb")) &&
436 strcmp(finfo.id, "nouveaufb") &&
437 strcmp(finfo.id, "psbfb"))
438 flags &= ~UTERM_MONITOR_DRM_BACKED;
440 if (!strcmp(finfo.id, "udlfb"))
441 flags |= UTERM_MONITOR_AUX;
442 else if (!strcmp(finfo.id, "VESA VGA"))
443 flags |= UTERM_MONITOR_PRIMARY;
450 static bool is_drm_primary(struct uterm_monitor *mon, struct udev_device *dev,
453 struct udev_device *pci;
456 pci = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
458 id = udev_device_get_sysattr_value(pci, "boot_vga");
459 if (id && !strcmp(id, "1")) {
460 log_debug("DRM device %s is primary PCI GPU", node);
469 * DRM doesn't provide public uapi headers but instead provides the ABI via
470 * libdrm... GREAT! That means we either need a build-time dependency to libdrm
471 * or we copy the parts we use in here. As we only need the VERSION ioctl, we
472 * simply copy it from drm.h.
475 struct uterm_drm_version {
476 int version_major; /**< Major version */
477 int version_minor; /**< Minor version */
478 int version_patchlevel; /**< Patch level */
479 size_t name_len; /**< Length of name buffer */
480 char *name; /**< Name of driver */
481 size_t date_len; /**< Length of date buffer */
482 char *date; /**< User-space buffer to hold date */
483 size_t desc_len; /**< Length of desc buffer */
484 char *desc; /**< User-space buffer to hold desc */
486 #define UTERM_DRM_IOCTL_VERSION _IOWR('d', 0x00, struct uterm_drm_version)
488 static inline char *get_drm_name(int fd)
490 struct uterm_drm_version v;
494 memset(&v, 0, sizeof(v));
495 ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
503 v.name = malloc(len + 1);
507 ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
517 static bool is_drm_usb(struct uterm_monitor *mon, const char *node, int fd)
522 name = get_drm_name(fd);
524 log_warning("cannot get driver name for DRM device %s (%d): %m",
529 if (!strcmp(name, "udl"))
534 log_debug("DRM device %s uses driver %s", node, name);
539 static unsigned int get_drm_flags(struct uterm_monitor *mon,
540 struct udev_device *dev, const char *node)
543 unsigned int flags = 0;
545 fd = open(node, O_RDWR | O_CLOEXEC);
547 log_warning("cannot open DRM device %s for primary-detection (%d): %m",
552 if (is_drm_primary(mon, dev, node))
553 flags |= UTERM_MONITOR_PRIMARY;
554 if (is_drm_usb(mon, node, fd))
555 flags |= UTERM_MONITOR_AUX;
561 static void monitor_udev_add(struct uterm_monitor *mon,
562 struct udev_device *dev)
564 const char *sname, *subs, *node, *name, *sysname;
565 struct shl_dlist *iter;
566 struct uterm_monitor_seat *seat;
567 unsigned int type, flags;
569 struct udev_device *p;
571 name = udev_device_get_syspath(dev);
573 log_debug("cannot get syspath of udev device");
577 if (monitor_find_dev(mon, dev)) {
578 log_debug("adding already available device %s", name);
582 node = udev_device_get_devnode(dev);
586 subs = udev_device_get_subsystem(dev);
588 log_debug("adding device with invalid subsystem %s", name);
592 if (!strcmp(subs, "drm")) {
593 if (mon->sd && udev_device_has_tag(dev, "seat") != 1) {
594 log_debug("adding non-seat'ed device %s", name);
597 id = get_card_id(dev);
599 log_debug("adding drm sub-device %s", name);
602 sname = udev_device_get_property_value(dev, "ID_SEAT");
603 type = UTERM_MONITOR_DRM;
604 flags = get_drm_flags(mon, dev, node);
605 } else if (!strcmp(subs, "graphics")) {
606 if (mon->sd && udev_device_has_tag(dev, "seat") != 1) {
607 log_debug("adding non-seat'ed device %s", name);
612 log_debug("adding fbdev sub-device %s", name);
615 sname = udev_device_get_property_value(dev, "ID_SEAT");
616 type = UTERM_MONITOR_FBDEV;
617 flags = get_fbdev_flags(mon, node);
618 } else if (!strcmp(subs, "input")) {
619 sysname = udev_device_get_sysname(dev);
620 if (!sysname || strncmp(sysname, "event", 5)) {
621 log_debug("adding unsupported input dev %s", name);
624 p = udev_device_get_parent_with_subsystem_devtype(dev,
627 log_debug("adding device without parent %s", name);
630 if (mon->sd && udev_device_has_tag(p, "seat") != 1) {
631 log_debug("adding non-seat'ed device %s", name);
634 sname = udev_device_get_property_value(p, "ID_SEAT");
635 type = UTERM_MONITOR_INPUT;
638 log_debug("adding device with unknown subsystem %s (%s)",
646 /* find correct seat */
647 shl_dlist_for_each(iter, &mon->seats) {
648 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
650 if (!strcmp(sname, seat->name))
654 if (iter == &mon->seats) {
655 log_debug("adding device for unknown seat %s (%s)",
660 seat_new_dev(seat, type, flags, node);
663 static void monitor_udev_remove(struct uterm_monitor *mon,
664 struct udev_device *dev)
666 struct uterm_monitor_dev *sdev;
668 sdev = monitor_find_dev(mon, dev);
670 log_debug("removing unknown device");
677 static void monitor_udev_change(struct uterm_monitor *mon,
678 struct udev_device *dev)
680 const char *sname, *val;
681 struct uterm_monitor_dev *sdev;
682 struct uterm_monitor_event ev;
684 sdev = monitor_find_dev(mon, dev);
686 sname = udev_device_get_property_value(dev, "ID_SEAT");
689 if (strcmp(sname, sdev->seat->name)) {
690 /* device switched seats; remove and add it again */
692 monitor_udev_add(mon, dev);
696 /* DRM devices send hotplug events; catch them here */
697 val = udev_device_get_property_value(dev, "HOTPLUG");
698 if (val && !strcmp(val, "1")) {
699 memset(&ev, 0, sizeof(ev));
700 ev.type = UTERM_MONITOR_HOTPLUG_DEV;
701 ev.seat = sdev->seat;
702 ev.seat_name = sdev->seat->name;
703 ev.seat_data = sdev->seat->data;
705 ev.dev_type = sdev->type;
706 ev.dev_node = sdev->node;
707 ev.dev_data = sdev->data;
708 sdev->seat->mon->cb(sdev->seat->mon, &ev,
709 sdev->seat->mon->data);
712 /* Unknown device; maybe it switched into a known seat? Try
713 * adding it as new device. If that fails, we ignore it */
714 monitor_udev_add(mon, dev);
718 static void monitor_udev_event(struct ev_fd *fd,
722 struct uterm_monitor *mon = data;
723 struct udev_device *dev;
726 if (mask & (EV_HUP | EV_ERR)) {
727 log_warn("udev monitor closed unexpectedly");
732 * If there is a pending sd_event in the current epoll-queue and our
733 * udev event is called first, we must make sure to first execute the
734 * sd_event. Otherwise, our udev event might introduce new seats that
735 * will be initialized later and we loose devices.
736 * monitor_sd_event() flushes the sd-fd so we will never refresh seat
737 * values twice in a single epoll-loop.
739 monitor_sd_poll(mon);
742 /* we use non-blocking udev monitor so ignore errors */
743 dev = udev_monitor_receive_device(mon->umon);
747 action = udev_device_get_action(dev);
749 if (!strcmp(action, "add"))
750 monitor_udev_add(mon, dev);
751 else if (!strcmp(action, "remove"))
752 monitor_udev_remove(mon, dev);
753 else if (!strcmp(action, "change"))
754 monitor_udev_change(mon, dev);
757 udev_device_unref(dev);
761 int uterm_monitor_new(struct uterm_monitor **out,
762 struct ev_eloop *eloop,
766 struct uterm_monitor *mon;
769 if (!out || !eloop || !cb)
772 mon = malloc(sizeof(*mon));
775 memset(mon, 0, sizeof(*mon));
780 shl_dlist_init(&mon->seats);
782 ret = monitor_sd_init(mon);
786 mon->udev = udev_new();
788 log_err("cannot create udev object");
793 mon->umon = udev_monitor_new_from_netlink(mon->udev, "udev");
795 log_err("cannot create udev monitor");
800 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
804 log_err("cannot add udev filter (%d): %m", ret);
809 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
813 log_err("cannot add udev filter (%d): %m", ret);
818 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
822 log_err("cannot add udev filter (%d): %m", ret);
827 ret = udev_monitor_enable_receiving(mon->umon);
830 log_err("cannot start udev monitor (%d): %m", ret);
835 ufd = udev_monitor_get_fd(mon->umon);
837 log_err("cannot get udev monitor fd");
842 set = fcntl(ufd, F_GETFL);
844 log_err("cannot get udev monitor fd flags");
850 ret = fcntl(ufd, F_SETFL, set);
852 log_err("cannot set udev monitor fd flags");
857 ret = ev_eloop_new_fd(mon->eloop, &mon->umon_fd, ufd, EV_READABLE,
858 monitor_udev_event, mon);
862 ev_eloop_ref(mon->eloop);
867 udev_monitor_unref(mon->umon);
869 udev_unref(mon->udev);
871 monitor_sd_deinit(mon);
877 void uterm_monitor_ref(struct uterm_monitor *mon)
879 if (!mon || !mon->ref)
885 void uterm_monitor_unref(struct uterm_monitor *mon)
887 struct uterm_monitor_seat *seat;
889 if (!mon || !mon->ref || --mon->ref)
892 while (mon->seats.next != &mon->seats) {
893 seat = shl_dlist_entry(mon->seats.next,
894 struct uterm_monitor_seat,
896 monitor_free_seat(seat);
899 ev_eloop_rm_fd(mon->umon_fd);
900 udev_monitor_unref(mon->umon);
901 udev_unref(mon->udev);
902 monitor_sd_deinit(mon);
903 ev_eloop_unref(mon->eloop);
907 void uterm_monitor_scan(struct uterm_monitor *mon)
909 struct udev_enumerate *e;
910 struct udev_list_entry *entry;
911 struct udev_device *dev;
918 monitor_refresh_seats(mon);
920 e = udev_enumerate_new(mon->udev);
922 log_err("cannot create udev enumeration");
926 ret = udev_enumerate_add_match_subsystem(e, "drm");
929 log_err("cannot add udev match (%d): %m", ret);
933 ret = udev_enumerate_add_match_subsystem(e, "graphics");
936 log_err("cannot add udev match (%d): %m", ret);
940 ret = udev_enumerate_add_match_subsystem(e, "input");
943 log_err("cannot add udev match (%d): %m", ret);
947 ret = udev_enumerate_scan_devices(e);
949 log_err("cannot scan udev devices (%d): %m", ret);
953 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
954 path = udev_list_entry_get_name(entry);
956 log_debug("udev device without syspath");
959 dev = udev_device_new_from_syspath(mon->udev, path);
961 log_debug("cannot get udev device for %s", path);
965 monitor_udev_add(mon, dev);
966 udev_device_unref(dev);
970 udev_enumerate_unref(e);
973 void uterm_monitor_set_seat_data(struct uterm_monitor_seat *seat, void *data)
981 void uterm_monitor_set_dev_data(struct uterm_monitor_dev *dev, void *data)