All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket
@ 2019-08-20 15:18 Cyril Hrubis
  2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

This patchset adds three basic test for uevent netlink socket.

v2:

Finished the input event test, now we match all events.

Cyril Hrubis (5):
  lib/tst_device: Export more functions.
  kernel/uevent: Add uevent01
  kernel/uevent: Add uevent02
  libs/libltpuinput: Add uinput library.
  kernel/uevent: Add uevent03

 include/tst_device.h                |   7 ++
 include/tst_uinput.h                |  31 +++++
 lib/tst_device.c                    |   8 +-
 libs/libltpuinput/Makefile          |  12 ++
 libs/libltpuinput/tst_uinput.c      |  93 +++++++++++++++
 runtest/uevent                      |   3 +
 scenario_groups/default             |   1 +
 testcases/kernel/uevents/.gitignore |   3 +
 testcases/kernel/uevents/Makefile   |  10 ++
 testcases/kernel/uevents/uevent.h   | 176 ++++++++++++++++++++++++++++
 testcases/kernel/uevents/uevent01.c |  90 ++++++++++++++
 testcases/kernel/uevents/uevent02.c | 141 ++++++++++++++++++++++
 testcases/kernel/uevents/uevent03.c |  98 ++++++++++++++++
 13 files changed, 669 insertions(+), 4 deletions(-)
 create mode 100644 include/tst_uinput.h
 create mode 100644 libs/libltpuinput/Makefile
 create mode 100644 libs/libltpuinput/tst_uinput.c
 create mode 100644 runtest/uevent
 create mode 100644 testcases/kernel/uevents/.gitignore
 create mode 100644 testcases/kernel/uevents/Makefile
 create mode 100644 testcases/kernel/uevents/uevent.h
 create mode 100644 testcases/kernel/uevents/uevent01.c
 create mode 100644 testcases/kernel/uevents/uevent02.c
 create mode 100644 testcases/kernel/uevents/uevent03.c

-- 
2.21.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions.
  2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
