1 /*
2  * Copyright © 2009 Julien Cristau
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author: Julien Cristau <jcristau@debian.org>
24  */
25 
26 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
28 #endif
29 
30 #include <libudev.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 
35 #include "input.h"
36 #include "inputstr.h"
37 #include "hotplug.h"
38 #include "config-backends.h"
39 #include "os.h"
40 #include "globals.h"
41 #include "systemd-logind.h"
42 
43 #define UDEV_XKB_PROP_KEY "xkb"
44 
45 #define LOG_PROPERTY(path, prop, val)                                   \
46     LogMessageVerb(X_INFO, 10,                                          \
47                    "config/udev: getting property %s on %s "            \
48                    "returned \"%s\"\n",                                 \
49                    (prop), (path), (val) ? (val) : "(null)")
50 #define LOG_SYSATTR(path, attr, val)                                    \
51     LogMessageVerb(X_INFO, 10,                                          \
52                    "config/udev: getting attribute %s on %s "           \
53                    "returned \"%s\"\n",                                 \
54                    (attr), (path), (val) ? (val) : "(null)")
55 
56 static struct udev_monitor *udev_monitor;
57 
58 #ifdef CONFIG_UDEV_KMS
59 static void
60 config_udev_odev_setup_attribs(const char *path, const char *syspath,
61                                int major, int minor,
62                                config_odev_probe_proc_ptr probe_callback);
63 #endif
64 
65 static char itoa_buf[16];
66 
itoa(int i)67 static const char *itoa(int i)
68 {
69     snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
70     return itoa_buf;
71 }
72 
73 static Bool
check_seat(struct udev_device * udev_device)74 check_seat(struct udev_device *udev_device)
75 {
76     const char *dev_seat;
77 
78     dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
79     if (!dev_seat)
80         dev_seat = "seat0";
81 
82     if (SeatId && strcmp(dev_seat, SeatId))
83         return FALSE;
84 
85     if (!SeatId && strcmp(dev_seat, "seat0"))
86         return FALSE;
87 
88     return TRUE;
89 }
90 
91 static void
device_added(struct udev_device * udev_device)92 device_added(struct udev_device *udev_device)
93 {
94     const char *path, *name = NULL;
95     char *config_info = NULL;
96     const char *syspath;
97     const char *tags_prop;
98     const char *key, *value, *tmp;
99     InputOption *input_options;
100     InputAttributes attrs = { };
101     DeviceIntPtr dev = NULL;
102     struct udev_list_entry *set, *entry;
103     struct udev_device *parent;
104     int rc;
105     dev_t devnum;
106 
107     path = udev_device_get_devnode(udev_device);
108 
109     syspath = udev_device_get_syspath(udev_device);
110 
111     if (!path || !syspath)
112         return;
113 
114     if (!check_seat(udev_device))
115         return;
116 
117     devnum = udev_device_get_devnum(udev_device);
118 
119 #ifdef CONFIG_UDEV_KMS
120     if (!strcmp(udev_device_get_subsystem(udev_device), "drm")) {
121         const char *sysname = udev_device_get_sysname(udev_device);
122 
123         if (strncmp(sysname, "card", 4) != 0)
124             return;
125 
126         /* Check for devices already added through xf86platformProbe() */
127         if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
128             return;
129 
130         LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
131 
132         config_udev_odev_setup_attribs(path, syspath, major(devnum),
133                                        minor(devnum), NewGPUDeviceRequest);
134         return;
135     }
136 #endif
137 
138     value = udev_device_get_property_value(udev_device, "ID_INPUT");
139     if (!value || !strcmp(value, "0")) {
140         LogMessageVerb(X_INFO, 10,
141                        "config/udev: ignoring device %s without "
142                        "property ID_INPUT set\n", path);
143         return;
144     }
145 
146     input_options = input_option_new(NULL, "_source", "server/udev");
147     if (!input_options)
148         return;
149 
150     parent = udev_device_get_parent(udev_device);
151     if (parent) {
152         const char *ppath = udev_device_get_devnode(parent);
153         const char *product = udev_device_get_property_value(parent, "PRODUCT");
154         const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
155         unsigned int usb_vendor, usb_model;
156 
157         name = udev_device_get_sysattr_value(parent, "name");
158         LOG_SYSATTR(ppath, "name", name);
159         if (!name) {
160             name = udev_device_get_property_value(parent, "NAME");
161             LOG_PROPERTY(ppath, "NAME", name);
162         }
163 
164         /* construct USB ID in lowercase hex - "0000:ffff" */
165         if (product &&
166             sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
167             char *usb_id;
168             if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
169                 == -1)
170                 usb_id = NULL;
171             else
172                 LOG_PROPERTY(ppath, "PRODUCT", product);
173             attrs.usb_id = usb_id;
174         }
175 
176         while (!pnp_id && (parent = udev_device_get_parent(parent))) {
177             pnp_id = udev_device_get_sysattr_value(parent, "id");
178             if (!pnp_id)
179                 continue;
180 
181             attrs.pnp_id = strdup(pnp_id);
182             ppath = udev_device_get_devnode(parent);
183             LOG_SYSATTR(ppath, "id", pnp_id);
184         }
185 
186     }
187     if (!name)
188         name = "(unnamed)";
189     else
190         attrs.product = strdup(name);
191     input_options = input_option_new(input_options, "name", name);
192     input_options = input_option_new(input_options, "path", path);
193     if(strstr(path, "kbdmux") != NULL) {
194         /*
195          * Don't pass "device" option if the keyboard is already attached
196          * to the console (ie. open() fails). This would activate a special
197          * logic in xf86-input-keyboard. Prevent any other attached to console
198          * keyboards being processed. There can be only one such device.
199          */
200         int fd = open(path, O_RDONLY);
201         if (fd > -1) {
202             close(fd);
203             input_options = input_option_new(input_options, "device", path);
204         }
205     }
206     else
207         input_options = input_option_new(input_options, "device", path);
208     input_options = input_option_new(input_options, "major", itoa(major(devnum)));
209     input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
210     if (path)
211         attrs.device = strdup(path);
212 
213     tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
214     LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
215     attrs.tags = xstrtokenize(tags_prop, ",");
216 
217     if (asprintf(&config_info, "udev:%s", syspath) == -1) {
218         config_info = NULL;
219         goto unwind;
220     }
221 
222     if (device_is_duplicate(config_info)) {
223         LogMessage(X_WARNING, "config/udev: device %s already added. "
224                    "Ignoring.\n", name);
225         goto unwind;
226     }
227 
228     set = udev_device_get_properties_list_entry(udev_device);
229     udev_list_entry_foreach(entry, set) {
230         key = udev_list_entry_get_name(entry);
231         if (!key)
232             continue;
233         value = udev_list_entry_get_value(entry);
234         if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
235             LOG_PROPERTY(path, key, value);
236             tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
237             if (!strcasecmp(tmp, "rules"))
238                 input_options =
239                     input_option_new(input_options, "xkb_rules", value);
240             else if (!strcasecmp(tmp, "layout"))
241                 input_options =
242                     input_option_new(input_options, "xkb_layout", value);
243             else if (!strcasecmp(tmp, "variant"))
244                 input_options =
245                     input_option_new(input_options, "xkb_variant", value);
246             else if (!strcasecmp(tmp, "model"))
247                 input_options =
248                     input_option_new(input_options, "xkb_model", value);
249             else if (!strcasecmp(tmp, "options"))
250                 input_options =
251                     input_option_new(input_options, "xkb_options", value);
252         }
253         else if (!strcmp(key, "ID_VENDOR")) {
254             LOG_PROPERTY(path, key, value);
255             attrs.vendor = strdup(value);
256         } else if (!strncmp(key, "ID_INPUT_", 9)) {
257             const struct pfmap {
258                 const char *property;
259                 unsigned int flag;
260             } map[] = {
261                 { "ID_INPUT_KEY", ATTR_KEY },
262                 { "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
263                 { "ID_INPUT_MOUSE", ATTR_POINTER },
264                 { "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
265                 { "ID_INPUT_TABLET", ATTR_TABLET },
266                 { "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
267                 { "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
268                 { "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
269                 { NULL, 0 },
270             };
271 
272             /* Anything but the literal string "0" is considered a
273              * boolean true. The empty string isn't a thing with udev
274              * properties anyway */
275             if (value && strcmp(value, "0")) {
276                 const struct pfmap *m = map;
277 
278                 while (m->property != NULL) {
279                     if (!strcmp(m->property, key)) {
280                         LOG_PROPERTY(path, key, value);
281                         attrs.flags |= m->flag;
282                     }
283                     m++;
284                 }
285             }
286         }
287     }
288 
289     if (attrs.flags & (ATTR_KEY | ATTR_KEYBOARD)) {
290         if (!feature_present("evdev_support"))
291             input_options = input_option_new(input_options, "driver", "kbd");
292     } else if (attrs.flags & ATTR_POINTER) {
293         if (strstr(path, "vbox"))
294             input_options = input_option_new(input_options, "driver", "vboxmouse");
295         else {
296             if (!feature_present("evdev_support"))
297                 input_options = input_option_new(input_options, "driver", "mouse");
298         }
299     }
300 
301     input_options = input_option_new(input_options, "config_info", config_info);
302 
303     /* Default setting needed for non-seat0 seats */
304     if (ServerIsNotSeat0())
305         input_options = input_option_new(input_options, "GrabDevice", "on");
306 
307     LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
308                name, path);
309     rc = NewInputDeviceRequest(input_options, &attrs, &dev);
310     if (rc != Success)
311         goto unwind;
312 
313  unwind:
314     free(config_info);
315     input_option_free_list(&input_options);
316 
317     free(attrs.usb_id);
318     free(attrs.pnp_id);
319     free(attrs.product);
320     free(attrs.device);
321     free(attrs.vendor);
322     if (attrs.tags) {
323         char **tag = attrs.tags;
324 
325         while (*tag) {
326             free(*tag);
327             tag++;
328         }
329         free(attrs.tags);
330     }
331 
332     return;
333 }
334 
335 static void
device_removed(struct udev_device * device)336 device_removed(struct udev_device *device)
337 {
338     char *value;
339     const char *syspath = udev_device_get_syspath(device);
340 
341 #ifdef CONFIG_UDEV_KMS
342     if (!strcmp(udev_device_get_subsystem(device), "drm")) {
343         const char *sysname = udev_device_get_sysname(device);
344         const char *path = udev_device_get_devnode(device);
345         dev_t devnum = udev_device_get_devnum(device);
346 
347         if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
348             return;
349 
350         LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
351                    syspath, path);
352         config_udev_odev_setup_attribs(path, syspath, major(devnum),
353                                        minor(devnum), DeleteGPUDeviceRequest);
354         /* Retry vtenter after a drm node removal */
355         systemd_logind_vtenter();
356         return;
357     }
358 #endif
359 
360     if (asprintf(&value, "udev:%s", syspath) == -1)
361         return;
362 
363     remove_devices("udev", value);
364 
365     free(value);
366 }
367 
368 static void
socket_handler(int fd,int ready,void * data)369 socket_handler(int fd, int ready, void *data)
370 {
371     struct udev_device *udev_device;
372     const char *action;
373 
374     input_lock();
375     udev_device = udev_monitor_receive_device(udev_monitor);
376     if (!udev_device) {
377         input_unlock();
378         return;
379     }
380     action = udev_device_get_action(udev_device);
381     if (action) {
382         if (!strcmp(action, "add")) {
383             device_removed(udev_device);
384             device_added(udev_device);
385         } else if (!strcmp(action, "change")) {
386             /* ignore change for the drm devices */
387             if (strcmp(udev_device_get_subsystem(udev_device), "drm")) {
388                 device_removed(udev_device);
389                 device_added(udev_device);
390             }
391         }
392         else if (!strcmp(action, "remove"))
393             device_removed(udev_device);
394     }
395     udev_device_unref(udev_device);
396     input_unlock();
397 }
398 
399 int
config_udev_pre_init(void)400 config_udev_pre_init(void)
401 {
402     struct udev *udev;
403 
404     udev = udev_new();
405     if (!udev)
406         return 0;
407 
408     udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
409     if (!udev_monitor)
410         return 0;
411 
412     udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
413                                                     NULL);
414     /* For Wacom serial devices */
415     udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
416 #ifdef CONFIG_UDEV_KMS
417     /* For output GPU devices */
418     udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
419 #endif
420 
421 #ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
422     if (ServerIsNotSeat0())
423         udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
424 #endif
425     if (udev_monitor_enable_receiving(udev_monitor)) {
426         ErrorF("config/udev: failed to bind the udev monitor\n");
427         return 0;
428     }
429     return 1;
430 }
431 
432 int
config_udev_init(void)433 config_udev_init(void)
434 {
435     struct udev *udev;
436     struct udev_enumerate *enumerate;
437     struct udev_list_entry *devices, *device;
438 
439     udev = udev_monitor_get_udev(udev_monitor);
440     enumerate = udev_enumerate_new(udev);
441     if (!enumerate)
442         return 0;
443 
444     udev_enumerate_add_match_subsystem(enumerate, "input");
445     udev_enumerate_add_match_subsystem(enumerate, "tty");
446 #ifdef CONFIG_UDEV_KMS
447     udev_enumerate_add_match_subsystem(enumerate, "drm");
448 #endif
449 
450 #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
451     if (ServerIsNotSeat0())
452         udev_enumerate_add_match_tag(enumerate, SeatId);
453 #endif
454 
455     udev_enumerate_scan_devices(enumerate);
456     devices = udev_enumerate_get_list_entry(enumerate);
457     udev_list_entry_foreach(device, devices) {
458         const char *syspath = udev_list_entry_get_name(device);
459         struct udev_device *udev_device =
460             udev_device_new_from_syspath(udev, syspath);
461 
462         /* Device might be gone by the time we try to open it */
463         if (!udev_device)
464             continue;
465 
466         device_added(udev_device);
467         udev_device_unref(udev_device);
468     }
469     udev_enumerate_unref(enumerate);
470 
471     SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
472 
473     return 1;
474 }
475 
476 void
config_udev_fini(void)477 config_udev_fini(void)
478 {
479     struct udev *udev;
480 
481     if (!udev_monitor)
482         return;
483 
484     udev = udev_monitor_get_udev(udev_monitor);
485 
486     RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
487     udev_monitor_unref(udev_monitor);
488     udev_monitor = NULL;
489     udev_unref(udev);
490 }
491 
492 #ifdef CONFIG_UDEV_KMS
493 
494 static void
config_udev_odev_setup_attribs(const char * path,const char * syspath,int major,int minor,config_odev_probe_proc_ptr probe_callback)495 config_udev_odev_setup_attribs(const char *path, const char *syspath,
496                                int major, int minor,
497                                config_odev_probe_proc_ptr probe_callback)
498 {
499     struct OdevAttributes *attribs = config_odev_allocate_attributes();
500 
501     attribs->path = XNFstrdup(path);
502     attribs->syspath = XNFstrdup(syspath);
503     attribs->major = major;
504     attribs->minor = minor;
505 
506     /* ownership of attribs is passed to probe layer */
507     probe_callback(attribs);
508 }
509 
510 void
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)511 config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
512 {
513     struct udev *udev;
514     struct udev_enumerate *enumerate;
515     struct udev_list_entry *devices, *device;
516 
517     udev = udev_monitor_get_udev(udev_monitor);
518     enumerate = udev_enumerate_new(udev);
519     if (!enumerate)
520         return;
521 
522     udev_enumerate_add_match_subsystem(enumerate, "drm");
523     udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
524 #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
525     if (ServerIsNotSeat0())
526         udev_enumerate_add_match_tag(enumerate, SeatId);
527 #endif
528     udev_enumerate_scan_devices(enumerate);
529     devices = udev_enumerate_get_list_entry(enumerate);
530     udev_list_entry_foreach(device, devices) {
531         const char *syspath = udev_list_entry_get_name(device);
532         struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
533         const char *path = udev_device_get_devnode(udev_device);
534         const char *sysname = udev_device_get_sysname(udev_device);
535         dev_t devnum = udev_device_get_devnum(udev_device);
536 
537         if (!path || !syspath)
538             goto no_probe;
539         else if (strcmp(udev_device_get_subsystem(udev_device), "drm") != 0)
540             goto no_probe;
541         else if (strncmp(sysname, "card", 4) != 0)
542             goto no_probe;
543         else if (!check_seat(udev_device))
544             goto no_probe;
545 
546         config_udev_odev_setup_attribs(path, syspath, major(devnum),
547                                        minor(devnum), probe_callback);
548     no_probe:
549         udev_device_unref(udev_device);
550     }
551     udev_enumerate_unref(enumerate);
552     return;
553 }
554 #endif
555 
556