• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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