@ 2019-08-20 15:18 ` Cyril Hrubis
  2019-08-22  9:31   ` Clemens Famulla-Conrad
  2019-08-20 15:18 ` [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01 Cyril Hrubis
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

Export tst_attach_device() and tst_deteach_device() which will be later
on used by a kernel netlink uevent tests.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/tst_device.h | 7 +++++++
 lib/tst_device.c     | 8 ++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/tst_device.h b/include/tst_device.h
index f0ddc3e93..c6e7b45b1 100644
--- a/include/tst_device.h
+++ b/include/tst_device.h
@@ -50,6 +50,13 @@ int tst_clear_device(const char *dev);
  *
  */
 int tst_find_free_loopdev(const char *path, size_t path_len);
+
+
+int tst_attach_device(const char *dev_path, const char *file_path);
+
+
+int tst_detach_device(const char *dev_path);
+
 /*
  * Reads test block device stat file and returns the bytes written since the
  * last call of this function.
diff --git a/lib/tst_device.c b/lib/tst_device.c
index 22abdef46..10f71901d 100644
--- a/lib/tst_device.c
+++ b/lib/tst_device.c
@@ -139,7 +139,7 @@ int tst_find_free_loopdev(char *path, size_t path_len)
 	return -1;
 }
 
-static int attach_device(const char *dev, const char *file)
+int tst_attach_device(const char *dev, const char *file)
 {
 	int dev_fd, file_fd;
 	struct loop_info loopinfo;
@@ -185,7 +185,7 @@ static int attach_device(const char *dev, const char *file)
 	return 0;
 }
 
-static int detach_device(const char *dev)
+int tst_detach_device(const char *dev)
 {
 	int dev_fd, ret, i;
 
@@ -284,7 +284,7 @@ const char *tst_acquire_device__(unsigned int size)
 	if (tst_find_free_loopdev(dev_path, sizeof(dev_path)) == -1)
 		return NULL;
 
-	if (attach_device(dev_path, DEV_FILE))
+	if (tst_attach_device(dev_path, DEV_FILE))
 		return NULL;
 
 	device_acquired = 1;
@@ -329,7 +329,7 @@ int tst_release_device(const char *dev)
 	 *
 	 * The file image is deleted in tst_rmdir();
 	 */
-	ret = detach_device(dev);
+	ret = tst_detach_device(dev);
 
 	device_acquired = 0;
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01
  2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
  2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
@ 2019-08-20 15:18 ` Cyril Hrubis
  2019-08-21 16:35   ` Clemens Famulla-Conrad
  2019-08-20 15:18 ` [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02 Cyril Hrubis
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

Simple test that attached and detaches a file to a loop device and
checks that kernel broadcasts correct events to the kernel uevent
broadcast group.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 runtest/uevent                      |   1 +
 scenario_groups/default             |   1 +
 testcases/kernel/uevents/.gitignore |   1 +
 testcases/kernel/uevents/Makefile   |   6 +
 testcases/kernel/uevents/uevent.h   | 176 ++++++++++++++++++++++++++++
 testcases/kernel/uevents/uevent01.c |  90 ++++++++++++++
 6 files changed, 275 insertions(+)
 create mode 100644 runtest/uevent
 create mode 100644 testcases/kernel/uevents/.gitignore
 create mode 100644 testcases/kernel/uevents/Makefile
 create mode 100644 testcases/kernel/uevents/uevent.h
 create mode 100644 testcases/kernel/uevents/uevent01.c

diff --git a/runtest/uevent b/runtest/uevent
new file mode 100644
index 000000000..e9cdf26b8
--- /dev/null
+++ b/runtest/uevent
@@ -0,0 +1 @@
+uevent01 uevent01
diff --git a/scenario_groups/default b/scenario_groups/default
index 093f5f706..62ae0759d 100644
--- a/scenario_groups/default
+++ b/scenario_groups/default
@@ -29,3 +29,4 @@ input
 cve
 crypto
 kernel_misc
+uevent
diff --git a/testcases/kernel/uevents/.gitignore b/testcases/kernel/uevents/.gitignore
new file mode 100644
index 000000000..53d0b546a
--- /dev/null
+++ b/testcases/kernel/uevents/.gitignore
@@ -0,0 +1 @@
+uevent01
diff --git a/testcases/kernel/uevents/Makefile b/testcases/kernel/uevents/Makefile
new file mode 100644
index 000000000..cba769739
--- /dev/null
+++ b/testcases/kernel/uevents/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir			?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/uevents/uevent.h b/testcases/kernel/uevents/uevent.h
new file mode 100644
index 000000000..2c32dd534
--- /dev/null
+++ b/testcases/kernel/uevents/uevent.h
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef UEVENT_H__
+#define UEVENT_H__
+
+#include "tst_netlink.h"
+
+/*
+ * There are two broadcast groups defined for the NETLINK_KOBJECT_UEVENT. The
+ * primary consument of the KERNEL group is udev which handles the hotplug
+ * events and then, once udev does it's magic the events are rebroadcasted to
+ * the UDEV group which is consumed by various daemons in the userspace.
+ */
+enum monitor_netlink_group {
+	MONITOR_GROUP_NONE,
+	MONITOR_GROUP_KERNEL,
+	MONITOR_GROUP_UDEV,
+};
+
+/*
+ * The messages received from the NETLINK_KOBJECT_UEVENT socket are stored as a
+ * sequence of a null-terminated strings. First in the buffer is a summary of a
+ * action i.e. "$ACTION@$DEVPATH" which is then followed by a bunch of
+ * key-value pairs.
+ *
+ * For example attaching a file to loopback device generates event:
+ *
+ * "change@/devices/virtual/block/loop0\0
+ *  ACTION=change\0
+ *  DEVPATH=/devices/virtual/block/loop0\0
+ *  SUBSYSTEM=block\0
+ *  MAJOR=7\0
+ *  MINOR=0\0
+ *  DEVNAME=loop0\0
+ *  DEVTYPE=disk\0
+ *  SEQNUM=2677\0"
+ */
+
+/*
+ * Prints uevent.
+ */
+static inline void print_uevent(const char *event, int len)
+{
+	int consumed = 0;
+
+	tst_res(TINFO, "Got uevent:");
+
+	while (consumed < len) {
+		tst_res(TINFO, "%s", event);
+		int l = strlen(event) + 1;
+		consumed += l;
+		event += l;
+	}
+}
+
+/*
+ * Uevents read from the socket are matched against this description.
+ *
+ * The msg is the overall action description e.g.
+ * "add@/class/input/input4/mouse1" which has to be matched exactly before we
+ * event attempt to check the key-value pairs stored in the values array. The
+ * event is considered to match if all key-value pairs in the values has been
+ * found in the received event.
+ */
+struct uevent_desc {
+	const char *msg;
+	int value_cnt;
+	const char **values;
+};
+
+static inline int uevent_match(const char *event, int len,
+                               const struct uevent_desc *uevent)
+{
+	int consumed = 0;
+	int val_matches = 0;
+
+	if (memcmp(event, uevent->msg, strlen(uevent->msg)))
+		return 0;
+
+	int l = strlen(event) + 1;
+
+	consumed += l;
+	event += l;
+
+	while (consumed < len) {
+		int i;
+		for (i = 0; i < uevent->value_cnt; i++) {
+			if (!strcmp(event, uevent->values[i])) {
+				val_matches++;
+				break;
+			}
+		}
+
+		l = strlen(event) + 1;
+		consumed += l;
+		event += l;
+	}
+
+	return val_matches == uevent->value_cnt;
+}
+
+static inline int open_uevent_netlink(void)
+{
+	int fd;
+	struct sockaddr_nl nl_addr = {
+		.nl_family = AF_NETLINK,
+		.nl_groups = MONITOR_GROUP_KERNEL,
+	};
+
+	fd = SAFE_SOCKET(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+
+	SAFE_BIND(fd, (struct sockaddr *)&nl_addr, sizeof(nl_addr));
+
+	return fd;
+}
+
+/*
+ * Reads events from uevent netlink socket until all expected events passed in
+ * the uevent array are matched.
+ */
+static inline void wait_for_uevents(int fd, const struct uevent_desc *const uevents[])
+{
+	int i = 0;
+
+	while (1) {
+		int len;
+		char buf[4096];
+
+		len = recv(fd, &buf, sizeof(buf), 0);
+
+		if (len == 0)
+			continue;
+
+		print_uevent(buf, len);
+
+		if (uevent_match(buf, len, uevents[i])) {
+			tst_res(TPASS, "Got expected UEVENT");
+			if (!uevents[++i]) {
+				close(fd);
+				exit(0);
+			}
+		}
+	}
+}
+
+/*
+ * Waits 5 seconds for a child to exit, kills the child after a timeout.
+ */
+static inline void wait_for_pid(int pid)
+{
+	int status, ret;
+	int retries = 5000;
+
+	do {
+		ret = waitpid(pid, &status, WNOHANG);
+		usleep(1000);
+	} while (ret == 0 && retries--);
+
+	if (ret == pid) {
+		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+			return;
+
+		tst_res(TFAIL, "Child exitted with %s", tst_strstatus(status));
+	}
+
+	SAFE_KILL(pid, SIGKILL);
+
+	SAFE_WAITPID(pid, NULL, 0);
+
+	tst_res(TFAIL, "Did not get all expected UEVENTS");
+}
+
+#endif /* UEVENT_H__ */
diff --git a/testcases/kernel/uevents/uevent01.c b/testcases/kernel/uevents/uevent01.c
new file mode 100644
index 000000000..41cd01b1f
--- /dev/null
+++ b/testcases/kernel/uevents/uevent01.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * Very simple uevent netlink socket test.
+ *
+ * We fork a child that listens for a kernel events while parents attaches and
+ * detaches a loop device which should produce two change events.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include "tst_test.h"
+
+#include "uevent.h"
+
+static void generate_device_events(const char *dev_path)
+{
+	tst_fill_file("loop.img", 0, 1024, 1024);
+
+	tst_res(TINFO, "Attaching device %s", dev_path);
+	tst_attach_device(dev_path, "loop.img");
+	tst_res(TINFO, "Detaching device %s", dev_path);
+	tst_detach_device(dev_path);
+}
+
+static void verify_uevent(void)
+{
+	int pid, fd, dev_num;
+	char dev_path[1024];
+	char ev_msg[1024];
+	char ev_dev_path[1024];
+	char ev_dev_minor[128];
+	char ev_dev_name[128];
+
+	struct uevent_desc desc = {
+		.msg = ev_msg,
+		.value_cnt = 7,
+		.values = (const char*[]) {
+			"ACTION=change",
+			ev_dev_path,
+			"SUBSYSTEM=block",
+			"MAJOR=7",
+			ev_dev_minor,
+			ev_dev_name,
+			"DEVTYPE=disk",
+		}
+	};
+
+	dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));
+
+	snprintf(ev_msg, sizeof(ev_msg),
+	         "change@/devices/virtual/block/loop%i", dev_num);
+
+	snprintf(ev_dev_path, sizeof(ev_dev_path),
+	         "DEVPATH=/devices/virtual/block/loop%i", dev_num);
+
+	snprintf(ev_dev_minor, sizeof(ev_dev_minor), "MINOR=%i", dev_num);
+	snprintf(ev_dev_name, sizeof(ev_dev_name), "DEVNAME=loop%i", dev_num);
+
+	const struct uevent_desc *const uevents[] = {
+		&desc,
+		&desc,
+		NULL
+	};
+
+	pid = SAFE_FORK();
+	if (!pid) {
+		fd = open_uevent_netlink();
+		TST_CHECKPOINT_WAKE(0);
+		wait_for_uevents(fd, uevents);
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+
+	generate_device_events(dev_path);
+
+	wait_for_pid(pid);
+}
+
+static struct tst_test test = {
+	.test_all = verify_uevent,
+	.forks_child = 1,
+	.needs_tmpdir = 1,
+	.needs_checkpoints = 1,
+	.needs_root = 1,
+};
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02
  2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
  2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
  2019-08-20 15:18 ` [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01 Cyril Hrubis
@ 2019-08-20 15:18 ` Cyril Hrubis
  2019-08-21 16:35   ` Clemens Famulla-Conrad
  2019-08-20 15:18 ` [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library Cyril Hrubis
  2019-08-20 15:18 ` [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03 Cyril Hrubis
  4 siblings, 1 reply; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

Similar to uevent01 but we create and remove a tun network card instead.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 runtest/uevent                      |   1 +
 testcases/kernel/uevents/.gitignore |   1 +
 testcases/kernel/uevents/uevent02.c | 141 ++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 testcases/kernel/uevents/uevent02.c

diff --git a/runtest/uevent b/runtest/uevent
index e9cdf26b8..30b1114a4 100644
--- a/runtest/uevent
+++ b/runtest/uevent
@@ -1 +1,2 @@
 uevent01 uevent01
+uevent02 uevent02
diff --git a/testcases/kernel/uevents/.gitignore b/testcases/kernel/uevents/.gitignore
index 53d0b546a..0afc95534 100644
--- a/testcases/kernel/uevents/.gitignore
+++ b/testcases/kernel/uevents/.gitignore
@@ -1 +1,2 @@
 uevent01
+uevent02
diff --git a/testcases/kernel/uevents/uevent02.c b/testcases/kernel/uevents/uevent02.c
new file mode 100644
index 000000000..2c28d1810
--- /dev/null
+++ b/testcases/kernel/uevents/uevent02.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * Very simple uevent netlink socket test.
+ *
+ * We fork a child that listens for a kernel events while parents creates and removes
+ * a tun network device which should produce two several add and remove events.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include "tst_test.h"
+
+#include "uevent.h"
+
+#define TUN_PATH "/dev/net/tun"
+
+static void generate_tun_uevents(void)
+{
+	int fd = SAFE_OPEN(TUN_PATH, O_RDWR);
+
+	struct ifreq ifr = {
+		.ifr_flags = IFF_TUN,
+		.ifr_name = "ltp-tun0",
+	};
+
+	SAFE_IOCTL(fd, TUNSETIFF, (void*)&ifr);
+
+	SAFE_IOCTL(fd, TUNSETPERSIST, 0);
+
+	SAFE_CLOSE(fd);
+}
+
+static void verify_uevent(void)
+{
+	int pid, fd;
+
+	struct uevent_desc add = {
+		.msg = "add@/devices/virtual/net/ltp-tun0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=add",
+			"DEVPATH=/devices/virtual/net/ltp-tun0",
+			"SUBSYSTEM=net",
+			"ITERFACE=ltp-tun0",
+		}
+	};
+
+	struct uevent_desc add_rx = {
+		.msg = "add@/devices/virtual/net/ltp-tun0/queues/rx-0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=add",
+			"DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0",
+			"SUBSYSTEM=queueus",
+		}
+	};
+
+	struct uevent_desc add_tx = {
+		.msg = "add@/devices/virtual/net/ltp-tun0/queues/tx-0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=add",
+			"DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0",
+			"SUBSYSTEM=queueus",
+		}
+	};
+
+	struct uevent_desc rem_rx = {
+		.msg = "remove@/devices/virtual/net/ltp-tun0/queues/rx-0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			"DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0",
+			"SUBSYSTEM=queueus",
+		}
+	};
+
+	struct uevent_desc rem_tx = {
+		.msg = "remove@/devices/virtual/net/ltp-tun0/queues/tx-0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			"DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0",
+			"SUBSYSTEM=queueus",
+		}
+	};
+
+	struct uevent_desc rem = {
+		.msg = "remove@/devices/virtual/net/ltp-tun0",
+		.value_cnt = 0,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			"DEVPATH=/devices/virtual/net/ltp-tun0",
+			"SUBSYSTEM=net",
+			"ITERFACE=ltp-tun0",
+		}
+	};
+
+	const struct uevent_desc *const uevents[] = {
+		&add,
+		&add_rx,
+		&add_tx,
+		&rem_rx,
+		&rem_tx,
+		&rem,
+		NULL
+	};
+
+	pid = SAFE_FORK();
+	if (!pid) {
+		fd = open_uevent_netlink();
+		TST_CHECKPOINT_WAKE(0);
+		wait_for_uevents(fd, uevents);
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+
+	generate_tun_uevents();
+
+	wait_for_pid(pid);
+}
+
+static struct tst_test test = {
+	.test_all = verify_uevent,
+	.forks_child = 1,
+	.needs_tmpdir = 1,
+	.needs_checkpoints = 1,
+	.needs_root = 1,
+	.needs_drivers = (const char *const []) {
+		"tun",
+		NULL
+	},
+};
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library.
  2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
                   ` (2 preceding siblings ...)
  2019-08-20 15:18 ` [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02 Cyril Hrubis
@ 2019-08-20 15:18 ` Cyril Hrubis
  2019-08-22  9:12   ` Clemens Famulla-Conrad
  2019-08-20 15:18 ` [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03 Cyril Hrubis
  4 siblings, 1 reply; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

I to be used in the uevent03 test.

Also I will convert the uinput testcases to new library and make use of
this library as well.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/tst_uinput.h           |  48 +++++++++++
 libs/libltpuinput/Makefile     |  12 +++
 libs/libltpuinput/tst_uinput.c | 143 +++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)
 create mode 100644 include/tst_uinput.h
 create mode 100644 libs/libltpuinput/Makefile
 create mode 100644 libs/libltpuinput/tst_uinput.c

diff --git a/include/tst_uinput.h b/include/tst_uinput.h
new file mode 100644
index 000000000..dddbd9921
--- /dev/null
+++ b/include/tst_uinput.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_UINPUT_H__
+#define TST_UINPUT_H__
+
+/**
+ * Tries to open the uinput device.
+ *
+ * Returns file descriptor on success, -1 on failure.
+ */
+int open_uinput(void);
+
+/**
+ * Creates virtual input device.
+ *
+ * @fd File descriptor returned by open_uinput().
+ */
+void create_input_device(int fd);
+
+/**
+ * Parses /proc/bus/input/devices and returns the handlers strings for our
+ * virtual device, which is list of input devices that receive events from the
+ * device separated by whitestpaces.
+ *
+ * Returns newly allocated string, list of handlers separated by whitespaces,
+ * or NULL in a case of failure.
+ */
+char *get_input_handlers(void);
+
+/**
+ * Sets up the virtual device to appear as a mouse, this must be called before
+ * the call to create_input_device().
+ *
+ * @fd File descriptor as returned by open_uinput().
+ */
+void setup_mouse_events(int fd);
+
+/**
+ * Destroys virtual input device.
+ *
+ * @fd File descriptor returned by open_uinput().
+ */
+void destroy_input_device(int fd);
+
+#endif	/* TST_UINPUT_H__ */
diff --git a/libs/libltpuinput/Makefile b/libs/libltpuinput/Makefile
new file mode 100644
index 000000000..dd2a6c096
--- /dev/null
+++ b/libs/libltpuinput/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) Cyril Hrubis <chrubis@suse.cz>
+
+top_srcdir		?= ../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LIB			:= libltpuinput.a
+
+include $(top_srcdir)/include/mk/lib.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/libs/libltpuinput/tst_uinput.c b/libs/libltpuinput/tst_uinput.c
new file mode 100644
index 000000000..61d06138e
--- /dev/null
+++ b/libs/libltpuinput/tst_uinput.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <linux/input.h>
+#include <linux/uinput.h>
+#include <stdio.h>
+#include <string.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+#include "tst_uinput.h"
+
+#define VIRTUAL_DEVICE "virtual-device-ltp"
+
+static const char *uinput_paths[] = {
+	"/dev/input/uinput",
+	"/dev/uinput",
+};
+
+int open_uinput(void)
+{
+	unsigned int i;
+	int fd;
+
+	for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
+		fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
+
+		if (fd > 0) {
+			tst_res(TINFO, "Found uinput dev at %s", uinput_paths[i]);
+			return fd;
+		}
+
+		if (fd < 0 && errno != ENOENT) {
+			tst_brk(TBROK | TERRNO, "open(%s)", uinput_paths[i]);
+		}
+	}
+
+	return -1;
+}
+
+#define HANDLERS_PREFIX "Handlers="
+
+static char *parse_handlers(char *line)
+{
+	char *handlers;
+
+	handlers = strstr(line, HANDLERS_PREFIX) + sizeof(HANDLERS_PREFIX) - 1;
+
+	handlers[strlen(handlers) - 1] = 0;
+
+	return strdup(handlers);
+}
+
+char *get_input_handlers(void)
+{
+	FILE *file;
+	char line[1024];
+	int flag = 0;
+
+	file = fopen("/proc/bus/input/devices", "r");
+	if (!file)
+		return NULL;
+
+	while (fgets(line, sizeof(line), file)) {
+		if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\""))
+			flag = 1;
+
+		if (flag) {
+			if (line[0] == 'H')
+				return parse_handlers(line);
+
+			if (line[0] == '\n')
+				flag = 0;
+		}
+	}
+
+	fclose(file);
+	return NULL;
+}
+
+static int check_device(void)
+{
+	FILE *file;
+	char line[256];
+
+	file = fopen("/proc/bus/input/devices", "r");
+	if (!file)
+		return 0;
+
+	while (fgets(line, 256, file)) {
+		if (strstr(line, VIRTUAL_DEVICE))
+			return 1;
+	}
+
+	fclose(file);
+
+	return 0;
+}
+
+void setup_mouse_events(int fd)
+{
+	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY);
+	SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
+	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL);
+	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X);
+	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y);
+}
+
+void destroy_input_device(int fd)
+{
+	SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL);
+	SAFE_CLOSE(fd);
+}
+
+void create_input_device(int fd)
+{
+	int nb;
+	struct uinput_user_dev uidev = {
+		.name = VIRTUAL_DEVICE,
+		.id = {
+			.bustype = BUS_USB,
+			.vendor = 0x1,
+			.product = 0x1,
+			.version = 1,
+		}
+	};
+
+	SAFE_WRITE(1, fd, &uidev, sizeof(uidev));
+	SAFE_IOCTL(fd, UI_DEV_CREATE, NULL);
+
+	for (nb = 100; nb > 0; nb--) {
+		if (check_device())
+			return;
+		usleep(10000);
+	}
+
+	destroy_input_device(fd);
+	tst_brk(TBROK, "Failed to create device");
+}
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03
  2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
                   ` (3 preceding siblings ...)
  2019-08-20 15:18 ` [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library Cyril Hrubis
@ 2019-08-20 15:18 ` Cyril Hrubis
  2019-08-22  9:00   ` Clemens Famulla-Conrad
  4 siblings, 1 reply; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-20 15:18 UTC (permalink / raw)
  To: ltp

This time we create a virtual input device, a mouse, and validate the result.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 runtest/uevent                      |   1 +
 testcases/kernel/uevents/.gitignore |   1 +
 testcases/kernel/uevents/Makefile   |   4 +
 testcases/kernel/uevents/uevent03.c | 240 ++++++++++++++++++++++++++++
 4 files changed, 246 insertions(+)
 create mode 100644 testcases/kernel/uevents/uevent03.c

diff --git a/runtest/uevent b/runtest/uevent
index 30b1114a4..0b59c8723 100644
--- a/runtest/uevent
+++ b/runtest/uevent
@@ -1,2 +1,3 @@
 uevent01 uevent01
 uevent02 uevent02
+uevent03 uevent03
diff --git a/testcases/kernel/uevents/.gitignore b/testcases/kernel/uevents/.gitignore
index 0afc95534..7818f7308 100644
--- a/testcases/kernel/uevents/.gitignore
+++ b/testcases/kernel/uevents/.gitignore
@@ -1,2 +1,3 @@
 uevent01
 uevent02
+uevent03
diff --git a/testcases/kernel/uevents/Makefile b/testcases/kernel/uevents/Makefile
index cba769739..d5ceb0719 100644
--- a/testcases/kernel/uevents/Makefile
+++ b/testcases/kernel/uevents/Makefile
@@ -2,5 +2,9 @@
 
 top_srcdir			?= ../../..
 
+LTPLIBS = ltpuinput
+
+uevent03: LDLIBS += -lltpuinput
+
 include $(top_srcdir)/include/mk/testcases.mk
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/uevents/uevent03.c b/testcases/kernel/uevents/uevent03.c
new file mode 100644
index 000000000..26790967c
--- /dev/null
+++ b/testcases/kernel/uevents/uevent03.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * Very simple uevent netlink socket test.
+ *
+ * We fork a child that listens for a kernel events while parents creates and
+ * removes a virtual mouse which produces add and remove event for the device
+ * itself and for two event handlers called eventX and mouseY.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/sysmacros.h>
+
+#include <linux/uinput.h>
+
+#include "tst_test.h"
+#include "tst_uinput.h"
+#include "uevent.h"
+
+static int mouse_fd;
+
+static void create_uinput_mouse(void)
+{
+	mouse_fd = open_uinput();
+	setup_mouse_events(mouse_fd);
+	create_input_device(mouse_fd);
+}
+
+static void destroy_uinput_mouse(void)
+{
+	destroy_input_device(mouse_fd);
+}
+
+static void get_minor_major(char *device, char *minor, char *major, size_t buf_sizes)
+{
+	char path[1024];
+	struct stat stbuf;
+
+	snprintf(path, sizeof(path), "/dev/input/%s", device);
+
+	SAFE_STAT(path, &stbuf);
+
+	snprintf(major, buf_sizes, "MAJOR=%i", major(stbuf.st_rdev));
+	snprintf(minor, buf_sizes, "MINOR=%i", minor(stbuf.st_rdev));
+}
+
+#define MINOR_MAJOR_SIZE 32
+
+static void verify_uevent(void)
+{
+	int pid, fd;
+	char sysname[64];
+	char add_msg[1024];
+	char rem_msg[1024];
+	char dev_path[1024];
+	char add_msg_event1[1024];
+	char rem_msg_event1[1024];
+	char dev_path_event1[1024];
+	char add_msg_event2[1024];
+	char rem_msg_event2[1024];
+	char dev_path_event2[1024];
+	char dev_name1[1024];
+	char dev_name2[1024];
+
+	char minor_event1[MINOR_MAJOR_SIZE];
+	char minor_event2[MINOR_MAJOR_SIZE];
+	char major_event1[MINOR_MAJOR_SIZE];
+	char major_event2[MINOR_MAJOR_SIZE];
+
+	char *handlers, *handler1, *handler2;
+
+	struct uevent_desc add = {
+		.msg = add_msg,
+		.value_cnt = 7,
+		.values = (const char*[]) {
+			"ACTION=add",
+			dev_path,
+			"SUBSYSTEM=input",
+			"NAME=\"virtual-device-ltp\"",
+			"PROP=0",
+			"EV=7",
+			"REL=3",
+		}
+	};
+
+	struct uevent_desc add_event1 = {
+		.msg = add_msg_event1,
+		.value_cnt = 6,
+		.values = (const char*[]) {
+			"ACTION=add",
+			"SUBSYSTEM=input",
+			dev_name1,
+			dev_path_event1,
+			minor_event1,
+			major_event1,
+		}
+	};
+
+	struct uevent_desc add_event2 = {
+		.msg = add_msg_event2,
+		.value_cnt = 6,
+		.values = (const char*[]) {
+			"ACTION=add",
+			"SUBSYSTEM=input",
+			dev_name2,
+			dev_path_event2,
+			minor_event2,
+			major_event2,
+		}
+	};
+
+	struct uevent_desc rem_event1 = {
+		.msg = rem_msg_event1,
+		.value_cnt = 6,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			"SUBSYSTEM=input",
+			dev_name1,
+			dev_path_event1,
+			minor_event1,
+			major_event1,
+		}
+	};
+
+	struct uevent_desc rem_event2 = {
+		.msg = rem_msg_event2,
+		.value_cnt = 6,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			"SUBSYSTEM=input",
+			dev_name2,
+			dev_path_event2,
+			minor_event2,
+			major_event2,
+		}
+	};
+
+	struct uevent_desc rem = {
+		.msg = rem_msg,
+		.value_cnt = 7,
+		.values = (const char*[]) {
+			"ACTION=remove",
+			dev_path,
+			"SUBSYSTEM=input",
+			"NAME=\"virtual-device-ltp\"",
+			"PROP=0",
+			"EV=7",
+			"REL=3",
+		}
+	};
+
+	const struct uevent_desc *const uevents[] = {
+		&add,
+		&add_event1,
+		&add_event2,
+		&rem_event1,
+		&rem_event2,
+		&rem,
+		NULL
+	};
+
+	fd = open_uevent_netlink();
+
+	create_uinput_mouse();
+
+	SAFE_IOCTL(mouse_fd, UI_GET_SYSNAME(sizeof(sysname)), sysname);
+	handlers = get_input_handlers();
+
+	handler1 = strtok(handlers, " ");
+	get_minor_major(handler1, minor_event1, major_event1, MINOR_MAJOR_SIZE);
+
+	handler2 = strtok(NULL, " ");
+	get_minor_major(handler2, minor_event2, major_event2, MINOR_MAJOR_SIZE);
+
+	destroy_uinput_mouse();
+
+	tst_res(TINFO, "Sysname: %s", sysname);
+	tst_res(TINFO, "Handlers: %s", handlers);
+
+	snprintf(add_msg, sizeof(add_msg),
+	         "add@/devices/virtual/input/%s", sysname);
+
+	snprintf(rem_msg, sizeof(rem_msg),
+	         "remove@/devices/virtual/input/%s", sysname);
+
+	snprintf(dev_path, sizeof(dev_path),
+	         "DEVPATH=/devices/virtual/input/%s", sysname);
+
+
+	snprintf(add_msg_event1, sizeof(add_msg_event1),
+	         "add@/devices/virtual/input/%s/%s", sysname, handler1);
+
+	snprintf(rem_msg_event1, sizeof(rem_msg_event1),
+	         "remove@/devices/virtual/input/%s/%s", sysname, handler1);
+
+	snprintf(dev_path_event1, sizeof(dev_path_event1),
+	         "DEVPATH=/devices/virtual/input/%s/%s", sysname, handler1);
+
+	snprintf(dev_name1, sizeof(dev_name1),
+	         "DEVNAME=input/%s", handler1);
+
+
+	snprintf(add_msg_event2, sizeof(add_msg_event2),
+	         "add@/devices/virtual/input/%s/%s", sysname, handler2);
+
+	snprintf(rem_msg_event2, sizeof(rem_msg_event2),
+	         "remove@/devices/virtual/input/%s/%s", sysname, handler2);
+
+	snprintf(dev_path_event2, sizeof(dev_path_event2),
+	         "DEVPATH=/devices/virtual/input/%s/%s", sysname, handler2);
+
+	snprintf(dev_name2, sizeof(dev_name2),
+	         "DEVNAME=input/%s", handler2);
+
+	free(handlers);
+
+	pid = SAFE_FORK();
+	if (!pid)
+		wait_for_uevents(fd, uevents);
+
+	SAFE_CLOSE(fd);
+	wait_for_pid(pid);
+}
+
+static struct tst_test test = {
+	.test_all = verify_uevent,
+	.forks_child = 1,
+	.needs_tmpdir = 1,
+	.needs_checkpoints = 1,
+	.needs_drivers = (const char *const[]) {
+		"uinput",
+		NULL
+	},
+	.needs_root = 1,
+};
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02
  2019-08-20 15:18 ` [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02 Cyril Hrubis
@ 2019-08-21 16:35   ` Clemens Famulla-Conrad
  2019-08-26 11:45     ` Cyril Hrubis
  0 siblings, 1 reply; 14+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-21 16:35 UTC (permalink / raw)
  To: ltp

Hi Cyril,

On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> Similar to uevent01 but we create and remove a tun network card
> instead.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  runtest/uevent                      |   1 +
>  testcases/kernel/uevents/.gitignore |   1 +
>  testcases/kernel/uevents/uevent02.c | 141
> ++++++++++++++++++++++++++++
>  3 files changed, 143 insertions(+)
>  create mode 100644 testcases/kernel/uevents/uevent02.c
> 
> diff --git a/runtest/uevent b/runtest/uevent
> index e9cdf26b8..30b1114a4 100644
> --- a/runtest/uevent
> +++ b/runtest/uevent
> @@ -1 +1,2 @@
>  uevent01 uevent01
> +uevent02 uevent02
> diff --git a/testcases/kernel/uevents/.gitignore
> b/testcases/kernel/uevents/.gitignore
> index 53d0b546a..0afc95534 100644
> --- a/testcases/kernel/uevents/.gitignore
> +++ b/testcases/kernel/uevents/.gitignore
> @@ -1 +1,2 @@
>  uevent01
> +uevent02
> diff --git a/testcases/kernel/uevents/uevent02.c
> b/testcases/kernel/uevents/uevent02.c
> new file mode 100644
> index 000000000..2c28d1810
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent02.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +/*
> + * Very simple uevent netlink socket test.
> + *
> + * We fork a child that listens for a kernel events while parents
> creates and removes
             ^maybe line wrap?

> + * a tun network device which should produce two several add and
> remove events.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <linux/if.h>
> +#include <linux/if_tun.h>
> +
> +#include "tst_test.h"
> +
> +#include "uevent.h"
> +
> +#define TUN_PATH "/dev/net/tun"
> +
> +static void generate_tun_uevents(void)
> +{
> +	int fd = SAFE_OPEN(TUN_PATH, O_RDWR);
> +
> +	struct ifreq ifr = {
> +		.ifr_flags = IFF_TUN,
> +		.ifr_name = "ltp-tun0",
> +	};
> +
> +	SAFE_IOCTL(fd, TUNSETIFF, (void*)&ifr);
> +
> +	SAFE_IOCTL(fd, TUNSETPERSIST, 0);
> +
> +	SAFE_CLOSE(fd);
> +}
> +
> +static void verify_uevent(void)
> +{
> +	int pid, fd;
> +
> +	struct uevent_desc add = {
> +		.msg = "add@/devices/virtual/net/ltp-tun0",
> +		.value_cnt = 0,
                             ^should it be 4?

> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			"DEVPATH=/devices/virtual/net/ltp-tun0",
> +			"SUBSYSTEM=net",
> +			"ITERFACE=ltp-tun0",
                          ^INTERFACE

> +		}
> +	};
> +
> +	struct uevent_desc add_rx = {
> +		.msg = "add@/devices/virtual/net/ltp-tun0/queues/rx-
> 0",
> +		.value_cnt = 0,
                             ^3

> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			"DEVPATH=/devices/virtual/net/ltp-
> tun0/queues/rx-0",
> +			"SUBSYSTEM=queueus",
                                        ^queues

> +		}
> +	};
> +
> +	struct uevent_desc add_tx = {
> +		.msg = "add@/devices/virtual/net/ltp-tun0/queues/tx-
> 0",
> +		.value_cnt = 0,
                             ^3

> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			"DEVPATH=/devices/virtual/net/ltp-
> tun0/queues/tx-0",
> +			"SUBSYSTEM=queueus",
                                        ^queues

> +		}
> +	};
> +
> +	struct uevent_desc rem_rx = {
> +		.msg = "remove@/devices/virtual/net/ltp-
> tun0/queues/rx-0",
> +		.value_cnt = 0,
                             ^3

> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			"DEVPATH=/devices/virtual/net/ltp-
> tun0/queues/rx-0",
> +			"SUBSYSTEM=queueus",
                                        ^queues

> +		}
> +	};
> +
> +	struct uevent_desc rem_tx = {
> +		.msg = "remove@/devices/virtual/net/ltp-
> tun0/queues/tx-0",
> +		.value_cnt = 0,
                             ^3

> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			"DEVPATH=/devices/virtual/net/ltp-
> tun0/queues/tx-0",
> +			"SUBSYSTEM=queueus",
> +		}
> +	};
> +
> +	struct uevent_desc rem = {
> +		.msg = "remove@/devices/virtual/net/ltp-tun0",
> +		.value_cnt = 0,
                             ^4
> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			"DEVPATH=/devices/virtual/net/ltp-tun0",
> +			"SUBSYSTEM=net",
> +			"ITERFACE=ltp-tun0",
                          ^should be INTERFACE

> +		}
> +	};
> +
> +	const struct uevent_desc *const uevents[] = {
> +		&add,
> +		&add_rx,
> +		&add_tx,
> +		&rem_rx,
> +		&rem_tx,
> +		&rem,
> +		NULL
> +	};
> +
> +	pid = SAFE_FORK();
> +	if (!pid) {
> +		fd = open_uevent_netlink();
> +		TST_CHECKPOINT_WAKE(0);
> +		wait_for_uevents(fd, uevents);
> +	}
> +
> +	TST_CHECKPOINT_WAIT(0);
> +
> +	generate_tun_uevents();
> +
> +	wait_for_pid(pid);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = verify_uevent,
> +	.forks_child = 1,
> +	.needs_tmpdir = 1,
> +	.needs_checkpoints = 1,
> +	.needs_root = 1,
> +	.needs_drivers = (const char *const []) {
> +		"tun",
> +		NULL
> +	},
> +};
> -- 
> 2.21.0
> 
> 

thanks
clemens

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01
  2019-08-20 15:18 ` [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01 Cyril Hrubis
@ 2019-08-21 16:35   ` Clemens Famulla-Conrad
  2019-08-26 11:47     ` Cyril Hrubis
  0 siblings, 1 reply; 14+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-21 16:35 UTC (permalink / raw)
  To: ltp

Hi Cyril,

On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> Simple test that attached and detaches a file to a loop device and
> checks that kernel broadcasts correct events to the kernel uevent
> broadcast group.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  runtest/uevent                      |   1 +
>  scenario_groups/default             |   1 +
>  testcases/kernel/uevents/.gitignore |   1 +
>  testcases/kernel/uevents/Makefile   |   6 +
>  testcases/kernel/uevents/uevent.h   | 176
> ++++++++++++++++++++++++++++
>  testcases/kernel/uevents/uevent01.c |  90 ++++++++++++++
>  6 files changed, 275 insertions(+)
>  create mode 100644 runtest/uevent
>  create mode 100644 testcases/kernel/uevents/.gitignore
>  create mode 100644 testcases/kernel/uevents/Makefile
>  create mode 100644 testcases/kernel/uevents/uevent.h
>  create mode 100644 testcases/kernel/uevents/uevent01.c
> 
> diff --git a/runtest/uevent b/runtest/uevent
> new file mode 100644
> index 000000000..e9cdf26b8
> --- /dev/null
> +++ b/runtest/uevent
> @@ -0,0 +1 @@
> +uevent01 uevent01
> diff --git a/scenario_groups/default b/scenario_groups/default
> index 093f5f706..62ae0759d 100644
> --- a/scenario_groups/default
> +++ b/scenario_groups/default
> @@ -29,3 +29,4 @@ input
>  cve
>  crypto
>  kernel_misc
> +uevent
> diff --git a/testcases/kernel/uevents/.gitignore
> b/testcases/kernel/uevents/.gitignore
> new file mode 100644
> index 000000000..53d0b546a
> --- /dev/null
> +++ b/testcases/kernel/uevents/.gitignore
> @@ -0,0 +1 @@
> +uevent01
> diff --git a/testcases/kernel/uevents/Makefile
> b/testcases/kernel/uevents/Makefile
> new file mode 100644
> index 000000000..cba769739
> --- /dev/null
> +++ b/testcases/kernel/uevents/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +top_srcdir			?= ../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/uevents/uevent.h
> b/testcases/kernel/uevents/uevent.h
> new file mode 100644
> index 000000000..2c32dd534
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent.h
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +#ifndef UEVENT_H__
> +#define UEVENT_H__
> +
> +#include "tst_netlink.h"
> +
> +/*
> + * There are two broadcast groups defined for the
> NETLINK_KOBJECT_UEVENT. The
> + * primary consument of the KERNEL group is udev which handles the
> hotplug
> + * events and then, once udev does it's magic the events are
> rebroadcasted to
> + * the UDEV group which is consumed by various daemons in the
> userspace.
> + */
> +enum monitor_netlink_group {
> +	MONITOR_GROUP_NONE,
> +	MONITOR_GROUP_KERNEL,
> +	MONITOR_GROUP_UDEV,
> +};
> +
> +/*
> + * The messages received from the NETLINK_KOBJECT_UEVENT socket are
> stored as a
> + * sequence of a null-terminated strings. First in the buffer is a
> summary of a
> + * action i.e. "$ACTION@$DEVPATH" which is then followed by a bunch
> of
> + * key-value pairs.
> + *
> + * For example attaching a file to loopback device generates event:
> + *
> + * "change@/devices/virtual/block/loop0\0
> + *  ACTION=change\0
> + *  DEVPATH=/devices/virtual/block/loop0\0
> + *  SUBSYSTEM=block\0
> + *  MAJOR=7\0
> + *  MINOR=0\0
> + *  DEVNAME=loop0\0
> + *  DEVTYPE=disk\0
> + *  SEQNUM=2677\0"
> + */
> +
> +/*
> + * Prints uevent.
> + */
> +static inline void print_uevent(const char *event, int len)
> +{
> +	int consumed = 0;
> +
> +	tst_res(TINFO, "Got uevent:");
> +
> +	while (consumed < len) {
> +		tst_res(TINFO, "%s", event);
> +		int l = strlen(event) + 1;
> +		consumed += l;
> +		event += l;
> +	}
> +}
> +
> +/*
> + * Uevents read from the socket are matched against this
> description.
> + *
> + * The msg is the overall action description e.g.
> + * "add@/class/input/input4/mouse1" which has to be matched exactly
> before we
> + * event attempt to check the key-value pairs stored in the values
> array. The
> + * event is considered to match if all key-value pairs in the values
> has been
> + * found in the received event.
> + */
> +struct uevent_desc {
> +	const char *msg;
> +	int value_cnt;
> +	const char **values;
> +};
> +
> +static inline int uevent_match(const char *event, int len,
> +                               const struct uevent_desc *uevent)
> +{
> +	int consumed = 0;
> +	int val_matches = 0;
> +
> +	if (memcmp(event, uevent->msg, strlen(uevent->msg)))
> +		return 0;
> +
> +	int l = strlen(event) + 1;
> +
> +	consumed += l;
> +	event += l;
> +
> +	while (consumed < len) {
> +		int i;
> +		for (i = 0; i < uevent->value_cnt; i++) {
> +			if (!strcmp(event, uevent->values[i])) {
> +				val_matches++;
> +				break;
> +			}
> +		}
> +
> +		l = strlen(event) + 1;
> +		consumed += l;
> +		event += l;
> +	}
> +
> +	return val_matches == uevent->value_cnt;
> +}
> +
> +static inline int open_uevent_netlink(void)
> +{
> +	int fd;
> +	struct sockaddr_nl nl_addr = {
> +		.nl_family = AF_NETLINK,
> +		.nl_groups = MONITOR_GROUP_KERNEL,
> +	};
> +
> +	fd = SAFE_SOCKET(AF_NETLINK, SOCK_RAW,
> NETLINK_KOBJECT_UEVENT);
> +
> +	SAFE_BIND(fd, (struct sockaddr *)&nl_addr, sizeof(nl_addr));
> +
> +	return fd;
> +}
> +
> +/*
> + * Reads events from uevent netlink socket until all expected events
> passed in
> + * the uevent array are matched.
> + */
> +static inline void wait_for_uevents(int fd, const struct uevent_desc
> *const uevents[])
> +{
> +	int i = 0;
> +
> +	while (1) {
> +		int len;
> +		char buf[4096];
> +
> +		len = recv(fd, &buf, sizeof(buf), 0);
> +
> +		if (len == 0)
> +			continue;
> +
> +		print_uevent(buf, len);
> +
> +		if (uevent_match(buf, len, uevents[i])) {
> +			tst_res(TPASS, "Got expected UEVENT");
> +			if (!uevents[++i]) {
> +				close(fd);
> +				exit(0);
> +			}
> +		}
> +	}
> +}
> +
> +/*
> + * Waits 5 seconds for a child to exit, kills the child after a
> timeout.
> + */
> +static inline void wait_for_pid(int pid)
> +{
> +	int status, ret;
> +	int retries = 5000;
> +
> +	do {
> +		ret = waitpid(pid, &status, WNOHANG);
> +		usleep(1000);
> +	} while (ret == 0 && retries--);
> +
> +	if (ret == pid) {
> +		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
> +			return;
> +
> +		tst_res(TFAIL, "Child exitted with %s",
> tst_strstatus(status));
> +	}
> +
> +	SAFE_KILL(pid, SIGKILL);
> +
> +	SAFE_WAITPID(pid, NULL, 0);
> +
> +	tst_res(TFAIL, "Did not get all expected UEVENTS");
> +}
> +
> +#endif /* UEVENT_H__ */
> diff --git a/testcases/kernel/uevents/uevent01.c
> b/testcases/kernel/uevents/uevent01.c
> new file mode 100644
> index 000000000..41cd01b1f
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent01.c
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +/*
> + * Very simple uevent netlink socket test.
> + *
> + * We fork a child that listens for a kernel events while parents 
> attaches and
> + * detaches a loop device which should produce two change events.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include "tst_test.h"
> +
> +#include "uevent.h"
> +
> +static void generate_device_events(const char *dev_path)
> +{
> +	tst_fill_file("loop.img", 0, 1024, 1024);
> +
> +	tst_res(TINFO, "Attaching device %s", dev_path);
> +	tst_attach_device(dev_path, "loop.img");
> +	tst_res(TINFO, "Detaching device %s", dev_path);
> +	tst_detach_device(dev_path);
> +}
> +
> +static void verify_uevent(void)
> +{
> +	int pid, fd, dev_num;
> +	char dev_path[1024];
> +	char ev_msg[1024];
> +	char ev_dev_path[1024];
> +	char ev_dev_minor[128];
> +	char ev_dev_name[128];
> +
> +	struct uevent_desc desc = {
> +		.msg = ev_msg,
> +		.value_cnt = 7,
> +		.values = (const char*[]) {
> +			"ACTION=change",
> +			ev_dev_path,
> +			"SUBSYSTEM=block",
> +			"MAJOR=7",
> +			ev_dev_minor,
> +			ev_dev_name,
> +			"DEVTYPE=disk",
> +		}
> +	};
> +
> +	dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));

Maybe it isn't worth to check if dev_num is a valid number.

> +
> +	snprintf(ev_msg, sizeof(ev_msg),
> +	         "change@/devices/virtual/block/loop%i", dev_num);
> +
> +	snprintf(ev_dev_path, sizeof(ev_dev_path),
> +	         "DEVPATH=/devices/virtual/block/loop%i", dev_num);
> +
> +	snprintf(ev_dev_minor, sizeof(ev_dev_minor), "MINOR=%i",
> dev_num);
> +	snprintf(ev_dev_name, sizeof(ev_dev_name), "DEVNAME=loop%i",
> dev_num);
> +
> +	const struct uevent_desc *const uevents[] = {
> +		&desc,
> +		&desc,
> +		NULL
> +	};
> +
> +	pid = SAFE_FORK();
> +	if (!pid) {
> +		fd = open_uevent_netlink();
> +		TST_CHECKPOINT_WAKE(0);
> +		wait_for_uevents(fd, uevents);

For me it wasn't obvious that wait_for_uevents() does the exit(). Not
sure if we should do the exit better here or name the function like
exit_on_uevents().

> +	}
> +
> +	TST_CHECKPOINT_WAIT(0);
> +
> +	generate_device_events(dev_path);
> +
> +	wait_for_pid(pid);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = verify_uevent,
> +	.forks_child = 1,
> +	.needs_tmpdir = 1,

Just curious, where do we need the tmpdir?

> +	.needs_checkpoints = 1,
> +	.needs_root = 1,
> +};
> -- 
> 2.21.0
> 
> 

thx
Clemens

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03
  2019-08-20 15:18 ` [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03 Cyril Hrubis
@ 2019-08-22  9:00   ` Clemens Famulla-Conrad
  2019-08-26 13:55     ` Cyril Hrubis
  0 siblings, 1 reply; 14+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-22  9:00 UTC (permalink / raw)
  To: ltp

Hi Cyril,
works nice, just minor thing and a question.

On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> This time we create a virtual input device, a mouse, and validate the
> result.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  runtest/uevent                      |   1 +
>  testcases/kernel/uevents/.gitignore |   1 +
>  testcases/kernel/uevents/Makefile   |   4 +
>  testcases/kernel/uevents/uevent03.c | 240
> ++++++++++++++++++++++++++++
>  4 files changed, 246 insertions(+)
>  create mode 100644 testcases/kernel/uevents/uevent03.c
> 
> diff --git a/runtest/uevent b/runtest/uevent
> index 30b1114a4..0b59c8723 100644
> --- a/runtest/uevent
> +++ b/runtest/uevent
> @@ -1,2 +1,3 @@
>  uevent01 uevent01
>  uevent02 uevent02
> +uevent03 uevent03
> diff --git a/testcases/kernel/uevents/.gitignore
> b/testcases/kernel/uevents/.gitignore
> index 0afc95534..7818f7308 100644
> --- a/testcases/kernel/uevents/.gitignore
> +++ b/testcases/kernel/uevents/.gitignore
> @@ -1,2 +1,3 @@
>  uevent01
>  uevent02
> +uevent03
> diff --git a/testcases/kernel/uevents/Makefile
> b/testcases/kernel/uevents/Makefile
> index cba769739..d5ceb0719 100644
> --- a/testcases/kernel/uevents/Makefile
> +++ b/testcases/kernel/uevents/Makefile
> @@ -2,5 +2,9 @@
>  
>  top_srcdir			?= ../../..
>  
> +LTPLIBS = ltpuinput
> +
> +uevent03: LDLIBS += -lltpuinput
> +
>  include $(top_srcdir)/include/mk/testcases.mk
>  include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/uevents/uevent03.c
> b/testcases/kernel/uevents/uevent03.c
> new file mode 100644
> index 000000000..26790967c
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent03.c
> @@ -0,0 +1,240 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +/*
> + * Very simple uevent netlink socket test.
> + *
> + * We fork a child that listens for a kernel events while parents
> creates and
> + * removes a virtual mouse which produces add and remove event for
> the device
> + * itself and for two event handlers called eventX and mouseY.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sys/sysmacros.h>
> +
> +#include <linux/uinput.h>
> +
> +#include "tst_test.h"
> +#include "tst_uinput.h"
> +#include "uevent.h"
> +
> +static int mouse_fd;
> +
> +static void create_uinput_mouse(void)
> +{
> +	mouse_fd = open_uinput();
> +	setup_mouse_events(mouse_fd);
> +	create_input_device(mouse_fd);
> +}
> +
> +static void destroy_uinput_mouse(void)
> +{
> +	destroy_input_device(mouse_fd);
> +}
> +
> +static void get_minor_major(char *device, char *minor, char *major,
> size_t buf_sizes)
> +{
> +	char path[1024];
> +	struct stat stbuf;
> +
> +	snprintf(path, sizeof(path), "/dev/input/%s", device);
> +
> +	SAFE_STAT(path, &stbuf);
> +
> +	snprintf(major, buf_sizes, "MAJOR=%i",
> major(stbuf.st_rdev));
> +	snprintf(minor, buf_sizes, "MINOR=%i",
> minor(stbuf.st_rdev));
> +}
> +
> +#define MINOR_MAJOR_SIZE 32
> +
> +static void verify_uevent(void)
> +{
> +	int pid, fd;
> +	char sysname[64];
> +	char add_msg[1024];
> +	char rem_msg[1024];
> +	char dev_path[1024];
> +	char add_msg_event1[1024];
> +	char rem_msg_event1[1024];
> +	char dev_path_event1[1024];
> +	char add_msg_event2[1024];
> +	char rem_msg_event2[1024];
> +	char dev_path_event2[1024];
> +	char dev_name1[1024];
> +	char dev_name2[1024];
> +
> +	char minor_event1[MINOR_MAJOR_SIZE];
> +	char minor_event2[MINOR_MAJOR_SIZE];
> +	char major_event1[MINOR_MAJOR_SIZE];
> +	char major_event2[MINOR_MAJOR_SIZE];
> +
> +	char *handlers, *handler1, *handler2;
> +
> +	struct uevent_desc add = {
> +		.msg = add_msg,
> +		.value_cnt = 7,
> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			dev_path,
> +			"SUBSYSTEM=input",
> +			"NAME=\"virtual-device-ltp\"",
> +			"PROP=0",
> +			"EV=7",
> +			"REL=3",
> +		}
> +	};
> +
> +	struct uevent_desc add_event1 = {
> +		.msg = add_msg_event1,
> +		.value_cnt = 6,
> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			"SUBSYSTEM=input",
> +			dev_name1,
> +			dev_path_event1,
> +			minor_event1,
> +			major_event1,
> +		}
> +	};
> +
> +	struct uevent_desc add_event2 = {
> +		.msg = add_msg_event2,
> +		.value_cnt = 6,
> +		.values = (const char*[]) {
> +			"ACTION=add",
> +			"SUBSYSTEM=input",
> +			dev_name2,
> +			dev_path_event2,
> +			minor_event2,
> +			major_event2,
> +		}
> +	};
> +
> +	struct uevent_desc rem_event1 = {
> +		.msg = rem_msg_event1,
> +		.value_cnt = 6,
> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			"SUBSYSTEM=input",
> +			dev_name1,
> +			dev_path_event1,
> +			minor_event1,
> +			major_event1,
> +		}
> +	};
> +
> +	struct uevent_desc rem_event2 = {
> +		.msg = rem_msg_event2,
> +		.value_cnt = 6,
> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			"SUBSYSTEM=input",
> +			dev_name2,
> +			dev_path_event2,
> +			minor_event2,
> +			major_event2,
> +		}
> +	};
> +
> +	struct uevent_desc rem = {
> +		.msg = rem_msg,
> +		.value_cnt = 7,
> +		.values = (const char*[]) {
> +			"ACTION=remove",
> +			dev_path,
> +			"SUBSYSTEM=input",
> +			"NAME=\"virtual-device-ltp\"",
> +			"PROP=0",
> +			"EV=7",
> +			"REL=3",
> +		}
> +	};
> +
> +	const struct uevent_desc *const uevents[] = {
> +		&add,
> +		&add_event1,
> +		&add_event2,
> +		&rem_event1,
> +		&rem_event2,
> +		&rem,
> +		NULL
> +	};
> +
> +	fd = open_uevent_netlink();
> +
> +	create_uinput_mouse();
> +
> +	SAFE_IOCTL(mouse_fd, UI_GET_SYSNAME(sizeof(sysname)),
> sysname);
> +	handlers = get_input_handlers();
> +
> +	handler1 = strtok(handlers, " ");
Not sure if it's possible that we will get none or only one handler?

> +	get_minor_major(handler1, minor_event1, major_event1,
> MINOR_MAJOR_SIZE);
> +
> +	handler2 = strtok(NULL, " ");
> +	get_minor_major(handler2, minor_event2, major_event2,
> MINOR_MAJOR_SIZE);
> +
> +	destroy_uinput_mouse();
> +
> +	tst_res(TINFO, "Sysname: %s", sysname);
> +	tst_res(TINFO, "Handlers: %s", handlers);
Because of strtok(), we do not see all handlers here.

> +
> +	snprintf(add_msg, sizeof(add_msg),
> +	         "add@/devices/virtual/input/%s", sysname);
> +
> +	snprintf(rem_msg, sizeof(rem_msg),
> +	         "remove@/devices/virtual/input/%s", sysname);
> +
> +	snprintf(dev_path, sizeof(dev_path),
> +	         "DEVPATH=/devices/virtual/input/%s", sysname);
> +
> +
> +	snprintf(add_msg_event1, sizeof(add_msg_event1),
> +	         "add@/devices/virtual/input/%s/%s", sysname,
> handler1);
> +
> +	snprintf(rem_msg_event1, sizeof(rem_msg_event1),
> +	         "remove@/devices/virtual/input/%s/%s", sysname,
> handler1);
> +
> +	snprintf(dev_path_event1, sizeof(dev_path_event1),
> +	         "DEVPATH=/devices/virtual/input/%s/%s", sysname,
> handler1);
> +
> +	snprintf(dev_name1, sizeof(dev_name1),
> +	         "DEVNAME=input/%s", handler1);
> +
> +
> +	snprintf(add_msg_event2, sizeof(add_msg_event2),
> +	         "add@/devices/virtual/input/%s/%s", sysname,
> handler2);
> +
> +	snprintf(rem_msg_event2, sizeof(rem_msg_event2),
> +	         "remove@/devices/virtual/input/%s/%s", sysname,
> handler2);
> +
> +	snprintf(dev_path_event2, sizeof(dev_path_event2),
> +	         "DEVPATH=/devices/virtual/input/%s/%s", sysname,
> handler2);
> +
> +	snprintf(dev_name2, sizeof(dev_name2),
> +	         "DEVNAME=input/%s", handler2);
> +
> +	free(handlers);
> +
> +	pid = SAFE_FORK();
> +	if (!pid)
> +		wait_for_uevents(fd, uevents);
> +
> +	SAFE_CLOSE(fd);
> +	wait_for_pid(pid);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = verify_uevent,
> +	.forks_child = 1,
> +	.needs_tmpdir = 1,
> +	.needs_checkpoints = 1,
> +	.needs_drivers = (const char *const[]) {
> +		"uinput",
> +		NULL
> +	},
> +	.needs_root = 1,
> +};
> -- 
> 2.21.0
> 
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library.
  2019-08-20 15:18 ` [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library Cyril Hrubis
@ 2019-08-22  9:12   ` Clemens Famulla-Conrad
  0 siblings, 0 replies; 14+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-22  9:12 UTC (permalink / raw)
  To: ltp

Hi Cyril,

On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> I to be used in the uevent03 test.
> 
> Also I will convert the uinput testcases to new library and make use
> of
> this library as well.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  include/tst_uinput.h           |  48 +++++++++++
>  libs/libltpuinput/Makefile     |  12 +++
>  libs/libltpuinput/tst_uinput.c | 143
> +++++++++++++++++++++++++++++++++
>  3 files changed, 203 insertions(+)
>  create mode 100644 include/tst_uinput.h
>  create mode 100644 libs/libltpuinput/Makefile
>  create mode 100644 libs/libltpuinput/tst_uinput.c
> 
> diff --git a/include/tst_uinput.h b/include/tst_uinput.h
> new file mode 100644
> index 000000000..dddbd9921
> --- /dev/null
> +++ b/include/tst_uinput.h
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +#ifndef TST_UINPUT_H__
> +#define TST_UINPUT_H__
> +
> +/**
> + * Tries to open the uinput device.
> + *
> + * Returns file descriptor on success, -1 on failure.
> + */
> +int open_uinput(void);
> +
> +/**
> + * Creates virtual input device.
> + *
> + * @fd File descriptor returned by open_uinput().
> + */
> +void create_input_device(int fd);
> +
> +/**
> + * Parses /proc/bus/input/devices and returns the handlers strings
> for our
> + * virtual device, which is list of input devices that receive
> events from the
> + * device separated by whitestpaces.
> + *
> + * Returns newly allocated string, list of handlers separated by
> whitespaces,
> + * or NULL in a case of failure.
> + */
> +char *get_input_handlers(void);
> +
> +/**
> + * Sets up the virtual device to appear as a mouse, this must be
> called before
> + * the call to create_input_device().
> + *
> + * @fd File descriptor as returned by open_uinput().
> + */
> +void setup_mouse_events(int fd);
> +
> +/**
> + * Destroys virtual input device.
> + *
> + * @fd File descriptor returned by open_uinput().
> + */
> +void destroy_input_device(int fd);
> +
> +#endif	/* TST_UINPUT_H__ */
> diff --git a/libs/libltpuinput/Makefile b/libs/libltpuinput/Makefile
> new file mode 100644
> index 000000000..dd2a6c096
> --- /dev/null
> +++ b/libs/libltpuinput/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) Cyril Hrubis <chrubis@suse.cz>
> +
> +top_srcdir		?= ../..
> +
> +include $(top_srcdir)/include/mk/env_pre.mk
> +
> +LIB			:= libltpuinput.a
> +
> +include $(top_srcdir)/include/mk/lib.mk
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/libs/libltpuinput/tst_uinput.c
> b/libs/libltpuinput/tst_uinput.c
> new file mode 100644
> index 000000000..61d06138e
> --- /dev/null
> +++ b/libs/libltpuinput/tst_uinput.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
> + * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +#include <linux/input.h>
> +#include <linux/uinput.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +
> +#include "tst_uinput.h"
> +
> +#define VIRTUAL_DEVICE "virtual-device-ltp"
> +
> +static const char *uinput_paths[] = {
> +	"/dev/input/uinput",
> +	"/dev/uinput",
> +};
> +
> +int open_uinput(void)
> +{
> +	unsigned int i;
> +	int fd;
> +
> +	for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
> +		fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
> +
> +		if (fd > 0) {
> +			tst_res(TINFO, "Found uinput dev at %s",
> uinput_paths[i]);
> +			return fd;
> +		}
> +
> +		if (fd < 0 && errno != ENOENT) {
> +			tst_brk(TBROK | TERRNO, "open(%s)",
> uinput_paths[i]);
> +		}
> +	}
> +
> +	return -1;
> +}
> +
> +#define HANDLERS_PREFIX "Handlers="
> +
> +static char *parse_handlers(char *line)
> +{
> +	char *handlers;
> +
> +	handlers = strstr(line, HANDLERS_PREFIX) +
> sizeof(HANDLERS_PREFIX) - 1;
> +
> +	handlers[strlen(handlers) - 1] = 0;
> +
> +	return strdup(handlers);
> +}
> +
> +char *get_input_handlers(void)
> +{
> +	FILE *file;
> +	char line[1024];
> +	int flag = 0;
> +
> +	file = fopen("/proc/bus/input/devices", "r");
> +	if (!file)
> +		return NULL;
> +
> +	while (fgets(line, sizeof(line), file)) {
> +		if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\""))
> +			flag = 1;
> +
> +		if (flag) {
> +			if (line[0] == 'H')
> +				return parse_handlers(line);
> +
> +			if (line[0] == '\n')
> +				flag = 0;
> +		}
> +	}
> +
> +	fclose(file);
> +	return NULL;
> +}
> +
> +static int check_device(void)
> +{
> +	FILE *file;
> +	char line[256];
> +
> +	file = fopen("/proc/bus/input/devices", "r");
> +	if (!file)
> +		return 0;
> +
> +	while (fgets(line, 256, file)) {
                           ^maybe sizeof(line)

> +		if (strstr(line, VIRTUAL_DEVICE))
Could we get name clash and should check for Name="VIRTUAL_DEVICE" as
in get_input_handlers() ?

> +			return 1;
> +	}
> +
> +	fclose(file);
> +
> +	return 0;
> +}
> +
> +void setup_mouse_events(int fd)
> +{
> +	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY);
> +	SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
> +	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL);
> +	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X);
> +	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y);
> +}
> +
> +void destroy_input_device(int fd)
> +{
> +	SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL);
> +	SAFE_CLOSE(fd);
> +}
> +
> +void create_input_device(int fd)
> +{
> +	int nb;
> +	struct uinput_user_dev uidev = {
> +		.name = VIRTUAL_DEVICE,
> +		.id = {
> +			.bustype = BUS_USB,
> +			.vendor = 0x1,
> +			.product = 0x1,
> +			.version = 1,
> +		}
> +	};
> +
> +	SAFE_WRITE(1, fd, &uidev, sizeof(uidev));
> +	SAFE_IOCTL(fd, UI_DEV_CREATE, NULL);
> +
> +	for (nb = 100; nb > 0; nb--) {
> +		if (check_device())
> +			return;
> +		usleep(10000);
> +	}
> +
> +	destroy_input_device(fd);
> +	tst_brk(TBROK, "Failed to create device");
> +}
> -- 
> 2.21.0
> 
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions.
  2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
