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