1 /*
2 * Copyright © 2013 Red Hat, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #include "config.h"
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <linux/uinput.h>
28 #include <poll.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <time.h>
33 #include <unistd.h>
34
35 #include "libevdev-int.h"
36 #include "libevdev-uinput-int.h"
37 #include "libevdev-uinput.h"
38 #include "libevdev-util.h"
39 #include "libevdev.h"
40
41 #ifndef UINPUT_IOCTL_BASE
42 #define UINPUT_IOCTL_BASE 'U'
43 #endif
44
45 #ifndef UI_SET_PROPBIT
46 #define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
47 #endif
48
49 static struct libevdev_uinput *
alloc_uinput_device(const char * name)50 alloc_uinput_device(const char *name)
51 {
52 struct libevdev_uinput *uinput_dev;
53
54 uinput_dev = calloc(1, sizeof(struct libevdev_uinput));
55 if (uinput_dev) {
56 uinput_dev->name = strdup(name);
57 uinput_dev->fd = -1;
58 }
59
60 return uinput_dev;
61 }
62
63 static inline int
set_abs(const struct libevdev * dev,int fd,unsigned int code)64 set_abs(const struct libevdev *dev, int fd, unsigned int code)
65 {
66 const struct input_absinfo *abs = libevdev_get_abs_info(dev, code);
67 struct uinput_abs_setup abs_setup = {0};
68 int rc;
69
70 abs_setup.code = code;
71 abs_setup.absinfo = *abs;
72 rc = ioctl(fd, UI_ABS_SETUP, &abs_setup);
73 return rc;
74 }
75
76 static int
set_evbits(const struct libevdev * dev,int fd,struct uinput_user_dev * uidev)77 set_evbits(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev)
78 {
79 int rc = 0;
80 unsigned int type;
81
82 for (type = 0; type < EV_CNT; type++) {
83 unsigned int code;
84 int max;
85 int uinput_bit;
86 const unsigned long *mask;
87
88 if (!libevdev_has_event_type(dev, type))
89 continue;
90
91 rc = ioctl(fd, UI_SET_EVBIT, type);
92 if (rc == -1)
93 break;
94
95 /* uinput can't set EV_REP */
96 if (type == EV_REP)
97 continue;
98
99 max = type_to_mask_const(dev, type, &mask);
100 if (max == -1)
101 continue;
102
103 switch(type) {
104 case EV_KEY: uinput_bit = UI_SET_KEYBIT; break;
105 case EV_REL: uinput_bit = UI_SET_RELBIT; break;
106 case EV_ABS: uinput_bit = UI_SET_ABSBIT; break;
107 case EV_MSC: uinput_bit = UI_SET_MSCBIT; break;
108 case EV_LED: uinput_bit = UI_SET_LEDBIT; break;
109 case EV_SND: uinput_bit = UI_SET_SNDBIT; break;
110 case EV_FF: uinput_bit = UI_SET_FFBIT; break;
111 case EV_SW: uinput_bit = UI_SET_SWBIT; break;
112 default:
113 rc = -1;
114 errno = EINVAL;
115 goto out;
116 }
117
118 for (code = 0; code <= (unsigned int)max; code++) {
119 if (!libevdev_has_event_code(dev, type, code))
120 continue;
121
122 rc = ioctl(fd, uinput_bit, code);
123 if (rc == -1)
124 goto out;
125
126 if (type == EV_ABS) {
127 if (uidev == NULL) {
128 rc = set_abs(dev, fd, code);
129 if (rc != 0)
130 goto out;
131 } else {
132 const struct input_absinfo *abs =
133 libevdev_get_abs_info(dev, code);
134
135 uidev->absmin[code] = abs->minimum;
136 uidev->absmax[code] = abs->maximum;
137 uidev->absfuzz[code] = abs->fuzz;
138 uidev->absflat[code] = abs->flat;
139 /* uinput has no resolution in the
140 * device struct */
141 }
142 }
143 }
144
145 }
146
147 out:
148 return rc;
149 }
150
151 static int
set_props(const struct libevdev * dev,int fd)152 set_props(const struct libevdev *dev, int fd)
153 {
154 unsigned int prop;
155 int rc = 0;
156
157 for (prop = 0; prop <= INPUT_PROP_MAX; prop++) {
158 if (!libevdev_has_property(dev, prop))
159 continue;
160
161 rc = ioctl(fd, UI_SET_PROPBIT, prop);
162 if (rc == -1) {
163 /* If UI_SET_PROPBIT is not supported, treat -EINVAL
164 * as success. The kernel only sends -EINVAL for an
165 * invalid ioctl, invalid INPUT_PROP_MAX or if the
166 * ioctl is called on an already created device. The
167 * last two can't happen here.
168 */
169 if (errno == EINVAL)
170 rc = 0;
171 break;
172 }
173 }
174 return rc;
175 }
176
177 LIBEVDEV_EXPORT int
libevdev_uinput_get_fd(const struct libevdev_uinput * uinput_dev)178 libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev)
179 {
180 return uinput_dev->fd;
181 }
182
183 #ifdef __FreeBSD__
184 /*
185 * FreeBSD does not have anything similar to sysfs.
186 * Set libevdev_uinput->syspath to NULL unconditionally.
187 * Look up the device nodes directly instead of via sysfs, as this matches what
188 * is returned by the UI_GET_SYSNAME ioctl() on FreeBSD.
189 */
190 static int
fetch_syspath_and_devnode(struct libevdev_uinput * uinput_dev)191 fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
192 {
193 #define DEV_INPUT_DIR "/dev/input/"
194 int rc;
195 char buf[sizeof(DEV_INPUT_DIR) + 64] = DEV_INPUT_DIR;
196
197 rc = ioctl(uinput_dev->fd,
198 UI_GET_SYSNAME(sizeof(buf) - strlen(DEV_INPUT_DIR)),
199 &buf[strlen(DEV_INPUT_DIR)]);
200 if (rc == -1)
201 return -1;
202
203 uinput_dev->syspath = NULL;
204 uinput_dev->devnode = strdup(buf);
205
206 return 0;
207 #undef DEV_INPUT_DIR
208 }
209
210 #else /* !__FreeBSD__ */
211
is_event_device(const struct dirent * dent)212 static int is_event_device(const struct dirent *dent) {
213 return strncmp("event", dent->d_name, 5) == 0;
214 }
215
216 static char *
fetch_device_node(const char * path)217 fetch_device_node(const char *path)
218 {
219 char *devnode = NULL;
220 struct dirent **namelist;
221 int ndev, i;
222
223 ndev = scandir(path, &namelist, is_event_device, alphasort);
224 if (ndev <= 0)
225 return NULL;
226
227 /* ndev should only ever be 1 */
228
229 for (i = 0; i < ndev; i++) {
230 if (!devnode && asprintf(&devnode, "/dev/input/%s", namelist[i]->d_name) == -1)
231 devnode = NULL;
232 free(namelist[i]);
233 }
234
235 free(namelist);
236
237 return devnode;
238 }
239
is_input_device(const struct dirent * dent)240 static int is_input_device(const struct dirent *dent) {
241 return strncmp("input", dent->d_name, 5) == 0;
242 }
243
244 static int
fetch_syspath_and_devnode(struct libevdev_uinput * uinput_dev)245 fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
246 {
247 #define SYS_INPUT_DIR "/sys/devices/virtual/input/"
248 struct dirent **namelist;
249 int ndev, i;
250 int rc;
251 char buf[sizeof(SYS_INPUT_DIR) + 64] = SYS_INPUT_DIR;
252
253 rc = ioctl(uinput_dev->fd,
254 UI_GET_SYSNAME(sizeof(buf) - strlen(SYS_INPUT_DIR)),
255 &buf[strlen(SYS_INPUT_DIR)]);
256 if (rc != -1) {
257 uinput_dev->syspath = strdup(buf);
258 uinput_dev->devnode = fetch_device_node(buf);
259 return 0;
260 }
261
262 ndev = scandir(SYS_INPUT_DIR, &namelist, is_input_device, alphasort);
263 if (ndev <= 0)
264 return -1;
265
266 for (i = 0; i < ndev; i++) {
267 int fd, len;
268 struct stat st;
269
270 rc = snprintf(buf, sizeof(buf), "%s%s/name",
271 SYS_INPUT_DIR,
272 namelist[i]->d_name);
273 if (rc < 0 || (size_t)rc >= sizeof(buf)) {
274 continue;
275 }
276
277 /* created within time frame */
278 fd = open(buf, O_RDONLY);
279 if (fd < 0)
280 continue;
281
282 /* created before UI_DEV_CREATE, or after it finished */
283 if (fstat(fd, &st) == -1 ||
284 st.st_ctime < uinput_dev->ctime[0] ||
285 st.st_ctime > uinput_dev->ctime[1]) {
286 close(fd);
287 continue;
288 }
289
290 len = read(fd, buf, sizeof(buf));
291 close(fd);
292 if (len <= 0)
293 continue;
294
295 buf[len - 1] = '\0'; /* file contains \n */
296 if (strcmp(buf, uinput_dev->name) == 0) {
297 if (uinput_dev->syspath) {
298 /* FIXME: could descend into bit comparison here */
299 log_info(NULL, "multiple identical devices found. syspath is unreliable\n");
300 break;
301 }
302
303 rc = snprintf(buf, sizeof(buf), "%s%s",
304 SYS_INPUT_DIR,
305 namelist[i]->d_name);
306
307 if (rc < 0 || (size_t)rc >= sizeof(buf)) {
308 log_error(NULL, "Invalid syspath, syspath is unreliable\n");
309 break;
310 }
311
312 uinput_dev->syspath = strdup(buf);
313 uinput_dev->devnode = fetch_device_node(buf);
314 }
315 }
316
317 for (i = 0; i < ndev; i++)
318 free(namelist[i]);
319 free(namelist);
320
321 return uinput_dev->devnode ? 0 : -1;
322 #undef SYS_INPUT_DIR
323 }
324 #endif /* __FreeBSD__*/
325
326 static int
uinput_create_write(const struct libevdev * dev,int fd)327 uinput_create_write(const struct libevdev *dev, int fd)
328 {
329 int rc;
330 struct uinput_user_dev uidev;
331
332 memset(&uidev, 0, sizeof(uidev));
333
334 strncpy(uidev.name, libevdev_get_name(dev), UINPUT_MAX_NAME_SIZE - 1);
335 uidev.id.vendor = libevdev_get_id_vendor(dev);
336 uidev.id.product = libevdev_get_id_product(dev);
337 uidev.id.bustype = libevdev_get_id_bustype(dev);
338 uidev.id.version = libevdev_get_id_version(dev);
339
340 if (set_evbits(dev, fd, &uidev) != 0)
341 goto error;
342 if (set_props(dev, fd) != 0)
343 goto error;
344
345 rc = write(fd, &uidev, sizeof(uidev));
346 if (rc < 0) {
347 goto error;
348 } else if ((size_t)rc < sizeof(uidev)) {
349 errno = EINVAL;
350 goto error;
351 }
352
353 errno = 0;
354
355 error:
356 return -errno;
357 }
358
359 static int
uinput_create_DEV_SETUP(const struct libevdev * dev,int fd,struct libevdev_uinput * new_device)360 uinput_create_DEV_SETUP(const struct libevdev *dev, int fd,
361 struct libevdev_uinput *new_device)
362 {
363 int rc;
364 struct uinput_setup setup;
365
366 if (set_evbits(dev, fd, NULL) != 0)
367 goto error;
368 if (set_props(dev, fd) != 0)
369 goto error;
370
371 memset(&setup, 0, sizeof(setup));
372 strncpy(setup.name, libevdev_get_name(dev), UINPUT_MAX_NAME_SIZE - 1);
373 setup.id.vendor = libevdev_get_id_vendor(dev);
374 setup.id.product = libevdev_get_id_product(dev);
375 setup.id.bustype = libevdev_get_id_bustype(dev);
376 setup.id.version = libevdev_get_id_version(dev);
377 setup.ff_effects_max = libevdev_has_event_type(dev, EV_FF) ? 10 : 0;
378
379 rc = ioctl(fd, UI_DEV_SETUP, &setup);
380 if (rc == 0)
381 errno = 0;
382 error:
383 return -errno;
384 }
385
386 LIBEVDEV_EXPORT int
libevdev_uinput_create_from_device(const struct libevdev * dev,int fd,struct libevdev_uinput ** uinput_dev)387 libevdev_uinput_create_from_device(const struct libevdev *dev, int fd, struct libevdev_uinput** uinput_dev)
388 {
389 int rc;
390 struct libevdev_uinput *new_device;
391 int close_fd_on_error = (fd == LIBEVDEV_UINPUT_OPEN_MANAGED);
392 unsigned int uinput_version = 0;
393
394 new_device = alloc_uinput_device(libevdev_get_name(dev));
395 if (!new_device)
396 return -ENOMEM;
397
398 if (fd == LIBEVDEV_UINPUT_OPEN_MANAGED) {
399 fd = open("/dev/uinput", O_RDWR|O_CLOEXEC);
400 if (fd < 0)
401 goto error;
402
403 new_device->fd_is_managed = 1;
404 } else if (fd < 0) {
405 log_bug(NULL, "Invalid fd %d\n", fd);
406 errno = EBADF;
407 goto error;
408 }
409
410 if (ioctl(fd, UI_GET_VERSION, &uinput_version) == 0 &&
411 uinput_version >= 5)
412 rc = uinput_create_DEV_SETUP(dev, fd, new_device);
413 else
414 rc = uinput_create_write(dev, fd);
415
416 if (rc != 0)
417 goto error;
418
419 /* ctime notes time before/after ioctl to help us filter out devices
420 when traversing /sys/devices/virtual/input to find the device
421 node.
422
423 this is in seconds, so ctime[0]/[1] will almost always be
424 identical but /sys doesn't give us sub-second ctime so...
425 */
426 new_device->ctime[0] = time(NULL);
427
428 rc = ioctl(fd, UI_DEV_CREATE, NULL);
429 if (rc == -1)
430 goto error;
431
432 new_device->ctime[1] = time(NULL);
433 new_device->fd = fd;
434
435 if (fetch_syspath_and_devnode(new_device) == -1) {
436 log_error(NULL, "unable to fetch syspath or device node.\n");
437 errno = ENODEV;
438 goto error;
439 }
440
441 *uinput_dev = new_device;
442
443 return 0;
444
445 error:
446 rc = -errno;
447 libevdev_uinput_destroy(new_device);
448 if (fd != -1 && close_fd_on_error)
449 close(fd);
450 return rc;
451 }
452
453 LIBEVDEV_EXPORT void
libevdev_uinput_destroy(struct libevdev_uinput * uinput_dev)454 libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev)
455 {
456 if (!uinput_dev)
457 return;
458
459 if (uinput_dev->fd >= 0) {
460 (void)ioctl(uinput_dev->fd, UI_DEV_DESTROY, NULL);
461 if (uinput_dev->fd_is_managed)
462 close(uinput_dev->fd);
463 }
464 free(uinput_dev->syspath);
465 free(uinput_dev->devnode);
466 free(uinput_dev->name);
467 free(uinput_dev);
468 }
469
470 LIBEVDEV_EXPORT const char*
libevdev_uinput_get_syspath(struct libevdev_uinput * uinput_dev)471 libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev)
472 {
473 return uinput_dev->syspath;
474 }
475
476 LIBEVDEV_EXPORT const char*
libevdev_uinput_get_devnode(struct libevdev_uinput * uinput_dev)477 libevdev_uinput_get_devnode(struct libevdev_uinput *uinput_dev)
478 {
479 return uinput_dev->devnode;
480 }
481
482 LIBEVDEV_EXPORT int
libevdev_uinput_write_event(const struct libevdev_uinput * uinput_dev,unsigned int type,unsigned int code,int value)483 libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev,
484 unsigned int type,
485 unsigned int code,
486 int value)
487 {
488 #ifndef __MUSL__
489 struct input_event ev = { {0,0}, type, code, value };
490 #else
491 struct input_event ev = { type, code, value };
492 #endif
493 int fd = libevdev_uinput_get_fd(uinput_dev);
494 int rc, max;
495
496 if (type > EV_MAX)
497 return -EINVAL;
498
499 max = libevdev_event_type_get_max(type);
500 if (max == -1 || code > (unsigned int)max)
501 return -EINVAL;
502
503 rc = write(fd, &ev, sizeof(ev));
504
505 return rc < 0 ? -errno : 0;
506 }
507