@ 2019-08-22  9:31   ` Clemens Famulla-Conrad
  0 siblings, 0 replies; 14+ messages in thread
From: Clemens Famulla-Conrad @ 2019-08-22  9:31 UTC (permalink / raw)
  To: ltp

Reviewed-by: Clemens Famulla-Conrad <cfamullaconrad@suse.de>

On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> Export tst_attach_device() and tst_deteach_device() which will be
> later
> on used by a kernel netlink uevent tests.
> 
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  include/tst_device.h | 7 +++++++
>  lib/tst_device.c     | 8 ++++----
>  2 files changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/include/tst_device.h b/include/tst_device.h
> index f0ddc3e93..c6e7b45b1 100644
> --- a/include/tst_device.h
> +++ b/include/tst_device.h
> @@ -50,6 +50,13 @@ int tst_clear_device(const char *dev);
>   *
>   */
>  int tst_find_free_loopdev(const char *path, size_t path_len);
> +
> +
> +int tst_attach_device(const char *dev_path, const char *file_path);
> +
> +
> +int tst_detach_device(const char *dev_path);
> +
>  /*
>   * Reads test block device stat file and returns the bytes written
> since the
>   * last call of this function.
> diff --git a/lib/tst_device.c b/lib/tst_device.c
> index 22abdef46..10f71901d 100644
> --- a/lib/tst_device.c
> +++ b/lib/tst_device.c
> @@ -139,7 +139,7 @@ int tst_find_free_loopdev(char *path, size_t
> path_len)
>  	return -1;
>  }
>  
> -static int attach_device(const char *dev, const char *file)
> +int tst_attach_device(const char *dev, const char *file)
>  {
>  	int dev_fd, file_fd;
>  	struct loop_info loopinfo;
> @@ -185,7 +185,7 @@ static int attach_device(const char *dev, const
> char *file)
>  	return 0;
>  }
>  
> -static int detach_device(const char *dev)
> +int tst_detach_device(const char *dev)
>  {
>  	int dev_fd, ret, i;
>  
> @@ -284,7 +284,7 @@ const char *tst_acquire_device__(unsigned int
> size)
>  	if (tst_find_free_loopdev(dev_path, sizeof(dev_path)) == -1)
>  		return NULL;
>  
> -	if (attach_device(dev_path, DEV_FILE))
> +	if (tst_attach_device(dev_path, DEV_FILE))
>  		return NULL;
>  
>  	device_acquired = 1;
> @@ -329,7 +329,7 @@ int tst_release_device(const char *dev)
>  	 *
>  	 * The file image is deleted in tst_rmdir();
>  	 */
> -	ret = detach_device(dev);
> +	ret = tst_detach_device(dev);
>  
>  	device_acquired = 0;
>  
> -- 
> 2.21.0
> 
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02
  2019-08-21 16:35   ` Clemens Famulla-Conrad
