diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2016-03-01 10:49:23 +1000 |
---|---|---|
committer | Benjamin Tissoires <benjamin.tissoires@gmail.com> | 2016-03-01 15:10:24 +0100 |
commit | 6eeb5474affe6a88fafa2e23332844f813d52024 (patch) | |
tree | 1a903e0bfeae8fa58ad5206b07cdab88c27e8349 | |
parent | 3974486d689d71fad0255be9e309ca2c758a2aeb (diff) |
evemu-record: add support for --autorestart to cycle buffers
Uses the existing evemu timeout feature where evemu_record() quits after a
given timeout. A call of
evemu-record --autorestart 10 /dev/input/event4 scroll.evemu
will use the filename as prefix and create a timestamped output file (e.g.
scroll.evemu.2016-02-25-09:13). Until the 10s inactivity timeout is hit, all
events are recorded to that file. After that, the file is closed with a note
at the bottom and a new file is started.
This enables a user to leave evemu running in the background for a prolonged
time and recover the most recent recording after triggering a bug without
having to wade through three days of recordings.
https://bugs.freedesktop.org/show_bug.cgi?id=93752
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
-rw-r--r-- | tools/evemu-describe.txt | 11 | ||||
-rw-r--r-- | tools/evemu-record.c | 186 |
2 files changed, 179 insertions, 18 deletions
diff --git a/tools/evemu-describe.txt b/tools/evemu-describe.txt index 8102eb1..2d9b7b7 100644 --- a/tools/evemu-describe.txt +++ b/tools/evemu-describe.txt @@ -11,7 +11,7 @@ SYNOPSIS -------- evemu-describe [/dev/input/eventX] [output file] - evemu-record [/dev/input/eventX] [output file] + evemu-record [--autorestart=s] [/dev/input/eventX] [output file] DESCRIPTION ----------- @@ -32,6 +32,15 @@ devices. If no output file is given, stdout is used. +OPTIONS +------- + + --autorestart=<s> + Terminate the curent recording after <s> seconds of device + inactivity. This option requires an output, the file is suffixed + with the date and time of the recording's start. + The timeout must be greater than 0. + DIAGNOSTICS ----------- If evtest-record does not see any events even though the device is being diff --git a/tools/evemu-record.c b/tools/evemu-record.c index abf8ffe..433e224 100644 --- a/tools/evemu-record.c +++ b/tools/evemu-record.c @@ -41,6 +41,9 @@ #define _GNU_SOURCE #include "evemu.h" +#include <assert.h> +#include <getopt.h> +#include <limits.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -55,6 +58,7 @@ #define INFINITE -1 FILE *output; +bool autorestart = false; static int describe_device(FILE *output, int fd) { @@ -82,6 +86,120 @@ static void handler (int sig __attribute__((unused))) fclose(output); output = stdout; } + autorestart = false; +} + +static inline bool safe_atoi(const char *str, int *val) +{ + char *endptr; + long v; + + v = strtol(str, &endptr, 10); + if (str == endptr) + return false; + if (*str != '\0' && *endptr != '\0') + return false; + + if (v > INT_MAX || v < INT_MIN) + return false; + + *val = v; + return true; +} + +static inline void usage() +{ + fprintf(stderr, "Usage: %s [--autorestart=s] <device> [output file]\n", + program_invocation_short_name); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " --autorestart=s\n"); + fprintf(stderr, " Terminate the current recording after <s> seconds\n" + " of inactivity and restart a new recording. This option requires\n" + " an output file, the file is suffixed with the date and time of \n" + " the recording's start.\n" + " The timeout must be greater than 0.\n" + " This option is only valid for evemu-record.\n"); +} + +static inline char* make_filename(const char *prefix) +{ + char *filename; + struct tm *tm; + time_t t; + int rc; + char buf[64]; + + t = time(NULL); + tm = localtime(&t); + rc = strftime(buf, sizeof(buf), "%F-%T", tm); + if (rc < 0) + return NULL; + + rc = asprintf(&filename, "%s.%s", prefix, buf); + if (rc < 0) + return NULL; + + return filename; +} + +static bool record_device(int fd, unsigned int timeout, const char *prefix) +{ + char *filename = NULL; + bool rc = false; + + assert(!autorestart || prefix != NULL); + + do { + free(filename); + + if (prefix == NULL) { + output = stdout; + } else { + if (autorestart) + filename = make_filename(prefix); + else + filename = strdup(prefix); + if (filename == NULL) { + fprintf(stderr, "error: failed to init the filename\n"); + goto out; + } + output = fopen(filename, "w"); + if (!output) { + fprintf(stderr, "error: could not open output file (%m)"); + goto out; + } + } + + if (describe_device(output, fd)) { + fprintf(stderr, "error: could not describe device\n"); + goto out; + } + + fprintf(output, "################################\n"); + fprintf(output, "# Waiting for events #\n"); + fprintf(output, "################################\n"); + if (autorestart) + fprintf(output, "# Autorestart timeout: %d\n", timeout); + + if (evemu_record(output, fd, timeout)) { + fprintf(stderr, "error: could not record device\n"); + } else if (autorestart) { + fprintf(output, "# Closing after %ds inactivity\n", + timeout/1000); + } + + fflush(output); + if (output != stdout) { + fclose(output); + output = stdout; + } + } while (autorestart); + + rc = true; + +out: + free(filename); + return rc; } static inline bool test_grab_device(int fd) @@ -102,6 +220,10 @@ enum mode { EVEMU_DESCRIBE }; +enum options { + OPT_AUTORESTART, +}; + int main(int argc, char *argv[]) { enum mode mode = EVEMU_RECORD; @@ -109,6 +231,12 @@ int main(int argc, char *argv[]) struct sigaction act; char *prgm_name = program_invocation_short_name; char *device = NULL; + int timeout = INFINITE; + struct option opts[] = { + { "autorestart", required_argument, 0, OPT_AUTORESTART }, + { 0, 0, 0, 0}, + }; + const char *prefix = NULL; int rc = 1; output = stdout; @@ -118,10 +246,34 @@ int main(int argc, char *argv[]) strcmp(prgm_name, "lt-evemu-describe") == 0)) mode = EVEMU_DESCRIBE; - device = (argc < 2) ? find_event_devices() : strdup(argv[1]); + while (1) { + int c; + int option_index = 0; + + c = getopt_long(argc, argv, "", opts, &option_index); + if (c == -1) + break; + + switch (c) { + case OPT_AUTORESTART: + if (!safe_atoi(optarg, &timeout) || + timeout <= 0) { + usage(); + goto out; + } + timeout *= 1000; /* sec to ms */ + autorestart = true; + break; + default: + usage(); + goto out; + } + } + + device = (optind >= argc) ? find_event_devices() : strdup(argv[optind++]); if (device == NULL) { - fprintf(stderr, "Usage: %s <device> [output file]\n", argv[0]); + usage(); goto out; } fd = open(device, O_RDONLY | O_NONBLOCK); @@ -142,13 +294,13 @@ int main(int argc, char *argv[]) goto out; } - if (argc < 3) - output = stdout; - else { - output = fopen(argv[2], "w"); - if (!output) { - fprintf(stderr, "error: could not open output file (%m)"); + if (optind >= argc) { + if (autorestart) { + fprintf(stderr, "Option --autoresume requires an output file\n"); + goto out; } + } else { + prefix = argv[optind++]; } if (mode == EVEMU_RECORD) { @@ -159,17 +311,17 @@ int main(int argc, char *argv[]) if (!test_grab_device(fd)) goto out; - if (describe_device(output, fd)) { - fprintf(stderr, "error: could not describe device\n"); - goto out; - } + record_device(fd, timeout, prefix); - fprintf(output, "################################\n"); - fprintf(output, "# Waiting for events #\n"); - fprintf(output, "################################\n"); - if (evemu_record(output, fd, INFINITE)) - fprintf(stderr, "error: could not record device\n"); } else if (mode == EVEMU_DESCRIBE) { + if (prefix) { + output = fopen(argv[optind++], "w"); + if (!output) { + fprintf(stderr, "error: could not open output file (%m)"); + goto out; + } + } + if (describe_device(output, fd)) { fprintf(stderr, "error: could not describe device\n"); goto out; |