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