@ 2019-08-26 11:45     ` Cyril Hrubis
  0 siblings, 0 replies; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:45 UTC (permalink / raw)
  To: ltp

Hi!
Thanks for pointing out the obvious mistakes, will fix in v3.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01
  2019-08-21 16:35   ` Clemens Famulla-Conrad
@ 2019-08-26 11:47     ` Cyril Hrubis
  0 siblings, 0 replies; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-26 11:47 UTC (permalink / raw)
  To: ltp

Hi!
> > +
> > +	dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));
> 
> Maybe it isn't worth to check if dev_num is a valid number.

Sure.

> > +
> > +	snprintf(ev_msg, sizeof(ev_msg),
> > +	         "change@/devices/virtual/block/loop%i", dev_num);
> > +
> > +	snprintf(ev_dev_path, sizeof(ev_dev_path),
> > +	         "DEVPATH=/devices/virtual/block/loop%i", dev_num);
> > +
> > +	snprintf(ev_dev_minor, sizeof(ev_dev_minor), "MINOR=%i",
> > dev_num);
> > +	snprintf(ev_dev_name, sizeof(ev_dev_name), "DEVNAME=loop%i",
> > dev_num);
> > +
> > +	const struct uevent_desc *const uevents[] = {
> > +		&desc,
> > +		&desc,
> > +		NULL
> > +	};
> > +
> > +	pid = SAFE_FORK();
> > +	if (!pid) {
> > +		fd = open_uevent_netlink();
> > +		TST_CHECKPOINT_WAKE(0);
> > +		wait_for_uevents(fd, uevents);
> 
> For me it wasn't obvious that wait_for_uevents() does the exit(). Not
> sure if we should do the exit better here or name the function like
> exit_on_uevents().

I was just lazy, I guess that the cleanest solution would be to call the
exit here after the wait_for_uevents() call.

> > +	}
> > +
> > +	TST_CHECKPOINT_WAIT(0);
> > +
> > +	generate_device_events(dev_path);
> > +
> > +	wait_for_pid(pid);
> > +}
> > +
> > +static struct tst_test test = {
> > +	.test_all = verify_uevent,
> > +	.forks_child = 1,
> > +	.needs_tmpdir = 1,
> 
> Just curious, where do we need the tmpdir?

We are creating a disk image to be attached to the loop device in the
generate_device_events().

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03
  2019-08-22  9:00   ` Clemens Famulla-Conrad
