wlt: fix shl_hook API changes
[platform/upstream/kmscon.git] / src / uterm_monitor.c
1 /*
2  * uterm - Linux User-Space Terminal
3  *
4  * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
5  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
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.
24  */
25
26 /*
27  * System Monitor
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.
32  */
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <libudev.h>
37 #include <linux/fb.h>
38 #include <stdbool.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/ioctl.h>
42 #include <unistd.h>
43 #include "log.h"
44 #include "shl_dlist.h"
45 #include "uterm_monitor.h"
46 #include "uterm_systemd_internal.h"
47
48 #define LOG_SUBSYSTEM "monitor"
49
50 struct uterm_monitor_dev {
51         struct shl_dlist list;
52         struct uterm_monitor_seat *seat;
53         unsigned int type;
54         unsigned int flags;
55         char *node;
56         void *data;
57 };
58
59 struct uterm_monitor_seat {
60         struct shl_dlist list;
61         struct uterm_monitor *mon;
62         char *name;
63         void *data;
64         struct shl_dlist devices;
65 };
66
67 struct uterm_monitor {
68         unsigned long ref;
69         struct ev_eloop *eloop;
70         uterm_monitor_cb cb;
71         void *data;
72
73         struct uterm_sd *sd;
74         struct ev_fd *sd_mon_fd;
75
76         struct udev *udev;
77         struct udev_monitor *umon;
78         struct ev_fd *umon_fd;
79
80         struct shl_dlist seats;
81 };
82
83 static void monitor_new_seat(struct uterm_monitor *mon, const char *name);
84 static void monitor_free_seat(struct uterm_monitor_seat *seat);
85
86 static void monitor_refresh_seats(struct uterm_monitor *mon)
87 {
88         char **seats;
89         int num, i;
90         struct shl_dlist *iter, *tmp;
91         struct uterm_monitor_seat *seat;
92
93         /* Use only seat0 if multi-seat support is not available */
94         if (!mon->sd) {
95                 if (shl_dlist_empty(&mon->seats))
96                         monitor_new_seat(mon, "seat0");
97                 return;
98         }
99
100         num = uterm_sd_get_seats(mon->sd, &seats);
101         if (num < 0) {
102                 log_warn("cannot read seat information from systemd: %d", num);
103                 return;
104         }
105
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,
109                                                 list);
110                 for (i = 0; i < num; ++i) {
111                         if (!strcmp(seats[i], seat->name))
112                                 break;
113                 }
114
115                 if (i < num) {
116                         free(seats[i]);
117                         seats[i] = NULL;
118                 } else {
119                         monitor_free_seat(seat);
120                 }
121         }
122
123         /* Add all new seats */
124         for (i = 0; i < num; ++i) {
125                 if (seats[i]) {
126                         monitor_new_seat(mon, seats[i]);
127                         free(seats[i]);
128                 }
129         }
130
131         free(seats);
132 }
133
134 static void monitor_sd_event(struct ev_fd *fd,
135                              int mask,
136                              void *data)
137 {
138         struct uterm_monitor *mon = data;
139
140         if (mask & (EV_HUP | EV_ERR)) {
141                 log_warn("systemd login monitor closed unexpectedly");
142                 return;
143         }
144
145         if (mon->sd) {
146                 uterm_sd_flush(mon->sd);
147                 ev_eloop_flush_fd(mon->eloop, mon->sd_mon_fd);
148         }
149         monitor_refresh_seats(mon);
150 }
151
152 static void monitor_sd_poll(struct uterm_monitor *mon)
153 {
154         monitor_sd_event(mon->sd_mon_fd, EV_READABLE, mon);
155 }
156
157 static int monitor_sd_init(struct uterm_monitor *mon)
158 {
159         int ret, sfd;
160
161         ret = uterm_sd_new(&mon->sd);
162         if (ret == -EOPNOTSUPP)
163                 return 0;
164         else if (ret)
165                 return ret;
166
167         sfd = uterm_sd_get_fd(mon->sd);
168         if (sfd < 0) {
169                 log_err("cannot get systemd login monitor fd");
170                 ret = -EFAULT;
171                 goto err_sd;
172         }
173
174         ret = ev_eloop_new_fd(mon->eloop, &mon->sd_mon_fd, sfd, EV_READABLE,
175                               monitor_sd_event, mon);
176         if (ret)
177                 goto err_sd;
178
179         return 0;
180
181 err_sd:
182         uterm_sd_free(mon->sd);
183         return ret;
184 }
185
186 static void monitor_sd_deinit(struct uterm_monitor *mon)
187 {
188         if (!mon->sd)
189                 return;
190
191         ev_eloop_rm_fd(mon->sd_mon_fd);
192         uterm_sd_free(mon->sd);
193 }
194
195 static void seat_new_dev(struct uterm_monitor_seat *seat,
196                                 unsigned int type,
197                                 unsigned int flags,
198                                 const char *node)
199 {
200         struct uterm_monitor_dev *dev;
201         struct uterm_monitor_event ev;
202
203         dev = malloc(sizeof(*dev));
204         if (!dev)
205                 return;
206         memset(dev, 0, sizeof(*dev));
207         dev->seat = seat;
208         dev->type = type;
209         dev->flags = flags;
210
211         dev->node = strdup(node);
212         if (!dev->node)
213                 goto err_free;
214
215         shl_dlist_link(&seat->devices, &dev->list);
216
217         memset(&ev, 0, sizeof(ev));
218         ev.type = UTERM_MONITOR_NEW_DEV;
219         ev.seat = dev->seat;
220         ev.seat_name = dev->seat->name;
221         ev.seat_data = dev->seat->data;
222         ev.dev = dev;
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);
228
229         log_debug("new device %s on %s", node, seat->name);
230         return;
231
232 err_free:
233         free(dev);
234 }
235
236 static void seat_free_dev(struct uterm_monitor_dev *dev)
237 {
238         struct uterm_monitor_event ev;
239
240         log_debug("free device %s on %s", dev->node, dev->seat->name);
241
242         shl_dlist_unlink(&dev->list);
243
244         memset(&ev, 0, sizeof(ev));
245         ev.type = UTERM_MONITOR_FREE_DEV;
246         ev.seat = dev->seat;
247         ev.seat_name = dev->seat->name;
248         ev.seat_data = dev->seat->data;
249         ev.dev = dev;
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);
255
256         free(dev->node);
257         free(dev);
258 }
259
260 static struct uterm_monitor_dev *monitor_find_dev(struct uterm_monitor *mon,
261                                                 struct udev_device *dev)
262 {
263         const char *node;
264         struct shl_dlist *iter, *iter2;
265         struct uterm_monitor_seat *seat;
266         struct uterm_monitor_dev *sdev;
267
268         node = udev_device_get_devnode(dev);
269         if (!node)
270                 return NULL;
271
272         shl_dlist_for_each(iter, &mon->seats) {
273                 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
274                                                 list);
275                 shl_dlist_for_each(iter2, &seat->devices) {
276                         sdev = shl_dlist_entry(iter2,
277                                                 struct uterm_monitor_dev,
278                                                 list);
279                         if (!strcmp(node, sdev->node))
280                                 return sdev;
281                 }
282         }
283
284         return NULL;
285 }
286
287 static void monitor_new_seat(struct uterm_monitor *mon, const char *name)
288 {
289         struct uterm_monitor_seat *seat;
290         struct uterm_monitor_event ev;
291
292         seat = malloc(sizeof(*seat));
293         if (!seat)
294                 return;
295         memset(seat, 0, sizeof(*seat));
296         seat->mon = mon;
297         shl_dlist_init(&seat->devices);
298
299         seat->name = strdup(name);
300         if (!seat->name)
301                 goto err_free;
302
303         shl_dlist_link(&mon->seats, &seat->list);
304
305         memset(&ev, 0, sizeof(ev));
306         ev.type = UTERM_MONITOR_NEW_SEAT;
307         ev.seat = seat;
308         ev.seat_name = seat->name;
309         ev.seat_data = seat->data;
310         seat->mon->cb(seat->mon, &ev, seat->mon->data);
311
312         log_debug("new seat %s", name);
313         return;
314
315 err_free:
316         free(seat);
317 }
318
319 static void monitor_free_seat(struct uterm_monitor_seat *seat)
320 {
321         struct uterm_monitor_event ev;
322         struct uterm_monitor_dev *dev;
323
324         log_debug("free seat %s", seat->name);
325
326         while (seat->devices.next != &seat->devices) {
327                 dev = shl_dlist_entry(seat->devices.next,
328                                                 struct uterm_monitor_dev,
329                                                 list);
330                 seat_free_dev(dev);
331         }
332
333         shl_dlist_unlink(&seat->list);
334
335         memset(&ev, 0, sizeof(ev));
336         ev.type = UTERM_MONITOR_FREE_SEAT;
337         ev.seat = seat;
338         ev.seat_name = seat->name;
339         ev.seat_data = seat->data;
340         seat->mon->cb(seat->mon, &ev, seat->mon->data);
341
342         free(seat->name);
343         free(seat);
344 }
345
346 static int get_card_id(struct udev_device *dev)
347 {
348         const char *name;
349         char *end;
350         int devnum;
351
352         name = udev_device_get_sysname(dev);
353         if (!name)
354                 return -ENODEV;
355         if (strncmp(name, "card", 4) || !name[4])
356                 return -ENODEV;
357
358         devnum = strtol(&name[4], &end, 10);
359         if (devnum < 0 || *end)
360                 return -ENODEV;
361
362         return devnum;
363 }
364
365 static int get_fb_id(struct udev_device *dev)
366 {
367         const char *name;
368         char *end;
369         int devnum;
370
371         name = udev_device_get_sysname(dev);
372         if (!name)
373                 return -ENODEV;
374         if (strncmp(name, "fb", 2) || !name[2])
375                 return -ENODEV;
376
377         devnum = strtol(&name[2], &end, 10);
378         if (devnum < 0 || *end)
379                 return -ENODEV;
380
381         return devnum;
382 }
383
384 /*
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.
392  *
393  * UTERM_MONITOR_AUX:
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.
398  *
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.
406  */
407
408 static unsigned int get_fbdev_flags(struct uterm_monitor *mon, const char *node)
409 {
410         int fd, ret, len;
411         struct fb_fix_screeninfo finfo;
412         unsigned int flags = UTERM_MONITOR_DRM_BACKED;
413
414         fd = open(node, O_RDWR | O_CLOEXEC);
415         if (fd < 0) {
416                 log_warning("cannot open fbdev node %s for drm-device verification (%d): %m",
417                             node, errno);
418                 return flags;
419         }
420
421         ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
422         if (ret) {
423                 log_warning("cannot retrieve finfo from fbdev node %s for drm-device verification (%d): %m",
424                             node, errno);
425                 goto out_close;
426         }
427
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
433          * device. */
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;
439
440         if (!strcmp(finfo.id, "udlfb"))
441                 flags |= UTERM_MONITOR_AUX;
442         else if (!strcmp(finfo.id, "VESA VGA"))
443                 flags |= UTERM_MONITOR_PRIMARY;
444
445 out_close:
446         close(fd);
447         return flags;
448 }
449
450 static bool is_drm_primary(struct uterm_monitor *mon, struct udev_device *dev,
451                            const char *node)
452 {
453         struct udev_device *pci;
454         const char *id;
455
456         pci = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
457         if (pci) {
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);
461                         return true;
462                 }
463         }
464
465         return false;
466 }
467
468 /*
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.
473  */
474
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 */
485 };
486 #define UTERM_DRM_IOCTL_VERSION _IOWR('d', 0x00, struct uterm_drm_version)
487
488 static inline char *get_drm_name(int fd)
489 {
490         struct uterm_drm_version v;
491         unsigned int len;
492         int ret;
493
494         memset(&v, 0, sizeof(v));
495         ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
496         if (ret < 0)
497                 return NULL;
498
499         if (!v.name_len)
500                 return NULL;
501
502         len = v.name_len;
503         v.name = malloc(len + 1);
504         if (!v.name)
505                 return NULL;
506
507         ret = ioctl(fd, UTERM_DRM_IOCTL_VERSION, &v);
508         if (ret < 0) {
509                 free(v.name);
510                 return NULL;
511         }
512
513         v.name[len] = 0;
514         return v.name;
515 }
516
517 static bool is_drm_usb(struct uterm_monitor *mon, const char *node, int fd)
518 {
519         char *name;
520         bool res;
521
522         name = get_drm_name(fd);
523         if (!name) {
524                 log_warning("cannot get driver name for DRM device %s (%d): %m",
525                             node, errno);
526                 return false;
527         }
528
529         if (!strcmp(name, "udl"))
530                 res = true;
531         else
532                 res = false;
533
534         log_debug("DRM device %s uses driver %s", node, name);
535         free(name);
536         return res;
537 }
538
539 static unsigned int get_drm_flags(struct uterm_monitor *mon,
540                                   struct udev_device *dev, const char *node)
541 {
542         int fd;
543         unsigned int flags = 0;
544
545         fd = open(node, O_RDWR | O_CLOEXEC);
546         if (fd < 0) {
547                 log_warning("cannot open DRM device %s for primary-detection (%d): %m",
548                             node, errno);
549                 return flags;
550         }
551
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;
556
557         close(fd);
558         return flags;
559 }
560
561 static void monitor_udev_add(struct uterm_monitor *mon,
562                                 struct udev_device *dev)
563 {
564         const char *sname, *subs, *node, *name, *sysname;
565         struct shl_dlist *iter;
566         struct uterm_monitor_seat *seat;
567         unsigned int type, flags;
568         int id;
569         struct udev_device *p;
570
571         name = udev_device_get_syspath(dev);
572         if (!name) {
573                 log_debug("cannot get syspath of udev device");
574                 return;
575         }
576
577         if (monitor_find_dev(mon, dev)) {
578                 log_debug("adding already available device %s", name);
579                 return;
580         }
581
582         node = udev_device_get_devnode(dev);
583         if (!node)
584                 return;
585
586         subs = udev_device_get_subsystem(dev);
587         if (!subs) {
588                 log_debug("adding device with invalid subsystem %s", name);
589                 return;
590         }
591
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);
595                         return;
596                 }
597                 id = get_card_id(dev);
598                 if (id < 0) {
599                         log_debug("adding drm sub-device %s", name);
600                         return;
601                 }
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);
608                         return;
609                 }
610                 id = get_fb_id(dev);
611                 if (id < 0) {
612                         log_debug("adding fbdev sub-device %s", name);
613                         return;
614                 }
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);
622                         return;
623                 }
624                 p = udev_device_get_parent_with_subsystem_devtype(dev,
625                                                                 "input", NULL);
626                 if (!p) {
627                         log_debug("adding device without parent %s", name);
628                         return;
629                 }
630                 if (mon->sd && udev_device_has_tag(p, "seat") != 1) {
631                         log_debug("adding non-seat'ed device %s", name);
632                         return;
633                 }
634                 sname = udev_device_get_property_value(p, "ID_SEAT");
635                 type = UTERM_MONITOR_INPUT;
636                 flags = 0;
637         } else {
638                 log_debug("adding device with unknown subsystem %s (%s)",
639                                 subs, name);
640                 return;
641         }
642
643         if (!sname)
644                 sname = "seat0";
645
646         /* find correct seat */
647         shl_dlist_for_each(iter, &mon->seats) {
648                 seat = shl_dlist_entry(iter, struct uterm_monitor_seat,
649                                                 list);
650                 if (!strcmp(sname, seat->name))
651                         break;
652         }
653
654         if (iter == &mon->seats) {
655                 log_debug("adding device for unknown seat %s (%s)",
656                                 sname, name);
657                 return;
658         }
659
660         seat_new_dev(seat, type, flags, node);
661 }
662
663 static void monitor_udev_remove(struct uterm_monitor *mon,
664                                 struct udev_device *dev)
665 {
666         struct uterm_monitor_dev *sdev;
667
668         sdev = monitor_find_dev(mon, dev);
669         if (!sdev) {
670                 log_debug("removing unknown device");
671                 return;
672         }
673
674         seat_free_dev(sdev);
675 }
676
677 static void monitor_udev_change(struct uterm_monitor *mon,
678                                 struct udev_device *dev)
679 {
680         const char *sname, *val;
681         struct uterm_monitor_dev *sdev;
682         struct uterm_monitor_event ev;
683
684         sdev = monitor_find_dev(mon, dev);
685         if (sdev) {
686                 sname = udev_device_get_property_value(dev, "ID_SEAT");
687                 if (!sname)
688                         sname = "seat0";
689                 if (strcmp(sname, sdev->seat->name)) {
690                         /* device switched seats; remove and add it again */
691                         seat_free_dev(sdev);
692                         monitor_udev_add(mon, dev);
693                         return;
694                 }
695
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;
704                         ev.dev = sdev;
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);
710                 }
711         } else {
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);
715         }
716 }
717
718 static void monitor_udev_event(struct ev_fd *fd,
719                                 int mask,
720                                 void *data)
721 {
722         struct uterm_monitor *mon = data;
723         struct udev_device *dev;
724         const char *action;
725
726         if (mask & (EV_HUP | EV_ERR)) {
727                 log_warn("udev monitor closed unexpectedly");
728                 return;
729         }
730
731         /*
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.
738          */
739         monitor_sd_poll(mon);
740
741         while (true) {
742                 /* we use non-blocking udev monitor so ignore errors */
743                 dev = udev_monitor_receive_device(mon->umon);
744                 if (!dev)
745                         return;
746
747                 action = udev_device_get_action(dev);
748                 if (action) {
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);
755                 }
756
757                 udev_device_unref(dev);
758         }
759 }
760
761 int uterm_monitor_new(struct uterm_monitor **out,
762                         struct ev_eloop *eloop,
763                         uterm_monitor_cb cb,
764                         void *data)
765 {
766         struct uterm_monitor *mon;
767         int ret, ufd, set;
768
769         if (!out || !eloop || !cb)
770                 return -EINVAL;
771
772         mon = malloc(sizeof(*mon));
773         if (!mon)
774                 return -EINVAL;
775         memset(mon, 0, sizeof(*mon));
776         mon->ref = 1;
777         mon->eloop = eloop;
778         mon->cb = cb;
779         mon->data = data;
780         shl_dlist_init(&mon->seats);
781
782         ret = monitor_sd_init(mon);
783         if (ret)
784                 goto err_free;
785
786         mon->udev = udev_new();
787         if (!mon->udev) {
788                 log_err("cannot create udev object");
789                 ret = -EFAULT;
790                 goto err_sd;
791         }
792
793         mon->umon = udev_monitor_new_from_netlink(mon->udev, "udev");
794         if (!mon->umon) {
795                 log_err("cannot create udev monitor");
796                 ret = -EFAULT;
797                 goto err_udev;
798         }
799
800         ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
801                                                         "drm", "drm_minor");
802         if (ret) {
803                 errno = -ret;
804                 log_err("cannot add udev filter (%d): %m", ret);
805                 ret = -EFAULT;
806                 goto err_umon;
807         }
808
809         ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
810                                                         "graphics", NULL);
811         if (ret) {
812                 errno = -ret;
813                 log_err("cannot add udev filter (%d): %m", ret);
814                 ret = -EFAULT;
815                 goto err_umon;
816         }
817
818         ret = udev_monitor_filter_add_match_subsystem_devtype(mon->umon,
819                                                         "input", NULL);
820         if (ret) {
821                 errno = -ret;
822                 log_err("cannot add udev filter (%d): %m", ret);
823                 ret = -EFAULT;
824                 goto err_umon;
825         }
826
827         ret = udev_monitor_enable_receiving(mon->umon);
828         if (ret) {
829                 errno = -ret;
830                 log_err("cannot start udev monitor (%d): %m", ret);
831                 ret = -EFAULT;
832                 goto err_umon;
833         }
834
835         ufd = udev_monitor_get_fd(mon->umon);
836         if (ufd < 0) {
837                 log_err("cannot get udev monitor fd");
838                 ret = -EFAULT;
839                 goto err_umon;
840         }
841
842         set = fcntl(ufd, F_GETFL);
843         if (set < 0) {
844                 log_err("cannot get udev monitor fd flags");
845                 ret = -EFAULT;
846                 goto err_umon;
847         }
848
849         set |= O_NONBLOCK;
850         ret = fcntl(ufd, F_SETFL, set);
851         if (ret != 0) {
852                 log_err("cannot set udev monitor fd flags");
853                 ret = -EFAULT;
854                 goto err_umon;
855         }
856
857         ret = ev_eloop_new_fd(mon->eloop, &mon->umon_fd, ufd, EV_READABLE,
858                                 monitor_udev_event, mon);
859         if (ret)
860                 goto err_umon;
861
862         ev_eloop_ref(mon->eloop);
863         *out = mon;
864         return 0;
865
866 err_umon:
867         udev_monitor_unref(mon->umon);
868 err_udev:
869         udev_unref(mon->udev);
870 err_sd:
871         monitor_sd_deinit(mon);
872 err_free:
873         free(mon);
874         return ret;
875 }
876
877 void uterm_monitor_ref(struct uterm_monitor *mon)
878 {
879         if (!mon || !mon->ref)
880                 return;
881
882         ++mon->ref;
883 }
884
885 void uterm_monitor_unref(struct uterm_monitor *mon)
886 {
887         struct uterm_monitor_seat *seat;
888
889         if (!mon || !mon->ref || --mon->ref)
890                 return;
891
892         while (mon->seats.next != &mon->seats) {
893                 seat = shl_dlist_entry(mon->seats.next,
894                                                 struct uterm_monitor_seat,
895                                                 list);
896                 monitor_free_seat(seat);
897         }
898
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);
904         free(mon);
905 }
906
907 void uterm_monitor_scan(struct uterm_monitor *mon)
908 {
909         struct udev_enumerate *e;
910         struct udev_list_entry *entry;
911         struct udev_device *dev;
912         const char *path;
913         int ret;
914
915         if (!mon)
916                 return;
917
918         monitor_refresh_seats(mon);
919
920         e = udev_enumerate_new(mon->udev);
921         if (!e) {
922                 log_err("cannot create udev enumeration");
923                 return;
924         }
925
926         ret = udev_enumerate_add_match_subsystem(e, "drm");
927         if (ret) {
928                 errno = -ret;
929                 log_err("cannot add udev match (%d): %m", ret);
930                 goto out_enum;
931         }
932
933         ret = udev_enumerate_add_match_subsystem(e, "graphics");
934         if (ret) {
935                 errno = -ret;
936                 log_err("cannot add udev match (%d): %m", ret);
937                 goto out_enum;
938         }
939
940         ret = udev_enumerate_add_match_subsystem(e, "input");
941         if (ret) {
942                 errno = -ret;
943                 log_err("cannot add udev match (%d): %m", ret);
944                 goto out_enum;
945         }
946
947         ret = udev_enumerate_scan_devices(e);
948         if (ret) {
949                 log_err("cannot scan udev devices (%d): %m", ret);
950                 goto out_enum;
951         }
952
953         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
954                 path = udev_list_entry_get_name(entry);
955                 if (!path) {
956                         log_debug("udev device without syspath");
957                         continue;
958                 }
959                 dev = udev_device_new_from_syspath(mon->udev, path);
960                 if (!dev) {
961                         log_debug("cannot get udev device for %s", path);
962                         continue;
963                 }
964
965                 monitor_udev_add(mon, dev);
966                 udev_device_unref(dev);
967         }
968
969 out_enum:
970         udev_enumerate_unref(e);
971 }
972
973 void uterm_monitor_set_seat_data(struct uterm_monitor_seat *seat, void *data)
974 {
975         if (!seat)
976                 return;
977
978         seat->data = data;
979 }
980
981 void uterm_monitor_set_dev_data(struct uterm_monitor_dev *dev, void *data)
982 {
983         if (!dev)
984                 return;
985
986         dev->data = data;
987 }