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