• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018 Red Hat, Inc.
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 
24 #include "config.h"
25 
26 #include <errno.h>
27 #include <sys/epoll.h>
28 #include <inttypes.h>
29 #include <linux/input.h>
30 #include <libevdev/libevdev.h>
31 #include <libudev.h>
32 #include <sys/signalfd.h>
33 #include <sys/timerfd.h>
34 #include <sys/utsname.h>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <poll.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <stdbool.h>
44 #include <time.h>
45 
46 #include "libinput-versionsort.h"
47 #include "libinput-version.h"
48 #include "libinput-git-version.h"
49 #include "shared.h"
50 #include "builddir.h"
51 #include "util-list.h"
52 #include "util-time.h"
53 #include "util-input-event.h"
54 #include "util-macros.h"
55 
56 static const int FILE_VERSION_NUMBER = 1;
57 
58 /* Indentation levels for the various data nodes */
59 enum indent {
60 	I_NONE = 0,
61 	I_TOPLEVEL = 0,
62 	I_LIBINPUT = 2,			/* nodes inside libinput: */
63 	I_SYSTEM = 0,			/* nodes inside system:   */
64 	I_DEVICE = 2,			/* nodes inside devices:  */
65 	I_EVDEV = 4,			/* nodes inside evdev:    */
66 	I_EVDEV_DATA = 6,		/* nodes below evdev:	  */
67 	I_UDEV = 4,			/* nodes inside udev:     */
68 	I_UDEV_DATA = 6,		/* nodes below udev:      */
69 	I_QUIRKS = 4,			/* nodes inside quirks:	  */
70 	I_LIBINPUTDEV = 4,		/* nodes inside libinput: (the
71 					   device description */
72 	I_EVENTTYPE = 4,		/* event type (evdev:, libinput:,
73 					   hidraw:) */
74 	I_EVENT = 6,			/* event data */
75 };
76 
77 struct record_device {
78 	struct record_context *ctx;
79 	struct list link;
80 	char *devnode;		/* device node of the source device */
81 	struct libevdev *evdev;
82 	struct libevdev *evdev_prev; /* previous value, used for EV_ABS
83 					deltas */
84 	struct libinput_device *device;
85 	struct list hidraw_devices;
86 
87 	struct {
88 		bool is_touch_device;
89 		uint16_t slot_state;
90 		uint16_t last_slot_state;
91 	} touch;
92 
93 	FILE *fp;
94 };
95 
96 struct hidraw {
97 	struct list link;
98 	struct record_device *device;
99 	int fd;
100 	char *name;
101 };
102 
103 struct record_context {
104 	int timeout;
105 	bool show_keycodes;
106 
107 	uint64_t offset;
108 
109 	/* The first device to be added */
110 	struct record_device *first_device;
111 
112 	struct list devices;
113 	int ndevices;
114 
115 	struct {
116 		char *name;		 /* file name given on cmdline */
117 		char *name_with_suffix;  /* full file name with suffix */
118 	} output_file;
119 
120 	struct libinput *libinput;
121 
122 	int epoll_fd;
123 	struct list sources;
124 
125 	struct {
126 		bool had_events_since_last_time;
127 		bool skipped_timer_print;
128 	} timestamps;
129 
130 	bool had_events;
131 	bool stop;
132 };
133 
134 #define resize(array_, sz_) \
135 { \
136 	size_t new_size = (sz_) + 1000; \
137 	void *tmp = realloc((array_), new_size * sizeof(*(array_))); \
138 	assert(tmp); \
139 	(array_)  = tmp; \
140 	(sz_) = new_size; \
141 }
142 
143 typedef void (*source_dispatch_t)(struct record_context *ctx,
144 				  int fd,
145 				  void *user_data);
146 
147 struct source {
148 	source_dispatch_t dispatch;
149 	void *user_data;
150 	int fd;
151 	struct list link;
152 };
153 
154 static bool
obfuscate_keycode(struct input_event * ev)155 obfuscate_keycode(struct input_event *ev)
156 {
157 	switch (ev->type) {
158 	case EV_KEY:
159 		switch (ev->code) {
160 		case KEY_ESC:
161 		case KEY_TAB:
162 		case KEY_ENTER:
163 		case KEY_LEFTCTRL:
164 			break;
165 		default:
166 			if ((ev->code > KEY_ESC && ev->code < KEY_CAPSLOCK) ||
167 			    (ev->code >= KEY_KP7 && ev->code <= KEY_KPDOT)) {
168 				ev->code = KEY_A;
169 				return true;
170 			}
171 		}
172 		break;
173 	case EV_MSC:
174 		if (ev->code == MSC_SCAN) {
175 			ev->value = 30; /* KEY_A scancode */
176 			return true;
177 		}
178 		break;
179 	}
180 
181 	return false;
182 }
183 
184 /**
185  * Indented dprintf, indentation is in the context
186  */
187 LIBINPUT_ATTRIBUTE_PRINTF(3, 4)
188 static void
iprintf(FILE * fp,enum indent indent,const char * format,...)189 iprintf(FILE *fp,
190 	enum indent indent,
191 	const char *format, ...)
192 {
193 	va_list args;
194 	char fmt[1024];
195 	static const char space[] = "                                     ";
196 	static const size_t len = sizeof(space);
197 	int rc;
198 
199 	assert(indent < len);
200 	assert(strlen(format) >= 1);
201 
202 	/* Special case: if we're printing a new list item, we want less
203 	 * indentation because the '- ' takes up one level of indentation
204 	 *
205 	 * This is only needed because I don't want to deal with open/close
206 	 * lists statements.
207 	 */
208 	if (format[0] == '-' && indent > 0)
209 		indent -= 2;
210 
211 	snprintf(fmt, sizeof(fmt), "%s%s", &space[len - indent - 1], format);
212 	va_start(args, format);
213 #pragma GCC diagnostic push
214 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
215 	rc = vfprintf(fp, fmt, args);
216 #pragma GCC diagnostic pop
217 	va_end(args);
218 
219 	assert(rc != -1 && (unsigned int)rc > indent);
220 }
221 
222 static uint64_t
time_offset(struct record_context * ctx,uint64_t time)223 time_offset(struct record_context *ctx, uint64_t time)
224 {
225 	return ctx->offset ? time - ctx->offset : 0;
226 }
227 
228 static void
print_evdev_event(struct record_device * dev,struct input_event * ev)229 print_evdev_event(struct record_device *dev,
230 		  struct input_event *ev)
231 {
232 	const char *tname, *cname;
233 	bool was_modified = false;
234 	char desc[1024];
235 	uint64_t time = input_event_time(ev) - dev->ctx->offset;
236 
237 	input_event_set_time(ev, time);
238 
239 	/* Don't leak passwords unless the user wants to */
240 	if (!dev->ctx->show_keycodes)
241 		was_modified = obfuscate_keycode(ev);
242 
243 	tname = libevdev_event_type_get_name(ev->type);
244 	cname = libevdev_event_code_get_name(ev->type, ev->code);
245 
246 	if (ev->type == EV_SYN && ev->code == SYN_MT_REPORT) {
247 		snprintf(desc,
248 			 sizeof(desc),
249 			 "++++++++++++ %s (%d) ++++++++++",
250 			 cname,
251 			 ev->value);
252 	} else if (ev->type == EV_SYN) {
253 		static unsigned long last_ms = 0;
254 		unsigned long time, dt;
255 
256 		time = us2ms(input_event_time(ev));
257 		dt = time - last_ms;
258 		last_ms = time;
259 
260 		snprintf(desc,
261 			 sizeof(desc),
262 			"------------ %s (%d) ---------- %+ldms",
263 			cname,
264 			ev->value,
265 			dt);
266 	} else if (ev->type == EV_ABS) {
267 		int oldval = 0;
268 		enum { DELTA, SLOT_DELTA, NO_DELTA } want = DELTA;
269 		int delta = 0;
270 
271 		/* We want to print deltas for abs axes but there are a few
272 		 * that we don't care about for actual deltas because
273 		 * they're meaningless.
274 		 *
275 		 * Also, any slotted axis needs to be printed per slot
276 		 */
277 		switch (ev->code) {
278 		case ABS_MT_SLOT:
279 			libevdev_set_event_value(dev->evdev_prev,
280 						 ev->type,
281 						 ev->code,
282 						 ev->value);
283 			want = NO_DELTA;
284 			break;
285 		case ABS_MT_TRACKING_ID:
286 		case ABS_MT_BLOB_ID:
287 			want = NO_DELTA;
288 			break;
289 		case ABS_MT_TOUCH_MAJOR ... ABS_MT_POSITION_Y:
290 		case ABS_MT_PRESSURE ... ABS_MT_TOOL_Y:
291 			if (libevdev_get_num_slots(dev->evdev_prev) > 0)
292 				want = SLOT_DELTA;
293 			break;
294 		default:
295 			break;
296 		}
297 
298 		switch (want) {
299 		case DELTA:
300 			oldval = libevdev_get_event_value(dev->evdev_prev,
301 							  ev->type,
302 							  ev->code);
303 			libevdev_set_event_value(dev->evdev_prev,
304 						 ev->type,
305 						 ev->code,
306 						 ev->value);
307 			break;
308 		case SLOT_DELTA: {
309 			int slot = libevdev_get_current_slot(dev->evdev_prev);
310 			oldval = libevdev_get_slot_value(dev->evdev_prev,
311 							 slot,
312 							 ev->code);
313 			libevdev_set_slot_value(dev->evdev_prev,
314 						slot,
315 						ev->code,
316 						ev->value);
317 			break;
318 		}
319 		case NO_DELTA:
320 			break;
321 
322 		}
323 
324 		delta = ev->value - oldval;
325 
326 		switch (want) {
327 		case DELTA:
328 		case SLOT_DELTA:
329 			snprintf(desc,
330 				 sizeof(desc),
331 				 "%s / %-20s %6d (%+d)",
332 				 tname,
333 				 cname,
334 				 ev->value,
335 				 delta);
336 			break;
337 		case NO_DELTA:
338 			snprintf(desc,
339 				 sizeof(desc),
340 				 "%s / %-20s %6d",
341 				 tname,
342 				 cname,
343 				 ev->value);
344 			break;
345 		}
346 	} else {
347 		snprintf(desc,
348 			 sizeof(desc),
349 			 "%s / %-20s %6d%s",
350 			 tname,
351 			 cname,
352 			 ev->value,
353 			 was_modified ? " (obfuscated)" : "");
354 	}
355 
356 	iprintf(dev->fp,
357 		I_EVENT,
358 		"- [%3lu, %6u, %3d, %3d, %7d] # %s\n",
359 		ev->input_event_sec,
360 		(unsigned int)ev->input_event_usec,
361 		ev->type,
362 		ev->code,
363 		ev->value,
364 		desc);
365 }
366 
367 static bool
handle_evdev_frame(struct record_device * d)368 handle_evdev_frame(struct record_device *d)
369 {
370 	struct libevdev *evdev = d->evdev;
371 	struct input_event e;
372 
373 	if (libevdev_next_event(evdev, LIBEVDEV_READ_FLAG_NORMAL, &e) !=
374 		LIBEVDEV_READ_STATUS_SUCCESS)
375 		return false;
376 
377 	iprintf(d->fp, I_EVENTTYPE, "- evdev:\n");
378 	do {
379 
380 		if (d->ctx->offset == 0) {
381 			uint64_t time = input_event_time(&e);
382 			d->ctx->offset = time;
383 		}
384 
385 		print_evdev_event(d, &e);
386 
387 		if (d->touch.is_touch_device &&
388 		    e.type == EV_ABS &&
389 		    e.code == ABS_MT_TRACKING_ID) {
390 			unsigned int slot = libevdev_get_current_slot(evdev);
391 			assert(slot < sizeof(d->touch.slot_state) * 8);
392 
393 			if (e.value != -1)
394 				d->touch.slot_state |= 1 << slot;
395 			else
396 				d->touch.slot_state &= ~(1 << slot);
397 		}
398 
399 		if (e.type == EV_SYN && e.code == SYN_REPORT)
400 			break;
401 	} while (libevdev_next_event(evdev,
402 				     LIBEVDEV_READ_FLAG_NORMAL,
403 				     &e) == LIBEVDEV_READ_STATUS_SUCCESS);
404 
405 	if (d->touch.slot_state != d->touch.last_slot_state) {
406 		d->touch.last_slot_state = d->touch.slot_state;
407 		if (d->touch.slot_state == 0) {
408 			iprintf(d->fp,
409 				I_EVENT,
410 				 "                                 # Touch device in neutral state\n");
411 		}
412 	}
413 
414 	return true;
415 }
416 
417 static void
print_device_notify(struct record_device * dev,struct libinput_event * e)418 print_device_notify(struct record_device *dev, struct libinput_event *e)
419 {
420 	struct libinput_device *d = libinput_event_get_device(e);
421 	struct libinput_seat *seat = libinput_device_get_seat(d);
422 	const char *type = NULL;
423 
424 	switch(libinput_event_get_type(e)) {
425 	case LIBINPUT_EVENT_DEVICE_ADDED:
426 		type = "DEVICE_ADDED";
427 		break;
428 	case LIBINPUT_EVENT_DEVICE_REMOVED:
429 		type = "DEVICE_REMOVED";
430 		break;
431 	default:
432 		abort();
433 	}
434 
435 	iprintf(dev->fp,
436 		I_EVENT,
437 		"- {type: %s, seat: %5s, logical_seat: %7s}\n",
438 		type,
439 		libinput_seat_get_physical_name(seat),
440 		libinput_seat_get_logical_name(seat));
441 }
442 
443 static void
print_key_event(struct record_device * dev,struct libinput_event * e)444 print_key_event(struct record_device *dev, struct libinput_event *e)
445 {
446 	struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(e);
447 	enum libinput_key_state state;
448 	uint32_t key;
449 	uint64_t time;
450 	const char *type;
451 
452 	switch(libinput_event_get_type(e)) {
453 	case LIBINPUT_EVENT_KEYBOARD_KEY:
454 		type = "KEYBOARD_KEY";
455 		break;
456 	default:
457 		abort();
458 	}
459 
460 	time = time_offset(dev->ctx, libinput_event_keyboard_get_time_usec(k));
461 	state = libinput_event_keyboard_get_key_state(k);
462 
463 	key = libinput_event_keyboard_get_key(k);
464 	if (!dev->ctx->show_keycodes &&
465 	    (key >= KEY_ESC && key < KEY_ZENKAKUHANKAKU))
466 		key = -1;
467 
468 	iprintf(dev->fp,
469 		I_EVENT,
470 		"- {time: %ld.%06ld, type: %s, key: %d, state: %s}\n",
471 		(long)(time / (int)1e6),
472 		(long)(time % (int)1e6),
473 		type,
474 		key,
475 		state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released");
476 }
477 
478 static void
print_motion_event(struct record_device * dev,struct libinput_event * e)479 print_motion_event(struct record_device *dev, struct libinput_event *e)
480 {
481 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
482 	double x = libinput_event_pointer_get_dx(p),
483 	       y = libinput_event_pointer_get_dy(p);
484 	double uax = libinput_event_pointer_get_dx_unaccelerated(p),
485 	       uay = libinput_event_pointer_get_dy_unaccelerated(p);
486 	uint64_t time;
487 	const char *type;
488 
489 	switch(libinput_event_get_type(e)) {
490 	case LIBINPUT_EVENT_POINTER_MOTION:
491 		type = "POINTER_MOTION";
492 		break;
493 	default:
494 		abort();
495 	}
496 
497 	time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p));
498 	iprintf(dev->fp,
499 		I_EVENT,
500 		"- {time: %ld.%06ld, type: %s, delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n",
501 		(long)(time / (int)1e6),
502 		(long)(time % (int)1e6),
503 		type,
504 		x, y,
505 		uax, uay);
506 }
507 
508 static void
print_absmotion_event(struct record_device * dev,struct libinput_event * e)509 print_absmotion_event(struct record_device *dev, struct libinput_event *e)
510 {
511 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
512 	double x = libinput_event_pointer_get_absolute_x(p),
513 	       y = libinput_event_pointer_get_absolute_y(p);
514 	double tx = libinput_event_pointer_get_absolute_x_transformed(p, 100),
515 	       ty = libinput_event_pointer_get_absolute_y_transformed(p, 100);
516 	uint64_t time;
517 	const char *type;
518 
519 	switch(libinput_event_get_type(e)) {
520 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
521 		type = "POINTER_MOTION_ABSOLUTE";
522 		break;
523 	default:
524 		abort();
525 	}
526 
527 	time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p));
528 
529 	iprintf(dev->fp,
530 		I_EVENT,
531 		"- {time: %ld.%06ld, type: %s, point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n",
532 		(long)(time / (int)1e6),
533 		(long)(time % (int)1e6),
534 		type,
535 		x, y,
536 		tx, ty);
537 }
538 
539 static void
print_pointer_button_event(struct record_device * dev,struct libinput_event * e)540 print_pointer_button_event(struct record_device *dev, struct libinput_event *e)
541 {
542 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
543 	enum libinput_button_state state;
544 	int button;
545 	uint64_t time;
546 	const char *type;
547 
548 	switch(libinput_event_get_type(e)) {
549 	case LIBINPUT_EVENT_POINTER_BUTTON:
550 		type = "POINTER_BUTTON";
551 		break;
552 	default:
553 		abort();
554 	}
555 
556 	time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p));
557 	button = libinput_event_pointer_get_button(p);
558 	state = libinput_event_pointer_get_button_state(p);
559 
560 	iprintf(dev->fp,
561 		I_EVENT,
562 		"- {time: %ld.%06ld, type: %s, button: %d, state: %s, seat_count: %u}\n",
563 		(long)(time / (int)1e6),
564 		(long)(time % (int)1e6),
565 		type,
566 		button,
567 		state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released",
568 		libinput_event_pointer_get_seat_button_count(p));
569 }
570 
571 static void
print_pointer_axis_event(struct record_device * dev,struct libinput_event * e)572 print_pointer_axis_event(struct record_device *dev, struct libinput_event *e)
573 {
574 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(e);
575 	uint64_t time;
576 	const char *type, *source;
577 	double h = 0, v = 0;
578 	int hd = 0, vd = 0;
579 
580 	switch(libinput_event_get_type(e)) {
581 	case LIBINPUT_EVENT_POINTER_AXIS:
582 		type = "POINTER_AXIS";
583 		break;
584 	default:
585 		abort();
586 	}
587 
588 	time = time_offset(dev->ctx, libinput_event_pointer_get_time_usec(p));
589 	if (libinput_event_pointer_has_axis(p,
590 				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
591 		h = libinput_event_pointer_get_axis_value(p,
592 				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
593 		hd = libinput_event_pointer_get_axis_value_discrete(p,
594 				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
595 	}
596 	if (libinput_event_pointer_has_axis(p,
597 				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
598 		v = libinput_event_pointer_get_axis_value(p,
599 				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
600 		vd = libinput_event_pointer_get_axis_value_discrete(p,
601 				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
602 	}
603 	switch(libinput_event_pointer_get_axis_source(p)) {
604 	case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: source = "wheel"; break;
605 	case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: source = "finger"; break;
606 	case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: source = "continuous"; break;
607 	case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: source = "wheel-tilt"; break;
608 	default:
609 		source = "unknown";
610 		break;
611 	}
612 
613 	iprintf(dev->fp,
614 		I_EVENT,
615 		"- {time: %ld.%06ld, type: %s, axes: [%2.2f, %2.2f], discrete: [%d, %d], source: %s}\n",
616 		(long)(time / (int)1e6),
617 		(long)(time % (int)1e6),
618 		type,
619 		h, v,
620 		hd, vd,
621 		source);
622 }
623 
624 static void
print_touch_event(struct record_device * dev,struct libinput_event * e)625 print_touch_event(struct record_device *dev, struct libinput_event *e)
626 {
627 	enum libinput_event_type etype = libinput_event_get_type(e);
628 	struct libinput_event_touch *t = libinput_event_get_touch_event(e);
629 	const char *type;
630 	double x, y;
631 	double tx, ty;
632 	uint64_t time;
633 	int32_t slot, seat_slot;
634 
635 	switch(etype) {
636 	case LIBINPUT_EVENT_TOUCH_DOWN:
637 		type = "TOUCH_DOWN";
638 		break;
639 	case LIBINPUT_EVENT_TOUCH_UP:
640 		type = "TOUCH_UP";
641 		break;
642 	case LIBINPUT_EVENT_TOUCH_MOTION:
643 		type = "TOUCH_MOTION";
644 		break;
645 	case LIBINPUT_EVENT_TOUCH_CANCEL:
646 		type = "TOUCH_CANCEL";
647 		break;
648 	case LIBINPUT_EVENT_TOUCH_FRAME:
649 		type = "TOUCH_FRAME";
650 		break;
651 	default:
652 		abort();
653 	}
654 
655 	time = time_offset(dev->ctx, libinput_event_touch_get_time_usec(t));
656 
657 	if (etype != LIBINPUT_EVENT_TOUCH_FRAME) {
658 		slot = libinput_event_touch_get_slot(t);
659 		seat_slot = libinput_event_touch_get_seat_slot(t);
660 	}
661 
662 	switch (etype) {
663 	case LIBINPUT_EVENT_TOUCH_FRAME:
664 		iprintf(dev->fp,
665 			I_EVENT,
666 			"- {time: %ld.%06ld, type: %s}\n",
667 			(long)(time / (int)1e6),
668 			(long)(time % (int)1e6),
669 			type);
670 		break;
671 	case LIBINPUT_EVENT_TOUCH_DOWN:
672 	case LIBINPUT_EVENT_TOUCH_MOTION:
673 		x = libinput_event_touch_get_x(t);
674 		y = libinput_event_touch_get_y(t);
675 		tx = libinput_event_touch_get_x_transformed(t, 100);
676 		ty = libinput_event_touch_get_y_transformed(t, 100);
677 		iprintf(dev->fp,
678 			I_EVENT,
679 			"- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d, "
680 			"point: [%6.2f, %6.2f], transformed: [%6.2f, %6.2f]}\n",
681 			(long)(time / (int)1e6),
682 			(long)(time % (int)1e6),
683 			type,
684 			slot,
685 			seat_slot,
686 			x, y,
687 			tx, ty);
688 		break;
689 	case LIBINPUT_EVENT_TOUCH_UP:
690 	case LIBINPUT_EVENT_TOUCH_CANCEL:
691 		iprintf(dev->fp,
692 			I_EVENT,
693 			"- {time: %ld.%06ld, type: %s, slot: %d, seat_slot: %d}\n",
694 			(long)(time / (int)1e6),
695 			(long)(time % (int)1e6),
696 			type,
697 			slot,
698 			seat_slot);
699 		break;
700 	default:
701 		abort();
702 	}
703 }
704 
705 static void
print_gesture_event(struct record_device * dev,struct libinput_event * e)706 print_gesture_event(struct record_device *dev, struct libinput_event *e)
707 {
708 	enum libinput_event_type etype = libinput_event_get_type(e);
709 	struct libinput_event_gesture *g = libinput_event_get_gesture_event(e);
710 	const char *type;
711 	uint64_t time;
712 
713 	switch(etype) {
714 	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
715 		type = "GESTURE_PINCH_BEGIN";
716 		break;
717 	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
718 		type = "GESTURE_PINCH_UPDATE";
719 		break;
720 	case LIBINPUT_EVENT_GESTURE_PINCH_END:
721 		type = "GESTURE_PINCH_END";
722 		break;
723 	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
724 		type = "GESTURE_SWIPE_BEGIN";
725 		break;
726 	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
727 		type = "GESTURE_SWIPE_UPDATE";
728 		break;
729 	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
730 		type = "GESTURE_SWIPE_END";
731 		break;
732 	default:
733 		abort();
734 	}
735 
736 	time = time_offset(dev->ctx, libinput_event_gesture_get_time_usec(g));
737 
738 	switch (etype) {
739 	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
740 	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
741 	case LIBINPUT_EVENT_GESTURE_PINCH_END:
742 		iprintf(dev->fp,
743 			I_EVENT,
744 			"- {time: %ld.%06ld, type: %s, nfingers: %d, "
745 			"delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f], "
746 			"angle_delta: %6.2f, scale: %6.2f}\n",
747 			(long)(time / (int)1e6),
748 			(long)(time % (int)1e6),
749 			type,
750 			libinput_event_gesture_get_finger_count(g),
751 			libinput_event_gesture_get_dx(g),
752 			libinput_event_gesture_get_dy(g),
753 			libinput_event_gesture_get_dx_unaccelerated(g),
754 			libinput_event_gesture_get_dy_unaccelerated(g),
755 			libinput_event_gesture_get_angle_delta(g),
756 			libinput_event_gesture_get_scale(g)
757 		       );
758 		break;
759 	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
760 	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
761 	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
762 		iprintf(dev->fp,
763 			I_EVENT,
764 			"- {time: %ld.%06ld, type: %s, nfingers: %d, "
765 			"delta: [%6.2f, %6.2f], unaccel: [%6.2f, %6.2f]}\n",
766 			(long)(time / (int)1e6),
767 			(long)(time % (int)1e6),
768 			type,
769 			libinput_event_gesture_get_finger_count(g),
770 			libinput_event_gesture_get_dx(g),
771 			libinput_event_gesture_get_dy(g),
772 			libinput_event_gesture_get_dx_unaccelerated(g),
773 			libinput_event_gesture_get_dy_unaccelerated(g)
774 		       );
775 		break;
776 	default:
777 		abort();
778 	}
779 }
780 
781 static char *
buffer_tablet_axes(struct libinput_event_tablet_tool * t)782 buffer_tablet_axes(struct libinput_event_tablet_tool *t)
783 {
784 	const int MAX_AXES = 10;
785 	struct libinput_tablet_tool *tool;
786 	char *s = NULL;
787 	int idx = 0;
788 	int len;
789 	double x, y;
790 	char **strv;
791 
792 	tool = libinput_event_tablet_tool_get_tool(t);
793 
794 	strv = zalloc(MAX_AXES * sizeof *strv);
795 
796 	x = libinput_event_tablet_tool_get_x(t);
797 	y = libinput_event_tablet_tool_get_y(t);
798 	len = xasprintf(&strv[idx++], "point: [%.2f, %.2f]", x, y);
799 	if (len <= 0)
800 		goto out;
801 
802 	if (libinput_tablet_tool_has_tilt(tool)) {
803 		x = libinput_event_tablet_tool_get_tilt_x(t);
804 		y = libinput_event_tablet_tool_get_tilt_y(t);
805 		len = xasprintf(&strv[idx++], "tilt: [%.2f, %.2f]", x, y);
806 		if (len <= 0)
807 			goto out;
808 	}
809 
810 	if (libinput_tablet_tool_has_distance(tool) ||
811 	    libinput_tablet_tool_has_pressure(tool)) {
812 		double dist, pressure;
813 
814 		dist = libinput_event_tablet_tool_get_distance(t);
815 		pressure = libinput_event_tablet_tool_get_pressure(t);
816 		if (dist)
817 			len = xasprintf(&strv[idx++], "distance: %.2f", dist);
818 		else
819 			len = xasprintf(&strv[idx++], "pressure: %.2f", pressure);
820 		if (len <= 0)
821 			goto out;
822 	}
823 
824 	if (libinput_tablet_tool_has_rotation(tool)) {
825 		double rotation;
826 
827 		rotation = libinput_event_tablet_tool_get_rotation(t);
828 		len = xasprintf(&strv[idx++], "rotation: %.2f", rotation);
829 		if (len <= 0)
830 			goto out;
831 	}
832 
833 	if (libinput_tablet_tool_has_slider(tool)) {
834 		double slider;
835 
836 		slider = libinput_event_tablet_tool_get_slider_position(t);
837 		len = xasprintf(&strv[idx++], "slider: %.2f", slider);
838 		if (len <= 0)
839 			goto out;
840 
841 	}
842 
843 	if (libinput_tablet_tool_has_wheel(tool)) {
844 		double wheel;
845 		int delta;
846 
847 		wheel = libinput_event_tablet_tool_get_wheel_delta(t);
848 		len = xasprintf(&strv[idx++], "wheel: %.2f", wheel);
849 		if (len <= 0)
850 			goto out;
851 
852 		delta = libinput_event_tablet_tool_get_wheel_delta_discrete(t);
853 		len = xasprintf(&strv[idx++], "wheel-discrete: %d", delta);
854 		if (len <= 0)
855 			goto out;
856 	}
857 
858 	assert(idx < MAX_AXES);
859 
860 	s = strv_join(strv, ", ");
861 out:
862 	strv_free(strv);
863 	return s;
864 }
865 
866 static void
print_tablet_tool_proximity_event(struct record_device * dev,struct libinput_event * e)867 print_tablet_tool_proximity_event(struct record_device *dev, struct libinput_event *e)
868 {
869 	struct libinput_event_tablet_tool *t =
870 		libinput_event_get_tablet_tool_event(e);
871 	struct libinput_tablet_tool *tool =
872 		libinput_event_tablet_tool_get_tool(t);
873 	uint64_t time;
874 	const char *type, *tool_type;
875 	char *axes;
876 	char caps[10] = {0};
877 	enum libinput_tablet_tool_proximity_state prox;
878 	size_t idx;
879 
880 	switch (libinput_event_get_type(e)) {
881 	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
882 		type = "TABLET_TOOL_PROXIMITY";
883 		break;
884 	default:
885 		abort();
886 	}
887 
888 	switch (libinput_tablet_tool_get_type(tool)) {
889 	case LIBINPUT_TABLET_TOOL_TYPE_PEN:
890 		tool_type = "pen";
891 		break;
892 	case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
893 		tool_type = "eraser";
894 		break;
895 	case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
896 		tool_type = "brush";
897 		break;
898 	case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
899 		tool_type = "brush";
900 		break;
901 	case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
902 		tool_type = "airbrush";
903 		break;
904 	case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
905 		tool_type = "mouse";
906 		break;
907 	case LIBINPUT_TABLET_TOOL_TYPE_LENS:
908 		tool_type = "lens";
909 		break;
910 	default:
911 		tool_type = "unknown";
912 		break;
913 	}
914 
915 	prox = libinput_event_tablet_tool_get_proximity_state(t);
916 	time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t));
917 	axes = buffer_tablet_axes(t);
918 
919 	idx = 0;
920 	if (libinput_tablet_tool_has_pressure(tool))
921 		caps[idx++] = 'p';
922 	if (libinput_tablet_tool_has_distance(tool))
923 		caps[idx++] = 'd';
924 	if (libinput_tablet_tool_has_tilt(tool))
925 		caps[idx++] = 't';
926 	if (libinput_tablet_tool_has_rotation(tool))
927 		caps[idx++] = 'r';
928 	if (libinput_tablet_tool_has_slider(tool))
929 		caps[idx++] = 's';
930 	if (libinput_tablet_tool_has_wheel(tool))
931 		caps[idx++] = 'w';
932 	assert(idx <= ARRAY_LENGTH(caps));
933 
934 	iprintf(dev->fp,
935 		I_EVENT,
936 		"- {time: %ld.%06ld, type: %s, proximity: %s, tool-type: %s, serial: %" PRIu64 ", axes: %s, %s}\n",
937 		(long)(time / (int)1e6),
938 		(long)(time % (int)1e6),
939 		type,
940 		prox ? "in" : "out",
941 		tool_type,
942 		libinput_tablet_tool_get_serial(tool),
943 		caps,
944 		axes);
945 	free(axes);
946 }
947 
948 static void
print_tablet_tool_button_event(struct record_device * dev,struct libinput_event * e)949 print_tablet_tool_button_event(struct record_device *dev,
950 			       struct libinput_event *e)
951 {
952 	struct libinput_event_tablet_tool *t =
953 		libinput_event_get_tablet_tool_event(e);
954 	uint64_t time;
955 	const char *type;
956 	uint32_t button;
957 	enum libinput_button_state state;
958 
959 	switch(libinput_event_get_type(e)) {
960 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
961 		type = "TABLET_TOOL_BUTTON";
962 		break;
963 	default:
964 		abort();
965 	}
966 
967 
968 	button = libinput_event_tablet_tool_get_button(t);
969 	state = libinput_event_tablet_tool_get_button_state(t);
970 	time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t));
971 
972 	iprintf(dev->fp,
973 		I_EVENT,
974 		"- {time: %ld.%06ld, type: %s, button: %d, state: %s}\n",
975 		(long)(time / (int)1e6),
976 		(long)(time % (int)1e6),
977 		type,
978 		button,
979 		state ? "pressed" : "released");
980 }
981 
982 static void
print_tablet_tool_event(struct record_device * dev,struct libinput_event * e)983 print_tablet_tool_event(struct record_device *dev, struct libinput_event *e)
984 {
985 	struct libinput_event_tablet_tool *t =
986 		libinput_event_get_tablet_tool_event(e);
987 	uint64_t time;
988 	const char *type;
989 	char *axes;
990 	enum libinput_tablet_tool_tip_state tip;
991 	char btn_buffer[30] = {0};
992 
993 	switch(libinput_event_get_type(e)) {
994 	case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
995 		type = "TABLET_TOOL_AXIS";
996 		break;
997 	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
998 		type = "TABLET_TOOL_TIP";
999 		break;
1000 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
1001 		type = "TABLET_TOOL_BUTTON";
1002 		break;
1003 	default:
1004 		abort();
1005 	}
1006 
1007 	if (libinput_event_get_type(e) == LIBINPUT_EVENT_TABLET_TOOL_BUTTON) {
1008 		uint32_t button;
1009 		enum libinput_button_state state;
1010 
1011 		button = libinput_event_tablet_tool_get_button(t);
1012 		state = libinput_event_tablet_tool_get_button_state(t);
1013 		snprintf(btn_buffer, sizeof(btn_buffer),
1014 			 ", button: %d, state: %s\n",
1015 			 button,
1016 			 state ? "pressed" : "released");
1017 	}
1018 
1019 	tip = libinput_event_tablet_tool_get_tip_state(t);
1020 	time = time_offset(dev->ctx, libinput_event_tablet_tool_get_time_usec(t));
1021 	axes = buffer_tablet_axes(t);
1022 
1023 	iprintf(dev->fp,
1024 		I_EVENT,
1025 		"- {time: %ld.%06ld, type: %s%s, tip: %s, %s}\n",
1026 		(long)(time / (int)1e6),
1027 		(long)(time % (int)1e6),
1028 		type,
1029 		btn_buffer, /* may be empty string */
1030 		tip ? "down" : "up",
1031 		axes);
1032 	free(axes);
1033 }
1034 
1035 static void
print_tablet_pad_button_event(struct record_device * dev,struct libinput_event * e)1036 print_tablet_pad_button_event(struct record_device *dev,
1037 			      struct libinput_event *e)
1038 {
1039 	struct libinput_event_tablet_pad *p =
1040 		libinput_event_get_tablet_pad_event(e);
1041 	struct libinput_tablet_pad_mode_group *group;
1042 	enum libinput_button_state state;
1043 	unsigned int button, mode;
1044 	const char *type;
1045 	uint64_t time;
1046 
1047 	switch(libinput_event_get_type(e)) {
1048 	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
1049 		type = "TABLET_PAD_BUTTON";
1050 		break;
1051 	default:
1052 		abort();
1053 	}
1054 
1055 	time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p));
1056 	button = libinput_event_tablet_pad_get_button_number(p),
1057 	state = libinput_event_tablet_pad_get_button_state(p);
1058 	mode = libinput_event_tablet_pad_get_mode(p);
1059 	group = libinput_event_tablet_pad_get_mode_group(p);
1060 
1061 	iprintf(dev->fp,
1062 		I_EVENT,
1063 		"- {time: %ld.%06ld, type: %s, button: %d, state: %s, mode: %d, is-toggle: %s}\n",
1064 		(long)(time / (int)1e6),
1065 		(long)(time % (int)1e6),
1066 		type,
1067 		button,
1068 		state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released",
1069 		mode,
1070 		libinput_tablet_pad_mode_group_button_is_toggle(group, button) ? "true" : "false"
1071 	       );
1072 
1073 
1074 }
1075 
1076 static void
print_tablet_pad_ringstrip_event(struct record_device * dev,struct libinput_event * e)1077 print_tablet_pad_ringstrip_event(struct record_device *dev, struct libinput_event *e)
1078 {
1079 	struct libinput_event_tablet_pad *p =
1080 		libinput_event_get_tablet_pad_event(e);
1081 	const char *source = NULL;
1082 	unsigned int mode, number;
1083 	const char *type;
1084 	uint64_t time;
1085 	double pos;
1086 
1087 	switch(libinput_event_get_type(e)) {
1088 	case LIBINPUT_EVENT_TABLET_PAD_RING:
1089 		type = "TABLET_PAD_RING";
1090 		number = libinput_event_tablet_pad_get_ring_number(p);
1091 	        pos = libinput_event_tablet_pad_get_ring_position(p);
1092 
1093 		switch (libinput_event_tablet_pad_get_ring_source(p)) {
1094 		case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER:
1095 			source = "finger";
1096 			break;
1097 		case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN:
1098 			source = "unknown";
1099 			break;
1100 		}
1101 		break;
1102 	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
1103 		type = "TABLET_PAD_STRIP";
1104 		number = libinput_event_tablet_pad_get_strip_number(p);
1105 	        pos = libinput_event_tablet_pad_get_strip_position(p);
1106 
1107 		switch (libinput_event_tablet_pad_get_strip_source(p)) {
1108 		case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER:
1109 			source = "finger";
1110 			break;
1111 		case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN:
1112 			source = "unknown";
1113 			break;
1114 		}
1115 		break;
1116 	default:
1117 		abort();
1118 	}
1119 
1120 	time = time_offset(dev->ctx, libinput_event_tablet_pad_get_time_usec(p));
1121 	mode = libinput_event_tablet_pad_get_mode(p);
1122 
1123 	iprintf(dev->fp,
1124 		I_EVENT,
1125 		"- {time: %ld.%06ld, type: %s, number: %d, position: %.2f, source: %s, mode: %d}\n",
1126 		(long)(time / (int)1e6),
1127 		(long)(time % (int)1e6),
1128 		type,
1129 		number,
1130 		pos,
1131 		source,
1132 		mode);
1133 }
1134 
1135 static void
print_switch_event(struct record_device * dev,struct libinput_event * e)1136 print_switch_event(struct record_device *dev, struct libinput_event *e)
1137 {
1138 	struct libinput_event_switch *s = libinput_event_get_switch_event(e);
1139 	enum libinput_switch_state state;
1140 	uint32_t sw;
1141 	const char *type;
1142 	uint64_t time;
1143 
1144 	switch(libinput_event_get_type(e)) {
1145 	case LIBINPUT_EVENT_SWITCH_TOGGLE:
1146 		type = "SWITCH_TOGGLE";
1147 		break;
1148 	default:
1149 		abort();
1150 	}
1151 
1152 	time = time_offset(dev->ctx, libinput_event_switch_get_time_usec(s));
1153 	sw = libinput_event_switch_get_switch(s);
1154 	state = libinput_event_switch_get_switch_state(s);
1155 
1156 	iprintf(dev->fp,
1157 		I_EVENT,
1158 		"- {time: %ld.%06ld, type: %s, switch: %d, state: %s}\n",
1159 		(long)(time / (int)1e6),
1160 		(long)(time % (int)1e6),
1161 		type,
1162 		sw,
1163 		state == LIBINPUT_SWITCH_STATE_ON ? "on" : "off");
1164 }
1165 
1166 static void
print_libinput_event(struct record_device * dev,struct libinput_event * e)1167 print_libinput_event(struct record_device *dev, struct libinput_event *e)
1168 {
1169 	switch (libinput_event_get_type(e)) {
1170 	case LIBINPUT_EVENT_NONE:
1171 		abort();
1172 	case LIBINPUT_EVENT_DEVICE_ADDED:
1173 	case LIBINPUT_EVENT_DEVICE_REMOVED:
1174 		print_device_notify(dev, e);
1175 		break;
1176 	case LIBINPUT_EVENT_KEYBOARD_KEY:
1177 		print_key_event(dev, e);
1178 		break;
1179 	case LIBINPUT_EVENT_POINTER_MOTION:
1180 		print_motion_event(dev, e);
1181 		break;
1182 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
1183 		print_absmotion_event(dev, e);
1184 		break;
1185 	case LIBINPUT_EVENT_POINTER_BUTTON:
1186 		print_pointer_button_event(dev, e);
1187 		break;
1188 	case LIBINPUT_EVENT_POINTER_AXIS:
1189 		print_pointer_axis_event(dev, e);
1190 		break;
1191 	case LIBINPUT_EVENT_TOUCH_DOWN:
1192 	case LIBINPUT_EVENT_TOUCH_UP:
1193 	case LIBINPUT_EVENT_TOUCH_MOTION:
1194 	case LIBINPUT_EVENT_TOUCH_CANCEL:
1195 	case LIBINPUT_EVENT_TOUCH_FRAME:
1196 		print_touch_event(dev, e);
1197 		break;
1198 	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
1199 	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
1200 	case LIBINPUT_EVENT_GESTURE_PINCH_END:
1201 	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
1202 	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
1203 	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
1204 		print_gesture_event(dev, e);
1205 		break;
1206 	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
1207 		print_tablet_tool_proximity_event(dev, e);
1208 		break;
1209 	case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
1210 	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
1211 		print_tablet_tool_event(dev, e);
1212 		break;
1213 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
1214 		print_tablet_tool_button_event(dev, e);
1215 		break;
1216 	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
1217 		print_tablet_pad_button_event(dev, e);
1218 		break;
1219 	case LIBINPUT_EVENT_TABLET_PAD_RING:
1220 	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
1221 		print_tablet_pad_ringstrip_event(dev, e);
1222 		break;
1223 	case LIBINPUT_EVENT_SWITCH_TOGGLE:
1224 		print_switch_event(dev, e);
1225 		break;
1226 	default:
1227 		break;
1228 	}
1229 }
1230 
1231 static bool
handle_hidraw(struct hidraw * hidraw)1232 handle_hidraw(struct hidraw *hidraw)
1233 {
1234 	struct record_device *d = hidraw->device;
1235 	unsigned char report[4096];
1236 	const char *sep = "";
1237 	struct timespec ts;
1238 	struct timeval tv;
1239 	uint64_t time;
1240 
1241 	int rc = read(hidraw->fd, report, sizeof(report));
1242 	if (rc <= 0)
1243 		return false;
1244 
1245 	/* hidraw doesn't give us a timestamps, we have to make them up */
1246 	clock_gettime(CLOCK_MONOTONIC, &ts);
1247 	time = s2us(ts.tv_sec) + ns2us(ts.tv_nsec);
1248 
1249 	/* The first evdev event is guaranteed to have an event time earlier
1250 	   than now, so we don't set the offset here, we rely on the evdev
1251 	   events to do so. This potentially leaves us with multiple hidraw
1252 	   events at timestap 0 but it's too niche to worry about.  */
1253 	if (d->ctx->offset == 0)
1254 		time = 0;
1255 	else
1256 		time = time_offset(d->ctx, time);
1257 
1258 	tv = us2tv(time);
1259 
1260 	iprintf(d->fp, I_EVENTTYPE, "- hid:\n");
1261 	iprintf(d->fp, I_EVENT, "time: [%3lu, %6lu]\n", tv.tv_sec, tv.tv_usec);
1262 	iprintf(d->fp, I_EVENT, "%s: [", hidraw->name);
1263 
1264 	for (int byte = 0; byte < rc; byte++) {
1265 		if (byte % 16 == 0) {
1266 			iprintf(d->fp, I_NONE, "%s\n", sep);
1267 			iprintf(d->fp, I_EVENT, "  ");
1268 			iprintf(d->fp, I_NONE, "0x%02x", report[byte]);
1269 		} else {
1270 			iprintf(d->fp, I_NONE, "%s0x%02x", sep, report[byte]);
1271 		}
1272 		sep = ", ";
1273 	}
1274 	iprintf(d->fp, I_NONE, "\n");
1275 	iprintf(d->fp, I_EVENT, "]\n");
1276 
1277 	return true;
1278 }
1279 
1280 static bool
handle_libinput_events(struct record_context * ctx,struct record_device * d,bool start_frame)1281 handle_libinput_events(struct record_context *ctx,
1282 		       struct record_device *d,
1283 		       bool start_frame)
1284 {
1285 	struct libinput_event *e;
1286 	struct record_device *current = d;
1287 
1288 	libinput_dispatch(ctx->libinput);
1289 	e = libinput_get_event(ctx->libinput);
1290 	if (!e)
1291 		return false;
1292 
1293 	iprintf(d->fp, I_EVENTTYPE, "%slibinput:\n", start_frame ? "- " : "");
1294 	do {
1295 		struct libinput_device *device = libinput_event_get_device(e);
1296 
1297 		if (device != current->device) {
1298 			struct record_device *tmp;
1299 			bool found = false;
1300 			list_for_each(tmp, &ctx->devices, link) {
1301 				if (device == tmp->device) {
1302 					current = tmp;
1303 					found = true;
1304 					break;
1305 				}
1306 			}
1307 			assert(found);
1308 		}
1309 
1310 		print_libinput_event(current, e);
1311 		libinput_event_destroy(e);
1312 	} while ((e = libinput_get_event(ctx->libinput)) != NULL);
1313 
1314 	return true;
1315 }
1316 
1317 static void
handle_events(struct record_context * ctx,struct record_device * d)1318 handle_events(struct record_context *ctx, struct record_device *d)
1319 {
1320 	bool has_events = true;
1321 
1322 	while (has_events) {
1323 		has_events = handle_evdev_frame(d);
1324 
1325 		if (ctx->libinput)
1326 			has_events |= handle_libinput_events(ctx,
1327 							     d,
1328 							     !has_events);
1329 	}
1330 
1331 	fflush(d->fp);
1332 }
1333 
1334 static void
print_libinput_header(FILE * fp,int timeout)1335 print_libinput_header(FILE *fp, int timeout)
1336 {
1337 	iprintf(fp, I_TOPLEVEL, "libinput:\n");
1338 	iprintf(fp, I_LIBINPUT, "version: \"%s\"\n", LIBINPUT_VERSION);
1339 	iprintf(fp, I_LIBINPUT, "git: \"%s\"\n", LIBINPUT_GIT_VERSION);
1340 	if (timeout > 0)
1341 		iprintf(fp, I_LIBINPUT, "autorestart: %d\n", timeout);
1342 }
1343 
1344 static void
print_system_header(FILE * fp)1345 print_system_header(FILE *fp)
1346 {
1347 	struct utsname u;
1348 	const char *kernel = "unknown";
1349 	FILE *dmi, *osrelease;
1350 	char dmistr[2048] = "unknown";
1351 
1352 	iprintf(fp, I_TOPLEVEL, "system:\n");
1353 
1354 	/* /etc/os-release version and distribution name */
1355 	osrelease = fopen("/etc/os-release", "r");
1356 	if (!osrelease)
1357 		osrelease = fopen("/usr/lib/os-release", "r");
1358 	if (osrelease) {
1359 		char *distro = NULL, *version = NULL;
1360 		char osrstr[256] = "unknown";
1361 
1362 		while (fgets(osrstr, sizeof(osrstr), osrelease)) {
1363 			osrstr[strlen(osrstr) - 1] = '\0'; /* linebreak */
1364 
1365 			if (!distro && strneq(osrstr, "ID=", 3))
1366 				distro = strstrip(&osrstr[3], "\"'");
1367 			else if (!version && strneq(osrstr, "VERSION_ID=", 11))
1368 				version = strstrip(&osrstr[11], "\"'");
1369 
1370 			if (distro && version) {
1371 				iprintf(fp,
1372 					I_SYSTEM,
1373 					"os: \"%s:%s\"\n",
1374 					distro,
1375 					version);
1376 				break;
1377 			}
1378 		}
1379 		free(distro);
1380 		free(version);
1381 		fclose(osrelease);
1382 	}
1383 
1384 	/* kernel version */
1385 	if (uname(&u) != -1)
1386 		kernel = u.release;
1387 	iprintf(fp, I_SYSTEM, "kernel: \"%s\"\n", kernel);
1388 
1389 	/* dmi modalias */
1390 	dmi = fopen("/sys/class/dmi/id/modalias", "r");
1391 	if (dmi) {
1392 		if (fgets(dmistr, sizeof(dmistr), dmi)) {
1393 			dmistr[strlen(dmistr) - 1] = '\0'; /* linebreak */
1394 		} else {
1395 			sprintf(dmistr, "unknown");
1396 		}
1397 		fclose(dmi);
1398 	}
1399 	iprintf(fp, I_SYSTEM, "dmi: \"%s\"\n", dmistr);
1400 }
1401 
1402 static void
print_header(FILE * fp,struct record_context * ctx)1403 print_header(FILE *fp, struct record_context *ctx)
1404 {
1405 	iprintf(fp, I_TOPLEVEL, "# libinput record\n");
1406 	iprintf(fp, I_TOPLEVEL, "version: %d\n", FILE_VERSION_NUMBER);
1407 	iprintf(fp, I_TOPLEVEL, "ndevices: %d\n", ctx->ndevices);
1408 	print_libinput_header(fp, ctx->timeout);
1409 	print_system_header(fp);
1410 }
1411 
1412 static void
print_description_abs(FILE * fp,struct libevdev * dev,unsigned int code)1413 print_description_abs(FILE *fp,
1414 		      struct libevdev *dev,
1415 		      unsigned int code)
1416 {
1417 	const struct input_absinfo *abs;
1418 
1419 	abs = libevdev_get_abs_info(dev, code);
1420 	assert(abs);
1421 
1422 	iprintf(fp, I_EVDEV, "#       Value      %6d\n", abs->value);
1423 	iprintf(fp, I_EVDEV, "#       Min        %6d\n", abs->minimum);
1424 	iprintf(fp, I_EVDEV, "#       Max        %6d\n", abs->maximum);
1425 	iprintf(fp, I_EVDEV, "#       Fuzz       %6d\n", abs->fuzz);
1426 	iprintf(fp, I_EVDEV, "#       Flat       %6d\n", abs->flat);
1427 	iprintf(fp, I_EVDEV, "#       Resolution %6d\n", abs->resolution);
1428 }
1429 
1430 static void
print_description_state(FILE * fp,struct libevdev * dev,unsigned int type,unsigned int code)1431 print_description_state(FILE *fp,
1432 			struct libevdev *dev,
1433 			unsigned int type,
1434 			unsigned int code)
1435 {
1436 	int state = libevdev_get_event_value(dev, type, code);
1437 	iprintf(fp, I_EVDEV, "#       State %d\n", state);
1438 }
1439 
1440 static void
print_description_codes(FILE * fp,struct libevdev * dev,unsigned int type)1441 print_description_codes(FILE *fp,
1442 			struct libevdev *dev,
1443 			unsigned int type)
1444 {
1445 	int max;
1446 
1447 	max = libevdev_event_type_get_max(type);
1448 	if (max == -1)
1449 		return;
1450 
1451 	iprintf(fp,
1452 		I_EVDEV,
1453 		"# Event type %d (%s)\n",
1454 		type,
1455 		libevdev_event_type_get_name(type));
1456 
1457 	if (type == EV_SYN)
1458 		return;
1459 
1460 	for (unsigned int code = 0; code <= (unsigned int)max; code++) {
1461 		if (!libevdev_has_event_code(dev, type, code))
1462 			continue;
1463 
1464 		iprintf(fp,
1465 			I_EVDEV,
1466 			"#   Event code %d (%s)\n",
1467 			code,
1468 			libevdev_event_code_get_name(type,
1469 						     code));
1470 
1471 		switch (type) {
1472 		case EV_ABS:
1473 			print_description_abs(fp, dev, code);
1474 			break;
1475 		case EV_LED:
1476 		case EV_SW:
1477 			print_description_state(fp, dev, type, code);
1478 			break;
1479 		}
1480 	}
1481 }
1482 
1483 static void
print_description(FILE * fp,struct libevdev * dev)1484 print_description(FILE *fp, struct libevdev *dev)
1485 {
1486 	const struct input_absinfo *x, *y;
1487 
1488 	iprintf(fp, I_EVDEV, "# Name: %s\n", libevdev_get_name(dev));
1489 	iprintf(fp,
1490 		I_EVDEV,
1491 		"# ID: bus %#02x vendor %#02x product %#02x version %#02x\n",
1492 		libevdev_get_id_bustype(dev),
1493 		libevdev_get_id_vendor(dev),
1494 		libevdev_get_id_product(dev),
1495 		libevdev_get_id_version(dev));
1496 
1497 	x = libevdev_get_abs_info(dev, ABS_X);
1498 	y = libevdev_get_abs_info(dev, ABS_Y);
1499 	if (x && y) {
1500 		if (x->resolution && y->resolution) {
1501 			int w, h;
1502 
1503 			w = (x->maximum - x->minimum)/x->resolution;
1504 			h = (y->maximum - y->minimum)/y->resolution;
1505 			iprintf(fp, I_EVDEV, "# Size in mm: %dx%d\n", w, h);
1506 		} else {
1507 			iprintf(fp,
1508 				I_EVDEV,
1509 				"# Size in mm: unknown, missing resolution\n");
1510 		}
1511 	}
1512 
1513 	iprintf(fp, I_EVDEV, "# Supported Events:\n");
1514 
1515 	for (unsigned int type = 0; type < EV_CNT; type++) {
1516 		if (!libevdev_has_event_type(dev, type))
1517 			continue;
1518 
1519 		print_description_codes(fp, dev, type);
1520 	}
1521 
1522 	iprintf(fp, I_EVDEV, "# Properties:\n");
1523 
1524 	for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) {
1525 		if (libevdev_has_property(dev, prop)) {
1526 			iprintf(fp,
1527 				I_EVDEV,
1528 				"#    Property %d (%s)\n",
1529 				prop,
1530 				libevdev_property_get_name(prop));
1531 		}
1532 	}
1533 }
1534 
1535 static void
print_bits_info(FILE * fp,struct libevdev * dev)1536 print_bits_info(FILE *fp, struct libevdev *dev)
1537 {
1538 	iprintf(fp, I_EVDEV, "name: \"%s\"\n", libevdev_get_name(dev));
1539 	iprintf(fp,
1540 		I_EVDEV,
1541 		"id: [%d, %d, %d, %d]\n",
1542 		libevdev_get_id_bustype(dev),
1543 		libevdev_get_id_vendor(dev),
1544 		libevdev_get_id_product(dev),
1545 		libevdev_get_id_version(dev));
1546 }
1547 
1548 static void
print_bits_absinfo(FILE * fp,struct libevdev * dev)1549 print_bits_absinfo(FILE *fp, struct libevdev *dev)
1550 {
1551 	const struct input_absinfo *abs;
1552 
1553 	if (!libevdev_has_event_type(dev, EV_ABS))
1554 		return;
1555 
1556 	iprintf(fp, I_EVDEV, "absinfo:\n");
1557 	for (unsigned int code = 0; code < ABS_CNT; code++) {
1558 		abs = libevdev_get_abs_info(dev, code);
1559 		if (!abs)
1560 			continue;
1561 
1562 		iprintf(fp,
1563 			I_EVDEV_DATA,
1564 			"%d: [%d, %d, %d, %d, %d]\n",
1565 			code,
1566 			abs->minimum,
1567 			abs->maximum,
1568 			abs->fuzz,
1569 			abs->flat,
1570 			abs->resolution);
1571 	}
1572 }
1573 
1574 static void
print_bits_codes(FILE * fp,struct libevdev * dev,unsigned int type)1575 print_bits_codes(FILE *fp, struct libevdev *dev, unsigned int type)
1576 {
1577 	int max;
1578 	const char *sep = "";
1579 
1580 	max = libevdev_event_type_get_max(type);
1581 	if (max == -1)
1582 		return;
1583 
1584 	iprintf(fp, I_EVDEV_DATA, "%d: [", type);
1585 
1586 	for (unsigned int code = 0; code <= (unsigned int)max; code++) {
1587 		if (!libevdev_has_event_code(dev, type, code))
1588 			continue;
1589 
1590 		iprintf(fp, I_NONE, "%s%d", sep, code);
1591 		sep = ", ";
1592 	}
1593 
1594 	iprintf(fp, I_NONE, "] # %s\n", libevdev_event_type_get_name(type));
1595 }
1596 
1597 static void
print_bits_types(FILE * fp,struct libevdev * dev)1598 print_bits_types(FILE *fp, struct libevdev *dev)
1599 {
1600 	iprintf(fp, I_EVDEV, "codes:\n");
1601 	for (unsigned int type = 0; type < EV_CNT; type++) {
1602 		if (!libevdev_has_event_type(dev, type))
1603 			continue;
1604 		print_bits_codes(fp, dev, type);
1605 	}
1606 }
1607 
1608 static void
print_bits_props(FILE * fp,struct libevdev * dev)1609 print_bits_props(FILE *fp, struct libevdev *dev)
1610 {
1611 	const char *sep = "";
1612 
1613 	iprintf(fp, I_EVDEV, "properties: [");
1614 	for (unsigned int prop = 0; prop < INPUT_PROP_CNT; prop++) {
1615 		if (libevdev_has_property(dev, prop)) {
1616 			iprintf(fp, I_NONE, "%s%d", sep, prop);
1617 			sep = ", ";
1618 		}
1619 	}
1620 	iprintf(fp, I_NONE, "]\n"); /* last entry, no comma */
1621 }
1622 
1623 static void
print_evdev_description(struct record_device * dev)1624 print_evdev_description(struct record_device *dev)
1625 {
1626 	struct libevdev *evdev = dev->evdev;
1627 
1628 	iprintf(dev->fp, I_DEVICE, "evdev:\n");
1629 
1630 	print_description(dev->fp, evdev);
1631 	print_bits_info(dev->fp, evdev);
1632 	print_bits_types(dev->fp, evdev);
1633 	print_bits_absinfo(dev->fp, evdev);
1634 	print_bits_props(dev->fp, evdev);
1635 }
1636 
1637 static void
print_hid_report_descriptor(struct record_device * dev)1638 print_hid_report_descriptor(struct record_device *dev)
1639 {
1640 	const char *prefix = "/dev/input/event";
1641 	char syspath[PATH_MAX];
1642 	unsigned char buf[1024];
1643 	int len;
1644 	int fd;
1645 	const char *sep = "";
1646 
1647 	/* we take the shortcut rather than the proper udev approach, the
1648 	   report_descriptor is available in sysfs and two devices up from
1649 	   our device.
1650 	   This approach won't work for /dev/input/by-id devices. */
1651 	if (!strstartswith(dev->devnode, prefix))
1652 		return;
1653 
1654 	len = snprintf(syspath,
1655 		       sizeof(syspath),
1656 		       "/sys/class/input/%s/device/device/report_descriptor",
1657 		       safe_basename(dev->devnode));
1658 	if (len <= 0)
1659 		return;
1660 
1661 	fd = open(syspath, O_RDONLY);
1662 	if (fd == -1)
1663 		return;
1664 
1665 	iprintf(dev->fp, I_DEVICE, "hid: [");
1666 
1667 	while ((len = read(fd, buf, sizeof(buf))) > 0) {
1668 		for (int i = 0; i < len; i++) {
1669 			/* We can't have a trailing comma, so our line-break
1670 			 * handling is awkward.
1671 			 * For a linebreak: print the comma, break, indent,
1672 			 *    then just the hex code.
1673 			 * For the other values: print the comma plus the
1674 			 *    hex code, unindented.
1675 			 */
1676 			if (i % 16 == 0) {
1677 				iprintf(dev->fp, I_NONE, "%s\n", sep);
1678 				iprintf(dev->fp, I_DEVICE, "  ");
1679 				iprintf(dev->fp, I_NONE, "0x%02x", buf[i]);
1680 			} else {
1681 				iprintf(dev->fp, I_NONE, "%s0x%02x", sep, buf[i]);
1682 			}
1683 			sep = ", ";
1684 		}
1685 	}
1686 	iprintf(dev->fp, I_NONE, "\n");
1687 	iprintf(dev->fp, I_DEVICE, "]\n");
1688 
1689 	close(fd);
1690 }
1691 
1692 static void
print_udev_properties(struct record_device * dev)1693 print_udev_properties(struct record_device *dev)
1694 {
1695 	struct udev *udev = NULL;
1696 	struct udev_device *udev_device = NULL;
1697 	struct udev_list_entry *entry;
1698 	struct stat st;
1699 
1700 	if (stat(dev->devnode, &st) < 0)
1701 		return;
1702 
1703 	udev = udev_new();
1704 	if (!udev)
1705 		goto out;
1706 
1707 	udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
1708 	if (!udev_device)
1709 		goto out;
1710 
1711 	iprintf(dev->fp, I_DEVICE, "udev:\n");
1712 
1713 	iprintf(dev->fp, I_UDEV, "properties:\n");
1714 
1715 	entry = udev_device_get_properties_list_entry(udev_device);
1716 	while (entry) {
1717 		const char *key, *value;
1718 
1719 		key = udev_list_entry_get_name(entry);
1720 
1721 		if (strneq(key, "ID_INPUT", 8) ||
1722 		    strneq(key, "LIBINPUT", 8) ||
1723 		    strneq(key, "EVDEV_ABS", 9) ||
1724 		    strneq(key, "MOUSE_DPI", 9) ||
1725 		    strneq(key, "POINTINGSTICK_", 14)) {
1726 			value = udev_list_entry_get_value(entry);
1727 			iprintf(dev->fp, I_UDEV_DATA, "- %s=%s\n", key, value);
1728 		}
1729 
1730 		entry = udev_list_entry_get_next(entry);
1731 	}
1732 
1733 out:
1734 	udev_device_unref(udev_device);
1735 	udev_unref(udev);
1736 }
1737 
1738 static void
quirks_log_handler(struct libinput * this_is_null,enum libinput_log_priority priority,const char * format,va_list args)1739 quirks_log_handler(struct libinput *this_is_null,
1740 		   enum libinput_log_priority priority,
1741 		   const char *format,
1742 		   va_list args)
1743 {
1744 }
1745 
1746 static void
list_print(void * userdata,const char * val)1747 list_print(void *userdata, const char *val)
1748 {
1749 	FILE *fp = userdata;
1750 
1751 	iprintf(fp, I_QUIRKS, "- %s\n", val);
1752 }
1753 
1754 static void
print_device_quirks(struct record_device * dev)1755 print_device_quirks(struct record_device *dev)
1756 {
1757 	struct udev *udev = NULL;
1758 	struct udev_device *udev_device = NULL;
1759 	struct stat st;
1760 	struct quirks_context *quirks;
1761 	const char *data_path = LIBINPUT_QUIRKS_DIR;
1762 	const char *override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE;
1763 	char *builddir = NULL;
1764 
1765 	if (stat(dev->devnode, &st) < 0)
1766 		return;
1767 
1768 	if ((builddir = builddir_lookup())) {
1769 		setenv("LIBINPUT_QUIRKS_DIR", LIBINPUT_QUIRKS_SRCDIR, 0);
1770 		data_path = LIBINPUT_QUIRKS_SRCDIR;
1771 		override_file = NULL;
1772 	}
1773 
1774 	free(builddir);
1775 
1776 	quirks = quirks_init_subsystem(data_path,
1777 				       override_file,
1778 				       quirks_log_handler,
1779 				       NULL,
1780 				       QLOG_CUSTOM_LOG_PRIORITIES);
1781 	if (!quirks) {
1782 		fprintf(stderr,
1783 			"Failed to initialize the device quirks. "
1784 			"Please see the above errors "
1785 			"and/or re-run with --verbose for more details\n");
1786 		return;
1787 	}
1788 
1789 	udev = udev_new();
1790 	if (!udev)
1791 		goto out;
1792 
1793 	udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
1794 	if (!udev_device)
1795 		goto out;
1796 
1797 	iprintf(dev->fp, I_DEVICE, "quirks:\n");
1798 	tools_list_device_quirks(quirks, udev_device, list_print, dev->fp);
1799 out:
1800 	udev_device_unref(udev_device);
1801 	udev_unref(udev);
1802 	quirks_context_unref(quirks);
1803 }
1804 
1805 static void
print_libinput_description(struct record_device * dev)1806 print_libinput_description(struct record_device *dev)
1807 {
1808 	struct libinput_device *device = dev->device;
1809 	double w, h;
1810 	struct cap {
1811 		enum libinput_device_capability cap;
1812 		const char *name;
1813 	} caps[] =  {
1814 		{LIBINPUT_DEVICE_CAP_KEYBOARD, "keyboard"},
1815 		{LIBINPUT_DEVICE_CAP_POINTER, "pointer"},
1816 		{LIBINPUT_DEVICE_CAP_TOUCH, "touch"},
1817 		{LIBINPUT_DEVICE_CAP_TABLET_TOOL, "tablet"},
1818 		{LIBINPUT_DEVICE_CAP_TABLET_PAD, "pad"},
1819 		{LIBINPUT_DEVICE_CAP_GESTURE, "gesture"},
1820 		{LIBINPUT_DEVICE_CAP_SWITCH, "switch"},
1821 	};
1822 	struct cap *cap;
1823 	const char *sep = "";
1824 
1825 	if (!device)
1826 		return;
1827 
1828 	iprintf(dev->fp, I_DEVICE, "libinput:\n");
1829 	if (libinput_device_get_size(device, &w, &h) == 0)
1830 		iprintf(dev->fp, I_LIBINPUTDEV, "size: [%.f, %.f]\n", w, h);
1831 
1832 	iprintf(dev->fp, I_LIBINPUTDEV, "capabilities: [");
1833 	ARRAY_FOR_EACH(caps, cap) {
1834 		if (!libinput_device_has_capability(device, cap->cap))
1835 			continue;
1836 		iprintf(dev->fp, I_NONE, "%s%s", sep, cap->name);
1837 		sep = ", ";
1838 	}
1839 	iprintf(dev->fp, I_NONE, "]\n");
1840 
1841 	/* Configuration options should be printed here, but since they
1842 	 * don't reflect the user-configured ones their usefulness is
1843 	 * questionable. We need the ability to specify the options like in
1844 	 * debug-events.
1845 	 */
1846 }
1847 
1848 static void
print_device_description(struct record_device * dev)1849 print_device_description(struct record_device *dev)
1850 {
1851 	iprintf(dev->fp, I_DEVICE, "- node: %s\n", dev->devnode);
1852 
1853 	print_evdev_description(dev);
1854 	print_hid_report_descriptor(dev);
1855 	print_udev_properties(dev);
1856 	print_device_quirks(dev);
1857 	print_libinput_description(dev);
1858 }
1859 
is_event_node(const struct dirent * dir)1860 static int is_event_node(const struct dirent *dir) {
1861 	return strneq(dir->d_name, "event", 5);
1862 }
1863 
1864 static char *
select_device(void)1865 select_device(void)
1866 {
1867 	struct dirent **namelist;
1868 	int ndev, selected_device;
1869 	int rc;
1870 	char *device_path;
1871 	bool has_eaccess = false;
1872 	int available_devices = 0;
1873 	const char *prefix = "";
1874 
1875 	if (!isatty(STDERR_FILENO))
1876 		prefix = "# ";
1877 
1878 	ndev = scandir("/dev/input", &namelist, is_event_node, versionsort);
1879 	if (ndev <= 0)
1880 		return NULL;
1881 
1882 	fprintf(stderr, "%sAvailable devices:\n", prefix);
1883 	for (int i = 0; i < ndev; i++) {
1884 		struct libevdev *device;
1885 		char path[PATH_MAX];
1886 		int fd = -1;
1887 
1888 		snprintf(path,
1889 			 sizeof(path),
1890 			 "/dev/input/%s",
1891 			 namelist[i]->d_name);
1892 		fd = open(path, O_RDONLY);
1893 		if (fd < 0) {
1894 			if (errno == EACCES)
1895 				has_eaccess = true;
1896 			continue;
1897 		}
1898 
1899 		rc = libevdev_new_from_fd(fd, &device);
1900 		close(fd);
1901 		if (rc != 0)
1902 			continue;
1903 
1904 		fprintf(stderr, "%s%s:	%s\n", prefix, path, libevdev_get_name(device));
1905 		libevdev_free(device);
1906 		available_devices++;
1907 	}
1908 
1909 	for (int i = 0; i < ndev; i++)
1910 		free(namelist[i]);
1911 	free(namelist);
1912 
1913 	if (available_devices == 0) {
1914 		fprintf(stderr,
1915 			"No devices available.%s\n",
1916 			has_eaccess ? " Please re-run as root." : "");
1917 		return NULL;
1918 	}
1919 
1920 	fprintf(stderr, "%sSelect the device event number: ", prefix);
1921 	rc = scanf("%d", &selected_device);
1922 
1923 	if (rc != 1 || selected_device < 0)
1924 		return NULL;
1925 
1926 	rc = xasprintf(&device_path, "/dev/input/event%d", selected_device);
1927 	if (rc == -1)
1928 		return NULL;
1929 
1930 	return device_path;
1931 }
1932 
1933 static char **
all_devices(void)1934 all_devices(void)
1935 {
1936 	struct dirent **namelist;
1937 	int ndev;
1938 	char **devices = NULL;
1939 
1940 	ndev = scandir("/dev/input", &namelist, is_event_node, versionsort);
1941 	if (ndev <= 0)
1942 		return NULL;
1943 
1944 	devices = zalloc((ndev + 1)* sizeof *devices); /* NULL-terminated */
1945 	for (int i = 0; i < ndev; i++) {
1946 		char *device_path;
1947 
1948 		int rc = xasprintf(&device_path,
1949 				   "/dev/input/%s",
1950 				   namelist[i]->d_name);
1951 		if (rc == -1)
1952 			goto error;
1953 
1954 		devices[i] = device_path;
1955 	}
1956 
1957 	return devices;
1958 
1959 error:
1960 	for (int i = 0; i < ndev; i++)
1961 		free(namelist[i]);
1962 	free(namelist);
1963 	if (devices)
1964 		strv_free(devices);
1965 	return NULL;
1966 }
1967 
1968 static char *
init_output_file(const char * file,bool is_prefix)1969 init_output_file(const char *file, bool is_prefix)
1970 {
1971 	char name[PATH_MAX];
1972 
1973 	assert(file != NULL);
1974 
1975 	if (is_prefix) {
1976 		struct tm *tm;
1977 		time_t t;
1978 		char suffix[64];
1979 
1980 		t = time(NULL);
1981 		tm = localtime(&t);
1982 		strftime(suffix, sizeof(suffix), "%F-%T", tm);
1983 		snprintf(name,
1984 			 sizeof(name),
1985 			 "%s.%s",
1986 			 file,
1987 			 suffix);
1988 	} else {
1989 		snprintf(name, sizeof(name), "%s", file);
1990 	}
1991 
1992 	return safe_strdup(name);
1993 }
1994 
1995 static bool
open_output_files(struct record_context * ctx,bool is_prefix)1996 open_output_files(struct record_context *ctx, bool is_prefix)
1997 {
1998 	FILE *out_file;
1999 	struct record_device *d;
2000 
2001 	if (ctx->output_file.name) {
2002 		char *fname = init_output_file(ctx->output_file.name, is_prefix);
2003 		ctx->output_file.name_with_suffix = fname;
2004 		out_file = fopen(fname, "w");
2005 		if (!out_file)
2006 			return false;
2007 	} else {
2008 		ctx->output_file.name_with_suffix = safe_strdup("stdout");
2009 		out_file = stdout;
2010 	}
2011 
2012 	ctx->first_device->fp = out_file;
2013 
2014 	list_for_each(d, &ctx->devices, link) {
2015 		if (d->fp)
2016 			continue;
2017 		d->fp = tmpfile();
2018 	}
2019 
2020 	return true;
2021 }
2022 
2023 static void
print_progress_bar(void)2024 print_progress_bar(void)
2025 {
2026 	static uint8_t foo = 0;
2027 
2028 	if (!isatty(STDERR_FILENO))
2029 		return;
2030 
2031 	if (++foo > 20)
2032 		foo = 1;
2033 	fprintf(stderr, "\rReceiving events: [%*s%*s]", foo, "*", 21 - foo, " ");
2034 }
2035 
2036 static void
print_wall_time(struct record_context * ctx)2037 print_wall_time(struct record_context *ctx)
2038 {
2039 	time_t t = time(NULL);
2040 	struct tm tm;
2041 	struct record_device *d;
2042 
2043 	localtime_r(&t, &tm);
2044 
2045 	list_for_each(d, &ctx->devices, link) {
2046 		iprintf(d->fp,
2047 			I_DEVICE,
2048 			"# Current time is %02d:%02d:%02d\n",
2049 			tm.tm_hour, tm.tm_min, tm.tm_sec);
2050 		fflush(d->fp);
2051 	}
2052 }
2053 
2054 static void
arm_timer(int timerfd)2055 arm_timer(int timerfd)
2056 {
2057 	time_t t = time(NULL);
2058 	struct tm tm;
2059 	struct itimerspec interval = {
2060 		.it_value = { 0, 0 },
2061 		.it_interval = { 5, 0 },
2062 	};
2063 
2064 	localtime_r(&t, &tm);
2065 	interval.it_value.tv_sec = 5 - (tm.tm_sec % 5);
2066 	timerfd_settime(timerfd, 0, &interval, NULL);
2067 }
2068 
2069 static struct source *
add_source(struct record_context * ctx,int fd,source_dispatch_t dispatch,void * user_data)2070 add_source(struct record_context *ctx,
2071 	   int fd,
2072 	   source_dispatch_t dispatch,
2073 	   void *user_data)
2074 {
2075 	struct source *source;
2076 	struct epoll_event ep;
2077 
2078 	assert(fd != -1);
2079 
2080 	source = zalloc(sizeof *source);
2081 	source->dispatch = dispatch;
2082 	source->user_data = user_data;
2083 	source->fd = fd;
2084 	list_append(&ctx->sources, &source->link);
2085 
2086 	memset(&ep, 0, sizeof ep);
2087 	ep.events = EPOLLIN;
2088 	ep.data.ptr = source;
2089 
2090 	if (epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
2091 		free(source);
2092 		return NULL;
2093 	}
2094 
2095 	return source;
2096 }
2097 
2098 static void
destroy_source(struct record_context * ctx,struct source * source)2099 destroy_source(struct record_context *ctx, struct source *source)
2100 {
2101 	list_remove(&source->link);
2102 	epoll_ctl(ctx->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
2103 	close(source->fd);
2104 	free(source);
2105 }
2106 
2107 static void
signalfd_dispatch(struct record_context * ctx,int fd,void * data)2108 signalfd_dispatch(struct record_context *ctx, int fd, void *data)
2109 {
2110 	struct signalfd_siginfo fdsi;
2111 
2112 	(void)read(fd, &fdsi, sizeof(fdsi));
2113 
2114 	ctx->stop = true;
2115 }
2116 
2117 static void
timefd_dispatch(struct record_context * ctx,int fd,void * data)2118 timefd_dispatch(struct record_context *ctx, int fd, void *data)
2119 {
2120 	char discard[64];
2121 
2122 	(void)read(fd, discard, sizeof(discard));
2123 
2124 	if (ctx->timestamps.had_events_since_last_time) {
2125 		print_wall_time(ctx);
2126 		ctx->timestamps.had_events_since_last_time = false;
2127 		ctx->timestamps.skipped_timer_print = false;
2128 	} else {
2129 		ctx->timestamps.skipped_timer_print = true;
2130 	}
2131 }
2132 
2133 static void
evdev_dispatch(struct record_context * ctx,int fd,void * data)2134 evdev_dispatch(struct record_context *ctx, int fd, void *data)
2135 {
2136 	struct record_device *this_device = data;
2137 
2138 	if (ctx->timestamps.skipped_timer_print) {
2139 		print_wall_time(ctx);
2140 		ctx->timestamps.skipped_timer_print = false;
2141 	}
2142 
2143 	ctx->had_events = true;
2144 	ctx->timestamps.had_events_since_last_time = true;
2145 
2146 	handle_events(ctx, this_device);
2147 }
2148 
2149 static void
libinput_ctx_dispatch(struct record_context * ctx,int fd,void * data)2150 libinput_ctx_dispatch(struct record_context *ctx, int fd, void *data)
2151 {
2152 	/* This function should only handle events caused by internal
2153 	 * timeouts etc. The real input events caused by the evdev devices
2154 	 * are already processed in handle_events */
2155 	libinput_dispatch(ctx->libinput);
2156 	handle_libinput_events(ctx, ctx->first_device, true);
2157 }
2158 
2159 static void
hidraw_dispatch(struct record_context * ctx,int fd,void * data)2160 hidraw_dispatch(struct record_context *ctx, int fd, void *data)
2161 {
2162 	struct hidraw *hidraw = data;
2163 
2164 	ctx->had_events = true;
2165 	ctx->timestamps.had_events_since_last_time = true;
2166 	handle_hidraw(hidraw);
2167 }
2168 
2169 static int
dispatch_sources(struct record_context * ctx)2170 dispatch_sources(struct record_context *ctx)
2171 {
2172 	struct source *source;
2173 	struct epoll_event ep[64];
2174 	int i, count;
2175 
2176 	count = epoll_wait(ctx->epoll_fd, ep, ARRAY_LENGTH(ep), ctx->timeout);
2177 	if (count < 0)
2178 		return -errno;
2179 
2180 	for (i = 0; i < count; ++i) {
2181 		source = ep[i].data.ptr;
2182 		if (source->fd == -1)
2183 			continue;
2184 		source->dispatch(ctx, source->fd, source->user_data);
2185 	}
2186 
2187 	return count;
2188 }
2189 
2190 static int
mainloop(struct record_context * ctx)2191 mainloop(struct record_context *ctx)
2192 {
2193 	bool autorestart = (ctx->timeout > 0);
2194 	struct source *source;
2195 	struct record_device *d = NULL;
2196 	sigset_t mask;
2197 	int sigfd, timerfd;
2198 
2199 	assert(ctx->timeout != 0);
2200 	assert(!list_empty(&ctx->devices));
2201 
2202 	ctx->epoll_fd = epoll_create1(0);
2203 	assert(ctx->epoll_fd >= 0);
2204 
2205 	sigemptyset(&mask);
2206 	sigaddset(&mask, SIGINT);
2207 	sigaddset(&mask, SIGQUIT);
2208 	sigprocmask(SIG_BLOCK, &mask, NULL);
2209 
2210 	sigfd = signalfd(-1, &mask, SFD_NONBLOCK);
2211 	add_source(ctx, sigfd, signalfd_dispatch, NULL);
2212 
2213 	timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC|TFD_NONBLOCK);
2214 	add_source(ctx, timerfd, timefd_dispatch, NULL);
2215 	arm_timer(timerfd);
2216 
2217 	list_for_each(d, &ctx->devices, link) {
2218 		struct hidraw *hidraw;
2219 
2220 		add_source(ctx, libevdev_get_fd(d->evdev), evdev_dispatch, d);
2221 
2222 		list_for_each(hidraw, &d->hidraw_devices, link) {
2223 			add_source(ctx, hidraw->fd, hidraw_dispatch, hidraw);
2224 		}
2225 	}
2226 
2227 	if (ctx->libinput) {
2228 		/* See the note in the dispatch function */
2229 		add_source(ctx,
2230 			   libinput_get_fd(ctx->libinput),
2231 			   libinput_ctx_dispatch,
2232 			   NULL);
2233 	}
2234 
2235 	/* If we have more than one device, the time starts at recording
2236 	 * start time. Otherwise, the first event starts the recording time.
2237 	 */
2238 	if (ctx->ndevices > 1) {
2239 		struct timespec ts;
2240 
2241 		clock_gettime(CLOCK_MONOTONIC, &ts);
2242 		ctx->offset = s2us(ts.tv_sec) + ns2us(ts.tv_nsec);
2243 	}
2244 
2245 	do {
2246 		struct record_device *d;
2247 
2248 		if (!open_output_files(ctx, autorestart)) {
2249 			fprintf(stderr,
2250 				"Failed to open '%s'\n",
2251 				ctx->output_file.name_with_suffix);
2252 			break;
2253 		}
2254 		fprintf(stderr, "%sRecording to '%s'.\n",
2255 			isatty(STDERR_FILENO) ? "" : "# ",
2256 			ctx->output_file.name_with_suffix);
2257 
2258 		ctx->had_events = false;
2259 
2260 		print_header(ctx->first_device->fp, ctx);
2261 		if (autorestart)
2262 			iprintf(ctx->first_device->fp,
2263 				I_NONE,
2264 				"# Autorestart timeout: %d\n",
2265 				ctx->timeout);
2266 
2267 		iprintf(ctx->first_device->fp, I_TOPLEVEL, "devices:\n");
2268 
2269 		/* we only print the first device's description, the
2270 		 * rest is assembled after CTRL+C */
2271 		list_for_each(d, &ctx->devices, link) {
2272 			print_device_description(d);
2273 			iprintf(d->fp, I_DEVICE, "events:\n");
2274 		}
2275 		print_wall_time(ctx);
2276 
2277 		if (ctx->libinput) {
2278 			libinput_dispatch(ctx->libinput);
2279 			handle_libinput_events(ctx, ctx->first_device, true);
2280 		}
2281 
2282 		while (true) {
2283 			int rc = dispatch_sources(ctx);
2284 			if (rc < 0) { /* error */
2285 				fprintf(stderr, "Error: %s\n", strerror(-rc));
2286 				ctx->stop = true;
2287 				break;
2288 			}
2289 
2290 			/* set by the signalfd handler */
2291 			if (ctx->stop)
2292 				break;
2293 
2294 			if (rc == 0) {
2295 				fprintf(stderr,
2296 					" ... timeout%s\n",
2297 					ctx->had_events ? "" : " (file is empty)");
2298 				break;
2299 
2300 			}
2301 
2302 			if (ctx->first_device->fp != stdout)
2303 				print_progress_bar();
2304 
2305 		}
2306 
2307 		if (autorestart) {
2308 			list_for_each(d, &ctx->devices, link) {
2309 				iprintf(d->fp,
2310 					I_NONE,
2311 					"# Closing after %ds inactivity",
2312 					ctx->timeout/1000);
2313 			}
2314 		}
2315 
2316 		/* First device is printed, now append all the data from the
2317 		 * other devices, if any */
2318 		list_for_each(d, &ctx->devices, link) {
2319 			char buf[4096];
2320 			size_t n;
2321 
2322 			if (d == ctx->first_device)
2323 				continue;
2324 
2325 			rewind(d->fp);
2326 			do {
2327 
2328 				n = fread(buf, 1, sizeof(buf), d->fp);
2329 				if (n > 0)
2330 					fwrite(buf, 1, n, ctx->first_device->fp);
2331 			} while (n == sizeof(buf));
2332 
2333 			fclose(d->fp);
2334 			d->fp = NULL;
2335 		}
2336 
2337 		/* If we didn't have events, delete the file. */
2338 		if (!isatty(fileno(ctx->first_device->fp))) {
2339 			struct record_device *d;
2340 
2341 			if (!ctx->had_events && ctx->output_file.name_with_suffix) {
2342 				fprintf(stderr,
2343 					"No events recorded, deleting '%s'\n",
2344 					ctx->output_file.name_with_suffix);
2345 				unlink(ctx->output_file.name_with_suffix);
2346 			}
2347 
2348 			list_for_each(d, &ctx->devices, link) {
2349 				if (d->fp && d->fp != stdout) {
2350 					fclose(d->fp);
2351 					d->fp = NULL;
2352 				}
2353 			}
2354 		}
2355 		free(ctx->output_file.name_with_suffix);
2356 		ctx->output_file.name_with_suffix = NULL;
2357 	} while (autorestart && !ctx->stop);
2358 
2359 	sigprocmask(SIG_UNBLOCK, &mask, NULL);
2360 
2361 	list_for_each_safe(source, &ctx->sources, link) {
2362 		destroy_source(ctx, source);
2363 	}
2364 	close(ctx->epoll_fd);
2365 
2366 	return 0;
2367 }
2368 
2369 static bool
init_device(struct record_context * ctx,const char * path,bool grab)2370 init_device(struct record_context *ctx, const char *path, bool grab)
2371 {
2372 	struct record_device *d;
2373 	int fd, rc;
2374 
2375 	d = zalloc(sizeof(*d));
2376 	d->ctx = ctx;
2377 	d->devnode = safe_strdup(path);
2378 
2379 	list_init(&d->hidraw_devices);
2380 
2381 	fd = open(d->devnode, O_RDONLY|O_NONBLOCK);
2382 	if (fd < 0) {
2383 		fprintf(stderr,
2384 			"Failed to open device %s (%m)\n",
2385 			d->devnode);
2386 		goto error;
2387 	}
2388 
2389 	rc = libevdev_new_from_fd(fd, &d->evdev);
2390 	if (rc == 0)
2391 		rc = libevdev_new_from_fd(fd, &d->evdev_prev);
2392 	if (rc != 0) {
2393 		fprintf(stderr,
2394 			"Failed to create context for %s (%s)\n",
2395 			d->devnode,
2396 			strerror(-rc));
2397 		goto error;
2398 	}
2399 
2400 	if (grab) {
2401 		rc = libevdev_grab(d->evdev, LIBEVDEV_GRAB);
2402 		if (rc != 0) {
2403 			fprintf(stderr,
2404 				"Grab failed on %s: %s\n",
2405 				path,
2406 				strerror(-rc));
2407 			goto error;
2408 		}
2409 	}
2410 
2411 	libevdev_set_clock_id(d->evdev, CLOCK_MONOTONIC);
2412 
2413 	if (libevdev_get_num_slots(d->evdev) > 0)
2414 		d->touch.is_touch_device = true;
2415 
2416 	list_append(&ctx->devices, &d->link);
2417 	if (!ctx->first_device)
2418 		ctx->first_device = d;
2419 	ctx->ndevices++;
2420 
2421 	return true;
2422 error:
2423 	close(fd);
2424 	free(d);
2425 	return false;
2426 
2427 }
2428 static int
open_restricted(const char * path,int flags,void * user_data)2429 open_restricted(const char *path, int flags, void *user_data)
2430 {
2431 	int fd = open(path, flags);
2432 	return fd == -1 ? -errno : fd;
2433 }
2434 
close_restricted(int fd,void * user_data)2435 static void close_restricted(int fd, void *user_data)
2436 {
2437 	close(fd);
2438 }
2439 
2440 const struct libinput_interface interface = {
2441 	.open_restricted = open_restricted,
2442 	.close_restricted = close_restricted,
2443 };
2444 
2445 static bool
init_libinput(struct record_context * ctx)2446 init_libinput(struct record_context *ctx)
2447 {
2448 	struct record_device *dev;
2449 	struct libinput *li;
2450 
2451 	li = libinput_path_create_context(&interface, NULL);
2452 	if (li == NULL) {
2453 		fprintf(stderr,
2454 			"Failed to create libinput context\n");
2455 		return false;
2456 	}
2457 
2458 	ctx->libinput = li;
2459 
2460 	list_for_each(dev, &ctx->devices, link) {
2461 		struct libinput_device *d;
2462 
2463 		d = libinput_path_add_device(li, dev->devnode);
2464 		if (!d) {
2465 			fprintf(stderr,
2466 				"Failed to add device %s\n",
2467 				dev->devnode);
2468 			continue;
2469 		}
2470 		dev->device = libinput_device_ref(d);
2471 		/* FIXME: this needs to be a commandline option */
2472 		libinput_device_config_tap_set_enabled(d,
2473 					       LIBINPUT_CONFIG_TAP_ENABLED);
2474 	}
2475 
2476 	return true;
2477 }
2478 
2479 static bool
init_hidraw(struct record_context * ctx)2480 init_hidraw(struct record_context *ctx)
2481 {
2482 	struct record_device *dev;
2483 
2484 	list_for_each(dev, &ctx->devices, link) {
2485 		char syspath[PATH_MAX];
2486 		DIR *dir;
2487 		struct dirent *entry;
2488 
2489 		snprintf(syspath,
2490 			 sizeof(syspath),
2491 			 "/sys/class/input/%s/device/device/hidraw",
2492 			 safe_basename(dev->devnode));
2493 		dir = opendir(syspath);
2494 		if (!dir)
2495 			continue;
2496 
2497 		while ((entry = readdir(dir))) {
2498 			char hidraw_node[PATH_MAX];
2499 			int fd;
2500 			struct hidraw *hidraw = NULL;
2501 
2502 			if (!strstartswith(entry->d_name, "hidraw"))
2503 				continue;
2504 
2505 			snprintf(hidraw_node,
2506 				 sizeof(hidraw_node),
2507 				 "/dev/%s",
2508 				 entry->d_name);
2509 			fd = open(hidraw_node, O_RDONLY|O_NONBLOCK);
2510 			if (fd == -1)
2511 				continue;
2512 
2513 			hidraw = zalloc(sizeof(*hidraw));
2514 			hidraw->fd = fd;
2515 			hidraw->name = safe_strdup(entry->d_name);
2516 			hidraw->device = dev;
2517 			list_insert(&dev->hidraw_devices, &hidraw->link);
2518 		}
2519 		closedir(dir);
2520 	}
2521 
2522 	return true;
2523 }
2524 
2525 static void
usage(void)2526 usage(void)
2527 {
2528 	printf("Usage: %s [--help] [--all] [--autorestart] [--output-file filename] [/dev/input/event0] [...]\n"
2529 	       "Common use-cases:\n"
2530 	       "\n"
2531 	       " sudo %s -o recording.yml\n"
2532 	       "    Then select the device to record and it Ctrl+C to stop.\n"
2533 	       "    The recorded data is in recording.yml and can be attached to a bug report.\n"
2534 	       "\n"
2535 	       " sudo %s -o recording.yml --autorestart 2\n"
2536 	       "    As above, but restarts after 2s of inactivity on the device.\n"
2537 	       "    Note, the output file is only the prefix.\n"
2538 	       "\n"
2539 	       " sudo %s -o recording.yml /dev/input/event3 /dev/input/event4\n"
2540 	       "    Records the two devices into the same recordings file.\n"
2541 	       "\n"
2542 	       "For more information, see the %s(1) man page\n",
2543 	       program_invocation_short_name,
2544 	       program_invocation_short_name,
2545 	       program_invocation_short_name,
2546 	       program_invocation_short_name,
2547 	       program_invocation_short_name);
2548 }
2549 
2550 enum ftype {
2551 	F_FILE = 8,
2552 	F_DEVICE,
2553 	F_NOEXIST,
2554 };
2555 
2556 static enum ftype
is_char_dev(const char * path)2557 is_char_dev(const char *path)
2558 {
2559 	struct stat st;
2560 
2561 	if (strneq(path, "/dev", 4))
2562 		return F_DEVICE;
2563 
2564 	if (stat(path, &st) != 0) {
2565 		if (errno == ENOENT)
2566 			return F_NOEXIST;
2567 		return F_FILE;
2568 	}
2569 
2570 	return S_ISCHR(st.st_mode) ? F_DEVICE : F_FILE;
2571 }
2572 
2573 enum fposition {
2574 	ERROR,
2575 	NOFILE,
2576 	FIRST,
2577 	LAST,
2578 };
2579 
2580 static enum fposition
find_output_file(int argc,char * argv[],const char ** output_file)2581 find_output_file(int argc, char *argv[], const char **output_file)
2582 {
2583 	char *first, *last;
2584 	enum ftype ftype_first, ftype_last;
2585 
2586 	first = argv[0];
2587 
2588 	ftype_first = is_char_dev(first);
2589 	if (argc == 1) {
2590 		/* arg is *not* a char device, so let's assume it's
2591 		 * the output file */
2592 		if (ftype_first != F_DEVICE) {
2593 			*output_file = first;
2594 			return FIRST;
2595 		}
2596 	}
2597 
2598 	/* multiple arguments, yay */
2599 	last = argv[argc - 1];
2600 	ftype_last = is_char_dev(last);
2601 	/*
2602 	   first is device, last is file -> last
2603 	   first is device, last is device -> noop
2604 	   first is device, last !exist -> last
2605 	   first is file, last is device -> first
2606 	   first is file, last is file -> error
2607 	   first is file, last !exist -> error
2608 	   first !exist, last is device -> first
2609 	   first !exist, last is file -> error
2610 	   first !exit, last !exist -> error
2611 	 */
2612 #define _m(f, l) (((f) << 8) | (l))
2613 	switch (_m(ftype_first, ftype_last)) {
2614 	case _m(F_FILE,    F_DEVICE):
2615 	case _m(F_FILE,    F_NOEXIST):
2616 	case _m(F_NOEXIST, F_DEVICE):
2617 		*output_file = first;
2618 		return FIRST;
2619 	case _m(F_DEVICE,  F_FILE):
2620 	case _m(F_DEVICE,  F_NOEXIST):
2621 		*output_file = last;
2622 		return LAST;
2623 	case _m(F_DEVICE,  F_DEVICE):
2624 		break;
2625 	case _m(F_FILE,    F_FILE):
2626 	case _m(F_NOEXIST, F_FILE):
2627 	case _m(F_NOEXIST, F_NOEXIST):
2628 		return ERROR;
2629 	}
2630 #undef _m
2631 	return NOFILE;
2632 }
2633 
2634 enum options {
2635 	OPT_AUTORESTART,
2636 	OPT_HELP,
2637 	OPT_OUTFILE,
2638 	OPT_KEYCODES,
2639 	OPT_MULTIPLE,
2640 	OPT_ALL,
2641 	OPT_LIBINPUT,
2642 	OPT_HIDRAW,
2643 	OPT_GRAB,
2644 };
2645 
2646 int
main(int argc,char ** argv)2647 main(int argc, char **argv)
2648 {
2649 	struct record_context ctx = {
2650 		.timeout = -1,
2651 		.show_keycodes = false,
2652 	};
2653 	struct option opts[] = {
2654 		{ "autorestart", required_argument, 0, OPT_AUTORESTART },
2655 		{ "output-file", required_argument, 0, OPT_OUTFILE },
2656 		{ "show-keycodes", no_argument, 0, OPT_KEYCODES },
2657 		{ "multiple", no_argument, 0, OPT_MULTIPLE },
2658 		{ "all", no_argument, 0, OPT_ALL },
2659 		{ "help", no_argument, 0, OPT_HELP },
2660 		{ "with-libinput", no_argument, 0, OPT_LIBINPUT },
2661 		{ "with-hidraw", no_argument, 0, OPT_HIDRAW },
2662 		{ "grab", no_argument, 0, OPT_GRAB },
2663 		{ 0, 0, 0, 0 },
2664 	};
2665 	struct record_device *d;
2666 	const char *output_arg = NULL;
2667 	bool all = false,
2668 	     with_libinput = false,
2669 	     with_hidraw = false,
2670 	     grab = false;
2671 	int ndevices;
2672 	int rc = EXIT_FAILURE;
2673 	char **paths = NULL;
2674 
2675 	list_init(&ctx.devices);
2676 	list_init(&ctx.sources);
2677 
2678 	while (1) {
2679 		int c;
2680 		int option_index = 0;
2681 
2682 		c = getopt_long(argc, argv, "ho:", opts, &option_index);
2683 		if (c == -1)
2684 			break;
2685 
2686 		switch (c) {
2687 		case 'h':
2688 		case OPT_HELP:
2689 			usage();
2690 			rc = EXIT_SUCCESS;
2691 			goto out;
2692 		case OPT_AUTORESTART:
2693 			if (!safe_atoi(optarg, &ctx.timeout) ||
2694 			    ctx.timeout <= 0) {
2695 				usage();
2696 				rc = EXIT_INVALID_USAGE;
2697 				goto out;
2698 			}
2699 			ctx.timeout = ctx.timeout * 1000;
2700 			break;
2701 		case 'o':
2702 		case OPT_OUTFILE:
2703 			output_arg = optarg;
2704 			break;
2705 		case OPT_KEYCODES:
2706 			ctx.show_keycodes = true;
2707 			break;
2708 		case OPT_MULTIPLE: /* deprecated */
2709 			break;
2710 		case OPT_ALL:
2711 			all = true;
2712 			break;
2713 		case OPT_LIBINPUT:
2714 			with_libinput = true;
2715 			break;
2716 		case OPT_HIDRAW:
2717 			with_hidraw = true;
2718 			fprintf(stderr, "# WARNING: do not type passwords while recording HID reports\n");
2719 			break;
2720 		case OPT_GRAB:
2721 			grab = true;
2722 			break;
2723 		default:
2724 			usage();
2725 			rc = EXIT_INVALID_USAGE;
2726 			goto out;
2727 		}
2728 	}
2729 
2730 	ndevices = argc - optind;
2731 
2732 	/* We allow for multiple arguments after the options, *one* of which
2733 	 * may be the output file. That one must be the first or the last to
2734 	 * prevent users from running
2735 	 *   libinput record /dev/input/event0 output.yml /dev/input/event1
2736 	 * because this will only backfire anyway.
2737 	 */
2738 	if (ndevices >= 1 && output_arg == NULL) {
2739 		enum fposition pos = find_output_file(argc - optind,
2740 						      &argv[optind],
2741 						      &output_arg);
2742 		if (pos == ERROR) {
2743 			fprintf(stderr,
2744 				"Ambiguous device vs output file list. "
2745 				"Please use --output-file.\n");
2746 			return EXIT_INVALID_USAGE;
2747 		}
2748 
2749 		if (pos == FIRST || pos == LAST)
2750 			ndevices--;
2751 		if (pos == FIRST)
2752 			optind++;
2753 	}
2754 
2755 	if (ctx.timeout > 0 && output_arg == NULL) {
2756 		fprintf(stderr,
2757 			"Option --autorestart requires --output-file\n");
2758 		rc = EXIT_INVALID_USAGE;
2759 		goto out;
2760 	}
2761 
2762 	ctx.output_file.name = safe_strdup(output_arg);
2763 
2764 	if (output_arg == NULL && (all || ndevices > 1)) {
2765 		fprintf(stderr,
2766 			"Recording multiple devices requires an output file\n");
2767 		rc = EXIT_INVALID_USAGE;
2768 		goto out;
2769 	}
2770 
2771 	/* Now collect all device paths and init our device struct */
2772 	if (all) {
2773 		paths = all_devices();
2774 	} else if (ndevices >= 1) {
2775 		paths = strv_from_argv(ndevices, &argv[optind]);
2776 	} else {
2777 		char *path = select_device();
2778 		if (path == NULL) {
2779 			goto out;
2780 		}
2781 
2782 		paths = strv_from_argv(1, &path);
2783 		free(path);
2784 	}
2785 
2786 	for (char **p = paths; *p; p++) {
2787 		if (!init_device(&ctx, *p, grab)) {
2788 			goto out;
2789 		}
2790 	}
2791 
2792 	if (with_libinput && !init_libinput(&ctx))
2793 		goto out;
2794 
2795 	if (with_hidraw && !init_hidraw(&ctx))
2796 		goto out;
2797 
2798 	rc = mainloop(&ctx);
2799 out:
2800 	strv_free(paths);
2801 	list_for_each_safe(d, &ctx.devices, link) {
2802 		struct hidraw *hidraw;
2803 
2804 		list_for_each_safe(hidraw, &d->hidraw_devices, link) {
2805 			close(hidraw->fd);
2806 			list_remove(&hidraw->link);
2807 			free(hidraw->name);
2808 			free(hidraw);
2809 		}
2810 
2811 		if (d->device)
2812 			libinput_device_unref(d->device);
2813 		free(d->devnode);
2814 		libevdev_free(d->evdev);
2815 	}
2816 
2817 	libinput_unref(ctx.libinput);
2818 
2819 	return rc;
2820 }
2821