[PATCH evemu 2/3] evemu-record: add support for --autorestart to cycle buffers
Peter Hutterer
peter.hutterer at who-t.net
Fri Feb 26 02:53:00 UTC 2016
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 at who-t.net>
---
tools/evemu-record.c | 194 +++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 172 insertions(+), 22 deletions(-)
diff --git a/tools/evemu-record.c b/tools/evemu-record.c
index bedb659..8a78cd1 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,18 +294,14 @@ 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) {
+ prefix = NULL;
+ if (autorestart) {
+ fprintf(stderr, "Option --autoresume requires an output file\n");
+ goto out;
}
- }
-
- if (describe_device(output, fd)) {
- fprintf(stderr, "error: could not describe device\n");
- goto out;
+ } else {
+ prefix = argv[optind++];
}
if (mode == EVEMU_RECORD) {
@@ -164,17 +312,19 @@ 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 (optind >= argc) {
+ output = stdout;
+ } else {
+ 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;
--
2.5.0
More information about the Input-tools
mailing list