* [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.