@ 2019-08-26 13:55     ` Cyril Hrubis
  0 siblings, 0 replies; 14+ messages in thread
From: Cyril Hrubis @ 2019-08-26 13:55 UTC (permalink / raw)
  To: ltp

Hi!
> > +	handler1 = strtok(handlers, " ");
> Not sure if it's possible that we will get none or only one handler?

Well that would be a bug. As far as I can tell we have to get eventX
handler and mouseY handler for each device that looks like a mouse.

I guess that checking the content of handler1 and handler2 wouldn't harm
though.

> > +	get_minor_major(handler1, minor_event1, major_event1,
> > MINOR_MAJOR_SIZE);
> > +
> > +	handler2 = strtok(NULL, " ");
> > +	get_minor_major(handler2, minor_event2, major_event2,
> > MINOR_MAJOR_SIZE);
> > +
> > +	destroy_uinput_mouse();
> > +
> > +	tst_res(TINFO, "Sysname: %s", sysname);
> > +	tst_res(TINFO, "Handlers: %s", handlers);
> Because of strtok(), we do not see all handlers here.

Ah my bad, we have to move that before the strtok() call.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2019-08-26 13:55 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
2019-08-22  9:31   ` Clemens Famulla-Conrad
2019-08-20 15:18 ` [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01 Cyril Hrubis
2019-08-21 16:35   ` Clemens Famulla-Conrad
2019-08-26 11:47     ` Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02 Cyril Hrubis
2019-08-21 16:35   ` Clemens Famulla-Conrad
2019-08-26 11:45     ` Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library Cyril Hrubis
2019-08-22  9:12   ` Clemens Famulla-Conrad
2019-08-20 15:18 ` [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03 Cyril Hrubis
2019-08-22  9:00   ` Clemens Famulla-Conrad
2019-08-26 13:55     ` Cyril Hrubis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.