You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
5.0 KiB
244 lines
5.0 KiB
// 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 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, *sysname;
|
|
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();
|
|
|
|
sysname = get_input_field_value('S');
|
|
handlers = get_input_field_value('H');
|
|
|
|
if (!sysname)
|
|
tst_brk(TBROK, "Expected /devices/virtual/input/inputN sysname!");
|
|
|
|
tst_res(TINFO, "Sysname: %s", sysname);
|
|
tst_res(TINFO, "Handlers: %s", handlers);
|
|
|
|
handler1 = strtok(handlers, " ");
|
|
if (!handler1)
|
|
tst_brk(TBROK, "Expected mouseX and eventY handlers!");
|
|
|
|
get_minor_major(handler1, minor_event1, major_event1, MINOR_MAJOR_SIZE);
|
|
|
|
handler2 = strtok(NULL, " ");
|
|
if (!handler2)
|
|
tst_brk(TBROK, "Expected mouseX and eventY handlers!");
|
|
|
|
get_minor_major(handler2, minor_event2, major_event2, MINOR_MAJOR_SIZE);
|
|
|
|
destroy_uinput_mouse();
|
|
|
|
snprintf(add_msg, sizeof(add_msg), "add@%s", sysname);
|
|
|
|
snprintf(rem_msg, sizeof(rem_msg), "remove@%s", sysname);
|
|
|
|
snprintf(dev_path, sizeof(dev_path), "DEVPATH=%s", sysname);
|
|
|
|
snprintf(add_msg_event1, sizeof(add_msg_event1),
|
|
"add@%s/%s", sysname, handler1);
|
|
|
|
snprintf(rem_msg_event1, sizeof(rem_msg_event1),
|
|
"remove@%s/%s", sysname, handler1);
|
|
|
|
snprintf(dev_path_event1, sizeof(dev_path_event1),
|
|
"DEVPATH=%s/%s", sysname, handler1);
|
|
|
|
snprintf(dev_name1, sizeof(dev_name1),
|
|
"DEVNAME=input/%s", handler1);
|
|
|
|
|
|
snprintf(add_msg_event2, sizeof(add_msg_event2),
|
|
"add@%s/%s", sysname, handler2);
|
|
|
|
snprintf(rem_msg_event2, sizeof(rem_msg_event2),
|
|
"remove@%s/%s", sysname, handler2);
|
|
|
|
snprintf(dev_path_event2, sizeof(dev_path_event2),
|
|
"DEVPATH=%s/%s", sysname, handler2);
|
|
|
|
snprintf(dev_name2, sizeof(dev_name2),
|
|
"DEVNAME=input/%s", handler2);
|
|
|
|
free(sysname);
|
|
free(handlers);
|
|
|
|
pid = SAFE_FORK();
|
|
if (!pid) {
|
|
wait_for_uevents(fd, uevents);
|
|
exit(0);
|
|
}
|
|
|
|
SAFE_CLOSE(fd);
|
|
wait_for_pid(pid);
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.test_all = verify_uevent,
|
|
.forks_child = 1,
|
|
.needs_checkpoints = 1,
|
|
.needs_drivers = (const char *const[]) {
|
|
"uinput",
|
|
NULL
|
|
},
|
|
.needs_root = 1,
|
|
};
|