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"
46 #include "uterm_monitor.h"
47 #include "uterm_systemd_internal.h"
49 #define LOG_SUBSYSTEM "monitor"
51 struct uterm_monitor_dev {
52 struct shl_dlist list;
53 struct uterm_monitor_seat *seat;
60 struct uterm_monitor_seat {
61 struct shl_dlist list;
62 struct uterm_monitor *mon;
65 struct shl_dlist devices;
68 struct uterm_monitor {
70 struct ev_eloop *eloop;
75 struct ev_fd *sd_mon_fd;
78 struct udev_monitor *umon;
79 struct ev_fd *umon_fd;
81 struct shl_dlist seats;
84 static void monitor_new_seat(struct uterm_monitor *mon, const char *name);
85 static void monitor_free_seat(struct uterm_monitor_seat *seat);
87 static void monitor_refresh_seats(struct uterm_monitor *mon)
91 struct shl_dlist *iter, *tmp;
92 struct uterm_monitor_seat *seat;
94 /* Use only seat0 if multi-seat support is not available */
96 if (shl_dlist_empty(&mon->seats))
97 monitor_new_seat(mon, "seat0");
101 num = uterm_sd_get_seats(mon->sd, &seats);
103 log_warn("cannot read seat information from systemd: %d", num);
107 /* Remove all seats that are no longer present */
108 shl_dlist_for_each_safe(iter, tmp, &mon->seats) {
109 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
111 for (i = 0; i < num; ++i) {
112 if (!strcmp(seats[i], seat->name))
120 monitor_free_seat(seat);
124 /* Add all new seats */
125 for (i = 0; i < num; ++i) {
127 monitor_new_seat(mon, seats[i]);
135 static void monitor_sd_event(struct ev_fd *fd,
139 struct uterm_monitor *mon = data;
141 if (mask & (EV_HUP | EV_ERR)) {
142 log_warn("systemd login monitor closed unexpectedly");
147 uterm_sd_flush(mon->sd);
148 ev_eloop_flush_fd(mon->eloop, mon->sd_mon_fd);
150 monitor_refresh_seats(mon);
153 static void monitor_sd_poll(struct uterm_monitor *mon)
155 monitor_sd_event(mon->sd_mon_fd, EV_READABLE, mon);
158 static int monitor_sd_init(struct uterm_monitor *mon)
162 ret = uterm_sd_new(&mon->sd);
163 if (ret == -EOPNOTSUPP)
168 sfd = uterm_sd_get_fd(mon->sd);
170 log_err("cannot get systemd login monitor fd");
175 ret = ev_eloop_new_fd(mon->eloop, &mon->sd_mon_fd, sfd, EV_READABLE,
176 monitor_sd_event, mon);
183 uterm_sd_free(mon->sd);
187 static void monitor_sd_deinit(struct uterm_monitor *mon)
192 ev_eloop_rm_fd(mon->sd_mon_fd);
193 uterm_sd_free(mon->sd);
196 static void seat_new_dev(struct uterm_monitor_seat *seat,
201 struct uterm_monitor_dev *dev;
202 struct uterm_monitor_event ev;
204 dev = malloc(sizeof(*dev));
207 memset(dev, 0, sizeof(*dev));
212 dev->node = strdup(node);
216 shl_dlist_link(&seat->devices, &dev->list);
218 memset(&ev, 0, sizeof(ev));
219 ev.type = UTERM_MONITOR_NEW_DEV;
221 ev.seat_name = dev->seat->name;
222 ev.seat_data = dev->seat->data;
224 ev.dev_type = dev->type;
225 ev.dev_flags = dev->flags;
226 ev.dev_node = dev->node;
227 ev.dev_data = dev->data;
228 dev->seat->mon->cb(dev->seat->mon, &ev, dev->seat->mon->data);
230 log_debug("new device %s on %s", node, seat->name);
237 static void seat_free_dev(struct uterm_monitor_dev *dev)
239 struct uterm_monitor_event ev;
241 log_debug("free device %s on %s", dev->node, dev->seat->name);
243 shl_dlist_unlink(&dev->list);
245 memset(&ev, 0, sizeof(ev));
246 ev.type = UTERM_MONITOR_FREE_DEV;
248 ev.seat_name = dev->seat->name;
249 ev.seat_data = dev->seat->data;
251 ev.dev_type = dev->type;
252 ev.dev_flags = dev->flags;
253 ev.dev_node = dev->node;
254 ev.dev_data = dev->data;
255 dev->seat->mon->cb(dev->seat->mon, &ev, dev->seat->mon->data);
261 static struct uterm_monitor_dev *monitor_find_dev(struct uterm_monitor *mon,
262 struct udev_device *dev)
265 struct shl_dlist *iter, *iter2;
266 struct uterm_monitor_seat *seat;
267 struct uterm_monitor_dev *sdev;
269 node = udev_device_get_devnode(dev);
273 shl_dlist_for_each(iter, &mon->seats) {
274 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
276 shl_dlist_for_each(iter2, &seat->devices) {
277 sdev = shl_dlist_entry(iter2,
278 struct uterm_monitor_dev,
280 if (!strcmp(node, sdev->node))
288 static void monitor_new_seat(struct uterm_monitor *mon, const char *name)
290 struct uterm_monitor_seat *seat;
291 struct uterm_monitor_event ev;
293 seat = malloc(sizeof(*seat));
296 memset(seat, 0, sizeof(*seat));
298 shl_dlist_init(&seat->devices);
300 seat->name = strdup(name);
304 shl_dlist_link(&mon->seats, &seat->list);
306 memset(&ev, 0, sizeof(ev));
307 ev.type = UTERM_MONITOR_NEW_SEAT;
309 ev.seat_name = seat->name;
310 ev.seat_data = seat->data;
311 seat->mon->cb(seat->mon, &ev, seat->mon->data);
313 log_debug("new seat %s", name);
320 static void monitor_free_seat(struct uterm_monitor_seat *seat)
322 struct uterm_monitor_event ev;
323 struct uterm_monitor_dev *dev;
325 log_debug("free seat %s", seat->name);
327 while (seat->devices.next != &seat->devices) {
328 dev = shl_dlist_entry(seat->devices.next,
329 struct uterm_monitor_dev,
334 shl_dlist_unlink(&seat->list);
336 memset(&ev, 0, sizeof(ev));
337 ev.type = UTERM_MONITOR_FREE_SEAT;
339 ev.seat_name = seat->name;
340 ev.seat_data = seat->data;
341 seat->mon->cb(seat->mon, &ev, seat->mon->data);
347 static int get_card_id(struct udev_device *dev)
353 name = udev_device_get_sysname(dev);
356 if (strncmp(name, "card", 4) || !name[4])
359 devnum = strtol(&name[4], &end, 10);
360 if (devnum < 0 || *end)
366 static int get_fb_id(struct udev_device *dev)
372 name = udev_device_get_sysname(dev);
375 if (strncmp(name, "fb", 2) || !name[2])
378 devnum = strtol(&name[2], &end, 10);
379 if (devnum < 0 || *end)
386 * UTERM_MONITOR_DRM_BACKED:
387 * Nearly all DRM drivers do also create fbdev nodes which refer to the same
388 * hardware as the DRM devices. So we shouldn't advertise these fbdev nodes as
389 * real devices. Otherwise, the user might use these and the DRM devices
390 * simultaneously, thinking that they deal with two different hardware devices.
391 * We also report that it is a drm-device if we actually cannot verify that it
392 * is not some DRM device.
395 * Auxiliary devices are devices that are not the main GPU but rather some kind
396 * of hotpluggable helpers that provide additional display controllers. This is
397 * some kind of whitelist that tells the application that this GPU can safely be
398 * used as additional GPU together with but also independent of the primary GPU.
400 * UTERM_MONITOR_PRIMARY:
401 * A primary GPU is the main GPU in the system which is used to display boot
402 * graphics. Older systems used to have them hardwired, but especially embedded
403 * systems tend to no longer have primary GPUs so this flag cannot be guaranteed
404 * to be set for all systems.
405 * Hence, this flag shouldn't be used by default but rather as fallback if the
406 * user selects "primary GPU only" flag or similar.
409 static unsigned int get_fbdev_flags(struct uterm_monitor *mon, const char *node)
412 struct fb_fix_screeninfo finfo;
413 unsigned int flags = UTERM_MONITOR_DRM_BACKED;
415 fd = open(node, O_RDWR | O_CLOEXEC);
417 log_warning("cannot open fbdev node %s for drm-device verification (%d): %m",
422 ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
424 log_warning("cannot retrieve finfo from fbdev node %s for drm-device verification (%d): %m",
429 /* TODO: we really need some reliable flag here that tells us that we
430 * are dealing with a DRM device indirectly. Checking for "drmfb" suffix
431 * seems fine, but that may be just luck.
432 * If this turns out to not work reliably, we can also fall back to
433 * checking whether the parent udev device node does also provide a DRM
435 len = strlen(finfo.id);
436 if ((len < 5 || strcmp(&finfo.id[len - 5], "drmfb")) &&
437 strcmp(finfo.id, "nouveaufb") &&
438 strcmp(finfo.id, "psbfb"))
439 flags &= ~UTERM_MONITOR_DRM_BACKED;
441 if (!strcmp(finfo.id, "udlfb"))
442 flags |= UTERM_MONITOR_AUX;
443 else if (!strcmp(finfo.id, "VESA VGA"))
444 flags |= UTERM_MONITOR_PRIMARY;
451 static bool is_drm_primary(struct uterm_monitor *mon, struct udev_device *dev,
454 struct udev_device *pci;
457 pci = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
459 id = udev_device_get_sysattr_value(pci, "boot_vga");
460 if (id && !strcmp(id, "1")) {
461 log_debug("DRM device %s is primary PCI GPU", node);
470 * DRM doesn't provide public uapi headers but instead provides the ABI via
471 * libdrm... GREAT! That means we either need a build-time dependency to libdrm
472 * or we copy the parts we use in here. As we only need the VERSION ioctl, we
473 * simply copy it from drm.h.
476 struct uterm_drm_version {
477 int version_major; /**< Major version */
478 int version_minor; /**< Minor version */
479 int version_patchlevel; /**< Patch level */
480 size_t name_len; /**< Length of name buffer */
481 char *name; /**< Name of driver */
482 size_t date_len; /**< Length of date buffer */
483 char *date; /**< User-space buffer to hold date */
484 size_t desc_len; /**< Length of desc buffer */
485 char *desc; /**< User-space buffer to hold desc */
487 #define UTERM_DRM_IOCTL_VERSION _IOWR('d', 0x00, struct uterm_drm_version)
489 static inline char *get_drm_name(int fd)
491 struct uterm_drm_version v;
495 memset(&v, 0, sizeof(v));
496 ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
504 v.name = malloc(len + 1);
508 ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
518 static bool is_drm_usb(struct uterm_monitor *mon, const char *node, int fd)
523 name = get_drm_name(fd);
525 log_warning("cannot get driver name for DRM device %s (%d): %m",
530 if (!strcmp(name, "udl"))
535 log_debug("DRM device %s uses driver %s", node, name);
540 static unsigned int get_drm_flags(struct uterm_monitor *mon,
541 struct udev_device *dev, const char *node)
544 unsigned int flags = 0;
546 fd = open(node, O_RDWR | O_CLOEXEC);
548 log_warning("cannot open DRM device %s for primary-detection (%d): %m",
553 if (is_drm_primary(mon, dev, node))
554 flags |= UTERM_MONITOR_PRIMARY;
555 if (is_drm_usb(mon, node, fd))
556 flags |= UTERM_MONITOR_AUX;
562 static void monitor_udev_add(struct uterm_monitor *mon,
563 struct udev_device *dev)
565 const char *sname, *subs, *node, *name, *sysname;
566 struct shl_dlist *iter;
567 struct uterm_monitor_seat *seat;
568 unsigned int type, flags;
570 struct udev_device *p;
572 name = udev_device_get_syspath(dev);
574 log_debug("cannot get syspath of udev device");
578 if (monitor_find_dev(mon, dev)) {
579 log_debug("adding already available device %s", name);
583 node = udev_device_get_devnode(dev);
587 subs = udev_device_get_subsystem(dev);
589 log_debug("adding device with invalid subsystem %s", name);
593 if (!strcmp(subs, "drm")) {
594 if (mon->sd && udev_device_has_tag(dev, "seat") != 1) {
595 log_debug("adding non-seat'ed device %s", name);
598 id = get_card_id(dev);
600 log_debug("adding drm sub-device %s", name);
603 sname = udev_device_get_property_value(dev, "ID_SEAT");
604 type = UTERM_MONITOR_DRM;
605 flags = get_drm_flags(mon, dev, node);
606 } else if (!strcmp(subs, "graphics")) {
607 if (mon->sd && udev_device_has_tag(dev, "seat") != 1) {
608 log_debug("adding non-seat'ed device %s", name);
613 log_debug("adding fbdev sub-device %s", name);
616 sname = udev_device_get_property_value(dev, "ID_SEAT");
617 type = UTERM_MONITOR_FBDEV;
618 flags = get_fbdev_flags(mon, node);
619 } else if (!strcmp(subs, "input")) {
620 sysname = udev_device_get_sysname(dev);
621 if (!sysname || strncmp(sysname, "event", 5)) {
622 log_debug("adding unsupported input dev %s", name);
625 p = udev_device_get_parent_with_subsystem_devtype(dev,
628 log_debug("adding device without parent %s", name);
631 if (mon->sd && udev_device_has_tag(p, "seat") != 1) {
632 log_debug("adding non-seat'ed device %s", name);
635 sname = udev_device_get_property_value(p, "ID_SEAT");
636 type = UTERM_MONITOR_INPUT;
639 log_debug("adding device with unknown subsystem %s (%s)",
647 /* find correct seat */
648 shl_dlist_for_each(iter, &mon->seats) {
649 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
651 if (!strcmp(sname, seat->name))
655 if (iter == &mon->seats) {
656 log_debug("adding device for unknown seat %s (%s)",
661 seat_new_dev(seat, type, flags, node);
664 static void monitor_udev_remove(struct uterm_monitor *mon,
665 struct udev_device *dev)
667 struct uterm_monitor_dev *sdev;
669 sdev = monitor_find_dev(mon, dev);
671 log_debug("removing unknown device");
678 static void monitor_udev_change(struct uterm_monitor *mon,
679 struct udev_device *dev)
681 const char *sname, *val;
682 struct uterm_monitor_dev *sdev;
683 struct uterm_monitor_event ev;
685 sdev = monitor_find_dev(mon, dev);
687 sname = udev_device_get_property_value(dev, "ID_SEAT");
690 if (strcmp(sname, sdev->seat->name)) {
691 /* device switched seats; remove and add it again */
693 monitor_udev_add(mon, dev);
697 /* DRM devices send hotplug events; catch them here */
698 val = udev_device_get_property_value(dev, "HOTPLUG");
699 if (val && !strcmp(val, "1")) {
700 memset(&ev, 0, sizeof(ev));
701 ev.type = UTERM_MONITOR_HOTPLUG_DEV;
702 ev.seat = sdev->seat;
703 ev.seat_name = sdev->seat->name;
704 ev.seat_data = sdev->seat->data;
706 ev.dev_type = sdev->type;
707 ev.dev_node = sdev->node;
708 ev.dev_data = sdev->data;
709 sdev->seat->mon->cb(sdev->seat->mon, &ev,
710 sdev->seat->mon->data);
713 /* Unknown device; maybe it switched into a known seat? Try
714 * adding it as new device. If that fails, we ignore it */
715 monitor_udev_add(mon, dev);
719 static void monitor_udev_event(struct ev_fd *fd,
723 struct uterm_monitor *mon = data;
724 struct udev_device *dev;
727 if (mask & (EV_HUP | EV_ERR)) {
728 log_warn("udev monitor closed unexpectedly");
733 * If there is a pending sd_event in the current epoll-queue and our
734 * udev event is called first, we must make sure to first execute the
735 * sd_event. Otherwise, our udev event might introduce new seats that
736 * will be initialized later and we loose devices.
737 * monitor_sd_event() flushes the sd-fd so we will never refresh seat
738 * values twice in a single epoll-loop.
740 monitor_sd_poll(mon);
743 /* we use non-blocking udev monitor so ignore errors */
744 dev = udev_monitor_receive_device(mon->umon);
748 action = udev_device_get_action(dev);
750 if (!strcmp(action, "add"))
751 monitor_udev_add(mon, dev);
752 else if (!strcmp(action, "remove"))
753 monitor_udev_remove(mon, dev);
754 else if (!strcmp(action, "change"))
755 monitor_udev_change(mon, dev);
758 udev_device_unref(dev);
763 int uterm_monitor_new(struct uterm_monitor **out,
764 struct ev_eloop *eloop,
768 struct uterm_monitor *mon;
771 if (!out || !eloop || !cb)
774 mon = malloc(sizeof(*mon));
777 memset(mon, 0, sizeof(*mon));
782 shl_dlist_init(&mon->seats);
784 ret = monitor_sd_init(mon);
788 mon->udev = udev_new();
790 log_err("cannot create udev object");
795 mon->umon = udev_monitor_new_from_netlink(mon->udev, "udev");
797 log_err("cannot create udev monitor");
802 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
806 log_err("cannot add udev filter (%d): %m", ret);
811 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
815 log_err("cannot add udev filter (%d): %m", ret);
820 ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
824 log_err("cannot add udev filter (%d): %m", ret);
829 ret = udev_monitor_enable_receiving(mon->umon);
832 log_err("cannot start udev monitor (%d): %m", ret);
837 ufd = udev_monitor_get_fd(mon->umon);
839 log_err("cannot get udev monitor fd");
844 set = fcntl(ufd, F_GETFL);
846 log_err("cannot get udev monitor fd flags");
852 ret = fcntl(ufd, F_SETFL, set);
854 log_err("cannot set udev monitor fd flags");
859 ret = ev_eloop_new_fd(mon->eloop, &mon->umon_fd, ufd, EV_READABLE,
860 monitor_udev_event, mon);
864 ev_eloop_ref(mon->eloop);
869 udev_monitor_unref(mon->umon);
871 udev_unref(mon->udev);
873 monitor_sd_deinit(mon);
880 void uterm_monitor_ref(struct uterm_monitor *mon)
882 if (!mon || !mon->ref)
889 void uterm_monitor_unref(struct uterm_monitor *mon)
891 struct uterm_monitor_seat *seat;
893 if (!mon || !mon->ref || --mon->ref)
896 while (mon->seats.next != &mon->seats) {
897 seat = shl_dlist_entry(mon->seats.next,
898 struct uterm_monitor_seat,
900 monitor_free_seat(seat);
903 ev_eloop_rm_fd(mon->umon_fd);
904 udev_monitor_unref(mon->umon);
905 udev_unref(mon->udev);
906 monitor_sd_deinit(mon);
907 ev_eloop_unref(mon->eloop);
912 void uterm_monitor_scan(struct uterm_monitor *mon)
914 struct udev_enumerate *e;
915 struct udev_list_entry *entry;
916 struct udev_device *dev;
923 monitor_refresh_seats(mon);
925 e = udev_enumerate_new(mon->udev);
927 log_err("cannot create udev enumeration");
931 ret = udev_enumerate_add_match_subsystem(e, "drm");
934 log_err("cannot add udev match (%d): %m", ret);
938 ret = udev_enumerate_add_match_subsystem(e, "graphics");
941 log_err("cannot add udev match (%d): %m", ret);
945 ret = udev_enumerate_add_match_subsystem(e, "input");
948 log_err("cannot add udev match (%d): %m", ret);
952 ret = udev_enumerate_scan_devices(e);
954 log_err("cannot scan udev devices (%d): %m", ret);
958 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
959 path = udev_list_entry_get_name(entry);
961 log_debug("udev device without syspath");
964 dev = udev_device_new_from_syspath(mon->udev, path);
966 log_debug("cannot get udev device for %s", path);
970 monitor_udev_add(mon, dev);
971 udev_device_unref(dev);
975 udev_enumerate_unref(e);
979 void uterm_monitor_set_seat_data(struct uterm_monitor_seat *seat, void *data)
988 void uterm_monitor_set_dev_data(struct uterm_monitor_dev *dev, void *data)