[RFC libevdev] Enable event logging for debugging

Peter Hutterer peter.hutterer at who-t.net
Thu Apr 3 03:30:16 PDT 2014


This is a new approach to an earlier patch [1]. I'm running into more
use-cases where I really need the event sequence the caller sees to figure
out where the bug is. Note that the patch is just lightly tested, this is an
early RFC.

I'll just copy the documentation here, that explains what I'm trying to do:

+ * libevdev checks the LIBEVDEV_LOG_EVENTS environment variable. If set to
+ * "error", "info", or "debug", all events are logged with the respective
+ * priority before they are passed to the client. This is useful to check
+ * event sequences that happen before a specific bug in the higher layers of
+ * the stack
+ *
+ * To debug specific devices only, the minor numbers of the device node may
+ * be provided as a comma-separated list after the priority:
+ * LIBEVDEV_LOG_EVENTS="error:1,2,3" logs all events from the devices with a
+ * minor number 1, 2 or 3. The minor number comparison is performed on
+ * libevdev_set_fd() and libevdev_change_fd().
+ *
+ * Since event logged by libevdev are likely to end up in some files and are
+ * potentially attached to public bug reports, key event codes are
+ * obfuscated to protect accidental leakage of private information. Key
+ * codes between KEY_ESC up to including KEY_STOP are always logged as
+ * "OBFUSCATED".
+ *

This should address some of the comments on the previous revision. It makes
it easier to debug a specific device only to cut down on the log spam. And
some of the security issues are alleviated by obfuscating key codes (I also
need to do this for MSC_SCAN) so that a password doesn't accidentally end up
in bugzilla somewhere.

Comments?

[1] http://lists.freedesktop.org/archives/input-tools/2014-March/000825.html
---
 libevdev/libevdev-int.h |  3 ++
 libevdev/libevdev.c     | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
 libevdev/libevdev.h     | 20 +++++++++++
 3 files changed, 111 insertions(+)

diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h
index 98c75ce..16aeeb7 100644
--- a/libevdev/libevdev-int.h
+++ b/libevdev/libevdev-int.h
@@ -64,6 +64,7 @@ struct mt_sync_state {
 struct libevdev {
 	int fd;
 	bool initialized;
+
 	char *name;
 	char *phys;
 	char *uniq;
@@ -107,6 +108,8 @@ struct libevdev {
 		unsigned long *tracking_id_changes;
 		size_t tracking_id_changes_sz;	 /* in bytes */
 	} mt_sync;
+
+	enum libevdev_log_priority event_logging_priority;
 };
 
 struct logdata {
diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
index 96bd41b..cc8cc62 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -22,12 +22,14 @@
 
 #include <config.h>
 #include <errno.h>
+#include <limits.h>
 #include <poll.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <sys/stat.h>
 
 #include "libevdev.h"
 #include "libevdev-int.h"
@@ -44,6 +46,32 @@ enum event_filter_status {
 
 static int sync_mt_state(struct libevdev *dev, int create_events);
 
+static inline void
+log_event(struct libevdev *dev, int flags, const struct input_event *ev)
+{
+	const char *mode;
+	const char *type, *code;
+
+	if (dev->event_logging_priority == 0)
+		return;
+
+	if (flags & LIBEVDEV_READ_FLAG_SYNC)
+		mode = "S";
+	else if (flags & LIBEVDEV_READ_FLAG_NORMAL)
+		mode = "N";
+	else
+		mode = "I";
+
+	type = libevdev_event_type_get_name(ev->type);
+	if (ev->type == EV_KEY && ev->code < KEY_STOP)
+		code = "OBFUSCATED";
+	else
+		code = libevdev_event_code_get_name(ev->type, ev->code);
+
+	log_msg_cond(dev->event_logging_priority, "EVENT(%s): %s %s %d\n",
+		     mode, type, code, ev->value);
+}
+
 static inline int*
 slot_value(const struct libevdev *dev, int slot, int axis)
 {
@@ -235,6 +263,55 @@ libevdev_get_log_priority(void)
 	return log_data.priority;
 }
 
+static void
+enable_event_logging(struct libevdev *dev)
+{
+	enum libevdev_log_priority pri = 0;
+	const char *env = getenv("LIBEVDEV_LOG_EVENTS");
+	const char *sep;
+	int device_minor;
+	long int minor;
+	char *endptr;
+	struct stat st;
+
+	if (!env || fstat(dev->fd, &st) == -1)
+		goto out;
+
+	device_minor= minor(st.st_rdev);
+
+	if (strncmp(env, "error", 5) == 0)
+		pri = LIBEVDEV_LOG_ERROR;
+	else if (strncmp(env, "info", 4) == 0)
+		pri = LIBEVDEV_LOG_INFO;
+	else if (strncmp(env, "debug", 5) == 0)
+		pri = LIBEVDEV_LOG_DEBUG;
+	else
+		goto out;
+
+	if ((sep = strchr(env, ':')) == NULL || sep[1] == '\0')
+	    goto out;
+
+	sep++;
+	do {
+		minor = strtol(sep, &endptr, 10);
+		if (endptr == sep || minor < 0 ||
+		    minor == LONG_MIN || minor == LONG_MAX)
+			goto out;
+
+		if (minor == device_minor)
+			goto out;
+		if (*endptr == ',')
+			sep = endptr + 1;
+		else if (*endptr != '\0')
+			break;
+	} while(*endptr != '\0' && *sep != '\0');
+
+	return;
+
+out:
+	dev->event_logging_priority = pri;
+}
+
 LIBEVDEV_EXPORT int
 libevdev_change_fd(struct libevdev *dev, int fd)
 {
@@ -242,7 +319,11 @@ libevdev_change_fd(struct libevdev *dev, int fd)
 		log_bug("device not initialized. call libevdev_set_fd() first\n");
 		return -1;
 	}
+
 	dev->fd = fd;
+
+	enable_event_logging(dev);
+
 	return 0;
 }
 
@@ -390,6 +471,8 @@ libevdev_set_fd(struct libevdev* dev, int fd)
 
 	dev->fd = fd;
 
+	enable_event_logging(dev);
+
 	/* devices with ABS_MT_SLOT - 1 aren't MT devices,
 	   see the documentation for multitouch-related
 	   functions for more details */
@@ -957,6 +1040,9 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
 		   of the device too */
 		while (queue_shift(dev, &e) == 0) {
 			dev->queue_nsync--;
+
+			log_event(dev, 0, ev);
+
 			if (sanitize_event(dev, &e, dev->sync_state) != EVENT_FILTER_DISCARD)
 				update_state(dev, &e);
 		}
@@ -988,6 +1074,8 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
 		if (queue_shift(dev, ev) != 0)
 			return -EAGAIN;
 
+		log_event(dev, flags, ev);
+
 		filter_status = sanitize_event(dev, ev, dev->sync_state);
 		if (filter_status != EVENT_FILTER_DISCARD)
 			update_state(dev, ev);
diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
index aa7b90d..b4cd2e4 100644
--- a/libevdev/libevdev.h
+++ b/libevdev/libevdev.h
@@ -151,6 +151,26 @@ extern "C" {
  * libevdev is licensed under the
  * [X11 license](http://cgit.freedesktop.org/libevdev/tree/COPYING).
  *
+ * Debugging
+ * =========
+ * libevdev checks the LIBEVDEV_LOG_EVENTS environment variable. If set to
+ * "error", "info", or "debug", all events are logged with the respective
+ * priority before they are passed to the client. This is useful to check
+ * event sequences that happen before a specific bug in the higher layers of
+ * the stack
+ *
+ * To debug specific devices only, the minor numbers of the device node may
+ * be provided as a comma-separated list after the priority:
+ * LIBEVDEV_LOG_EVENTS="error:1,2,3" logs all events from the devices with a
+ * minor number 1, 2 or 3. The minor number comparison is performed on
+ * libevdev_set_fd() and libevdev_change_fd().
+ *
+ * Since event logged by libevdev are likely to end up in some files and are
+ * potentially attached to public bug reports, key event codes are
+ * obfuscated to protect accidental leakage of private information. Key
+ * codes between KEY_ESC up to including KEY_STOP are always logged as
+ * "OBFUSCATED".
+ *
  * Reporting bugs
  * ==============
  * Please report bugs in the freedesktop.org bugzilla under the libevdev product:
-- 
1.9.0



More information about the Input-tools mailing list