From mboxrd@z Thu Jan 1 00:00:00 1970 From: Cyril Hrubis Date: Wed, 25 Nov 2015 14:59:43 +0100 Subject: [LTP] [PATCH] kernel/input: add tests In-Reply-To: <1448379664-13775-1-git-send-email-chnyda@suse.com> References: <1448379664-13775-1-git-send-email-chnyda@suse.com> Message-ID: <20151125135943.GD24599@rei.lan> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: ltp@lists.linux.it Hi! > --- /dev/null > +++ b/runtest/input > @@ -0,0 +1,5 @@ > +input01 input01 > +input02 input02 > +input03 input03 > +input04 input04 > +input05 input05 If you create a new runtest file you should also add it to default scenario (scenario_groups/default) so it's actually executed by default. > diff --git a/testcases/kernel/input/input01.c b/testcases/kernel/input/input01.c > new file mode 100644 > index 0000000..dcce215 > --- /dev/null > +++ b/testcases/kernel/input/input01.c > @@ -0,0 +1,201 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > + /* > + * AUTHOR : Cedric Hnyda > + * DATE STARTED : 10/21/2015 Is this really necessary? The Copyright line at the top of the file gives nearly the same information... > + * Create a virtual device (mouse), send events to /dev/uinput > + * and check that the events are well received in /dev/input/eventX > + * > + */ > + > +#include > +#include > +#include > + > +#include "input_helper.h" > +#include "test.h" > +#include "safe_macros.h" > +#include "lapi/fcntl.h" > + > +#define NB_TEST 100 > + > +static void setup(void); > +static void send_information(void); > +static int verify_data(struct input_event iev, int *nb); > +static int check_information(void); > +static void cleanup(void); > + > +static int fd; > +static int fd2; > + > +char *TCID = "uinput01"; ^ This should be input01 to match the source file name > +int main(int ac, char **av) > +{ > + int lc; > + int pid; > + > + tst_parse_opts(ac, av, NULL, NULL); > + > + for (lc = 0; lc < TEST_LOOPING(lc); ++lc) { > + > + setup(); > + pid = tst_fork(); > + > + if (!pid) > + send_information(); > + else { > + fd2 = setup_read(); > + if (check_information()) > + tst_resm(TFAIL, > + "Wrong data received in eventX"); > + else > + tst_resm(TPASS, "Data received in eventX"); > + } LKML coding style, that is used by LTP prefers curly braces around both code block if they are necessary for one of them. But this is minor. > + } > + tst_exit(); > +} > + > +static void setup(void) > +{ > + struct uinput_user_dev uidev; > + > + tst_require_root(); > + > + fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0 && errno == ENOENT) > + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0) ^ Eh, did you forget && errno == ENOENT here? > + tst_brkm(TCONF, NULL, "unable to find and open uinput"); > + else if (fd < 0) > + tst_brkm(TBROK, NULL, "open failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_REL) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_X) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_Y) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); I guess that it's time to add SAFE_IOCTL(). I will add it to LTP tree so that you can use it in the testcases. > + memset(&uidev, 0, sizeof(uidev)); > + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, VIRTUAL_DEVICE); > + uidev.id.bustype = BUS_USB; > + uidev.id.vendor = 0x1; > + uidev.id.product = 0x1; > + uidev.id.version = 1; > + > + if (write(fd, &uidev, sizeof(uidev)) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); We have SAFE_WRITE() allready. ;) > + if (ioctl(fd, UI_DEV_CREATE) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + sleep(1); What do we wait here for? Using sleep() in testcases is frowned upon unless there is real need for it. I guess that we wait for the device to appear right? If that is the case we should loop here with a 0.1s sleep and exit the loop once the device was created. > +} > + > +static void send_information(void) > +{ > + struct input_event ev; > + int nb; > + > + sleep(1); Here as well. > + for (nb = 0; nb < NB_TEST; ++nb) { > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_X; > + ev.value = 10; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); SAFE_WRITE() > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_Y; > + ev.value = 1; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); Here as well. > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_SYN; > + ev.code = 0; > + ev.value = 0; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); And here as well. > + usleep(100); We sleep here so that the kernel buffers are not filled up right? What happens when we overfill them? Does the write fail with EAGAIN? > + } > + > + cleanup(); > +} > + > +static int check_information(void) > +{ > + int nb; > + int fail; > + int rd; > + uint i; > + struct input_event iev[64]; > + > + fail = 0; > + nb = 0; > + > + while (nb < NB_TEST * 3 && !fail) { > + rd = read(fd2, iev, sizeof(struct input_event) * 64); > + > + if (rd < (int) sizeof(struct input_event)) > + fail = 1; What about if (rd < 0) and if (rd % sizeof(struct input_event) == 0), since the read size should be multiple of the input_event structure size. > + for (i = 0; i < rd / sizeof(struct input_event) && !fail; i++) > + fail = verify_data(iev[i], &nb); > + } > + > + SAFE_CLOSE(NULL, fd2); > + return fail; > +} > + > +static int verify_data(struct input_event iev, int *nb) ^ It's more usuall to pass structure values by pointer in C. Sice if this function couldn't be inlined the whole structure would be compied on stack... > +{ > + if (iev.type == EV_REL && *nb % 3 == 0 > + && iev.value == 10 && iev.code == REL_X) > + (*nb)++; > + else if (iev.type == EV_REL && *nb % 3 == 1 > + && iev.value == 1 && iev.code == REL_Y) > + (*nb)++; > + else if (iev.type == EV_SYN && *nb % 3 == 2 > + && iev.code == 0) > + (*nb)++; > + else > + return 1; > + return 0; Eh, what about adding more returns to make it more readable and also being more verbose about what happened? if (*nb % 3 == 0) { if (iev->type != EV_REL) { tst_resm(TINFO, "%i: Unexpected event type %i expected %i", *nb, ev->type, EV_REL); return 1; } if (iev->code != REL_X) { ... } if (iev->value != 10) { ... } return 0; } if (*nb % 3 == 1) { if ( ... .... } ... > +} > + > +static void cleanup(void) > +{ > + if (ioctl(fd, UI_DEV_DESTROY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + SAFE_CLOSE(NULL, fd); > +} > diff --git a/testcases/kernel/input/input02.c b/testcases/kernel/input/input02.c > new file mode 100644 > index 0000000..5b9d90b > --- /dev/null > +++ b/testcases/kernel/input/input02.c > @@ -0,0 +1,166 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > + /* > + * AUTHOR : Cedric Hnyda > + * DATE STARTED : 10/21/2015 > + * > + * Create a virtual device (mouse), send events to /dev/uinput > + * and check that the events are not received in /dev/input/eventX > + * because the device is grabbed by another process > + * > + */ > + > +#include > +#include > +#include > + > +#include "test.h" > +#include "safe_macros.h" > +#include "lapi/fcntl.h" > +#include "input_helper.h" > + > +#define NB_TEST 100 > + > +static void setup(void); > +static void send_information(void); > +static int check_information(void); > +static void cleanup(void); > + > +static int fd; > +static int fd2; > + > +char *TCID = "uinput02"; > + > +int main(int ac, char **av) > +{ > + int lc; > + int pid; > + > + tst_parse_opts(ac, av, NULL, NULL); > + > + for (lc = 0; lc < TEST_LOOPING(lc); ++lc) { > + > + setup(); > + pid = tst_fork(); > + fd2 = setup_read(); > + > + if (!pid) > + send_information(); > + else { > + if (check_information()) > + tst_resm(TFAIL, "Data received in eventX"); > + else > + tst_resm(TPASS, "No data received in eventX"); > + } > + } > + tst_exit(); > +} > + > +static void setup(void) > +{ > + struct uinput_user_dev uidev; > + > + tst_require_root(); > + > + fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0 && errno == ENOENT) > + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0) > + tst_brkm(TCONF, NULL, "unable to find and open uinput"); > + else if (fd < 0) > + tst_brkm(TBROK, NULL, "open failed"); This exact code fragment is part of the input01.c setup. Can you please create open_uinput() function in the library instead of copy&pasting code? > + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_REL) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_X) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_Y) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + memset(&uidev, 0, sizeof(uidev)); > + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, VIRTUAL_DEVICE); > + uidev.id.bustype = BUS_USB; > + uidev.id.vendor = 0x1; > + uidev.id.product = 0x1; > + uidev.id.version = 1; > + > + if (write(fd, &uidev, sizeof(uidev)) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_DEV_CREATE) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + sleep(1); The same comments apply here as well. > +} > + > +static void send_information(void) > +{ > + int nb; > + struct input_event ev; > + > + if (ioctl(fd2, EVIOCGRAB, 1)) > + tst_brkm(TBROK, cleanup, "ioctl failed"); > + tst_resm(TINFO, "The virtual device was grabbed"); > + > + sleep(1); > + > + for (nb = 0; nb < NB_TEST; ++nb) { > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_SYN; > + ev.code = 0; > + ev.value = 0; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + usleep(100); Hmm, are you sure that EV_SYN actually appear on the other end of the input stac even when no changes were done? > + } > + > + cleanup(); > +} > + > +static int check_information(void) > +{ > + int nb; > + int rd; > + struct input_event iev[64]; > + > + nb = 0; > + > + while (nb == 0) { > + rd = read(fd2, iev, sizeof(struct input_event) * 64); > + if (rd == 0) > + break; > + nb++; > + } > + > + SAFE_CLOSE(NULL, fd2); > + return nb == 0; > +} > + > +static void cleanup(void) > +{ > + if (ioctl(fd, UI_DEV_DESTROY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + SAFE_CLOSE(NULL, fd); > +} > diff --git a/testcases/kernel/input/input03.c b/testcases/kernel/input/input03.c > new file mode 100644 > index 0000000..922866e > --- /dev/null > +++ b/testcases/kernel/input/input03.c > @@ -0,0 +1,186 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > + /* > + * AUTHOR : Cedric Hnyda > + * DATE STARTED : 10/21/2015 > + * > + * Create a virtual device (mouse), send events to /dev/uinput > + * and check that the events are well received in /dev/input/mice > + * > + */ > + > +#include > +#include > +#include > + > +#include "test.h" > +#include "safe_macros.h" > +#include "lapi/fcntl.h" > +#include "input_helper.h" > + > +#define NB_TEST 100 > +#define X_VALUE 10 > +#define Y_VALUE 10 > + > +static void setup(void); > +static void send_information(void); > +static int check_information(void); > +static void cleanup(void); > + > +static int fd; > +static int fd2; > + > +char *TCID = "uinput03"; > + > +int main(int ac, char **av) > +{ > + int lc; > + int pid; > + > + tst_parse_opts(ac, av, NULL, NULL); > + > + for (lc = 0; lc < TEST_LOOPING(lc); ++lc) { > + > + setup(); > + pid = tst_fork(); > + > + if (!pid) > + send_information(); > + else { > + if (check_information()) > + tst_resm(TFAIL, "Wrong data received"); > + else > + tst_resm(TPASS, > + "Data received in /dev/input/mice"); > + } > + } > + tst_exit(); > +} > + > +static void setup(void) > +{ > + struct uinput_user_dev uidev; > + > + tst_require_root(); > + > + fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0 && errno == ENOENT) > + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0) > + tst_brkm(TCONF, NULL, "unable to find and open uinput"); > + else if (fd < 0) > + tst_brkm(TBROK, NULL, "open failed"); Here as well, fix the code and move it to the library. > + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_REL) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_X) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_Y) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + memset(&uidev, 0, sizeof(uidev)); > + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, VIRTUAL_DEVICE); > + uidev.id.bustype = BUS_USB; > + uidev.id.vendor = 0x1; > + uidev.id.product = 0x1; > + uidev.id.version = 1; > + > + if (write(fd, &uidev, sizeof(uidev)) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_DEV_CREATE) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + sleep(1); And here as well. > +} > + > +static void send_information(void) > +{ > + int nb; > + struct input_event ev; > + > + sleep(1); > + > + for (nb = 0; nb < NB_TEST; ++nb) { > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_X; > + ev.value = X_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_Y; > + ev.value = Y_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_SYN; > + ev.code = 0; > + ev.value = 0; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + usleep(100); > + > + } > + > + cleanup(); Eh, why do you call cleanup() here? Also this function si nearly identical to the one in input01.c. What about adding send_rel_move(int fd, int x, int y) to the library that would actually write the events and calling it from the testcases? > +} > + > +static int check_information(void) > +{ > + int nb; > + int fail; > + int rd; > + char buf[3]; > + > + fd2 = SAFE_OPEN(NULL, "/dev/input/mice", O_RDONLY); > + fail = 0; > + nb = 0; > + > + while (nb < NB_TEST && !fail) { > + memset(buf, 0, sizeof(char) * 3); > + rd = read(fd2, buf, sizeof(char) * 3); > + > + if (rd < (int) sizeof(char) * 3) > + fail = 1; > + if (buf[1] != X_VALUE || buf[2] != -Y_VALUE || buf[0] != 40) > + fail = 1; > + nb++; > + } The sizeof(char) == 1 by definition, remove it from the code. > + SAFE_CLOSE(NULL, fd2); > + return fail; > +} > + > +static void cleanup(void) > +{ > + if (ioctl(fd, UI_DEV_DESTROY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + SAFE_CLOSE(NULL, fd); > +} > diff --git a/testcases/kernel/input/input04.c b/testcases/kernel/input/input04.c > new file mode 100644 > index 0000000..8bd0af5 > --- /dev/null > +++ b/testcases/kernel/input/input04.c > @@ -0,0 +1,179 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > + /* > + * AUTHOR : Cedric Hnyda > + * DATE STARTED : 11/13/2015 > + * > + * Create a virtual device (mouse), send empty events to /dev/uinput > + * and check that the events are not received in /dev/input/mice > + * > + */ > + > +#include > +#include > +#include > + > +#include "test.h" > +#include "safe_macros.h" > +#include "lapi/fcntl.h" > +#include "input_helper.h" > + > +#define NB_TEST 100 > +#define X_VALUE 0 > +#define Y_VALUE 0 > + > +static void setup(void); > +static void send_information(void); > +static int check_information(void); > +static void cleanup(void); > + > +static int fd; > +static int fd2; > + > +char *TCID = "uinput04"; > + > +int main(int ac, char **av) > +{ > + int lc; > + int pid; > + > + tst_parse_opts(ac, av, NULL, NULL); > + > + for (lc = 0; lc < TEST_LOOPING(lc); ++lc) { > + > + setup(); > + pid = tst_fork(); > + > + if (!pid) > + send_information(); > + else { > + if (check_information()) > + tst_resm(TPASS, > + "No data received in /dev/input/mice"); > + else > + tst_resm(TFAIL, > + "Data received /dev/input/mice"); > + } > + } > + tst_exit(); > +} > + > +static void setup(void) > +{ > + struct uinput_user_dev uidev; > + > + tst_require_root(); > + > + fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0 && errno == ENOENT) > + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0) > + tst_brkm(TCONF, NULL, "unable to find and open uinput"); > + else if (fd < 0) > + tst_brkm(TBROK, NULL, "open failed"); Here as well. Move it to the library. > + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_REL) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_X) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_RELBIT, REL_Y) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + memset(&uidev, 0, sizeof(uidev)); > + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, VIRTUAL_DEVICE); > + uidev.id.bustype = BUS_USB; > + uidev.id.vendor = 0x1; > + uidev.id.product = 0x1; > + uidev.id.version = 1; > + > + if (write(fd, &uidev, sizeof(uidev)) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_DEV_CREATE) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + sleep(1); Here as well. > +} > + > +static void send_information(void) > +{ > + struct input_event ev; > + int nb; > + > + sleep(1); > + > + for (nb = 0; nb < NB_TEST; ++nb) { > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_X; > + ev.value = X_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_Y; > + ev.value = Y_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_SYN; > + ev.code = 0; > + ev.value = 0; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + usleep(100); > + } Here as well, you could just called send_rel_move(fd, 0, 0); > + cleanup(); > +} > + > +static int check_information(void) > +{ > + int rv; > + struct timeval timeout; > + fd_set set; > + > + fd2 = SAFE_OPEN(NULL, "/dev/input/mice", O_RDWR); > + FD_ZERO(&set); > + FD_SET(fd2, &set); > + timeout.tv_sec = 0; > + timeout.tv_usec = 10000; > + rv = select(fd2 + 1, &set, NULL, NULL, &timeout); > + if (rv < 0) > + tst_brkm(TBROK, NULL, "select failed"); > + SAFE_CLOSE(NULL, fd2); > + return rv == 0; > +} > + > +static void cleanup(void) > +{ > + if (ioctl(fd, UI_DEV_DESTROY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + SAFE_CLOSE(NULL, fd); > +} > diff --git a/testcases/kernel/input/input05.c b/testcases/kernel/input/input05.c > new file mode 100644 > index 0000000..6c5b759 > --- /dev/null > +++ b/testcases/kernel/input/input05.c > @@ -0,0 +1,174 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > + /* > + * AUTHOR : Cedric Hnyda > + * DATE STARTED : 11/16/2015 > + * > + * Create a virtual device (mouse), send events to /dev/uinput > + * and check that the events are not received in /dev/input/eventX > + * because it is not possible to sent such events > + * > + */ > + > +#include > +#include > +#include > + > +#include "test.h" > +#include "safe_macros.h" > +#include "lapi/fcntl.h" > +#include "input_helper.h" > + > +#define X_VALUE 10 > +#define Y_VALUE 10 > + > +#define NB_TEST 100 > + > +static void setup(void); > +static void send_information(void); > +static int check_information(void); > +static void cleanup(void); > + > +static int fd; > +static int fd2; > + > +char *TCID = "uinput05"; > + > +int main(int ac, char **av) > +{ > + int lc; > + int pid; > + > + tst_parse_opts(ac, av, NULL, NULL); > + > + for (lc = 0; lc < TEST_LOOPING(lc); ++lc) { > + > + setup(); > + pid = tst_fork(); > + fd2 = setup_read(); > + > + if (!pid) > + send_information(); > + else { > + if (check_information()) > + tst_resm(TFAIL, "Data received in eventX"); > + else > + tst_resm(TPASS, "No data received in eventX"); > + } > + } > + tst_exit(); > +} > + > +static void setup(void) > +{ > + struct uinput_user_dev uidev; > + > + tst_require_root(); > + > + fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0 && errno == ENOENT) > + fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); > + > + if (fd < 0) > + tst_brkm(TCONF, NULL, "unable to find and open uinput"); > + else if (fd < 0) > + tst_brkm(TBROK, NULL, "open failed"); > + > + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + memset(&uidev, 0, sizeof(uidev)); > + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, VIRTUAL_DEVICE); > + uidev.id.bustype = BUS_USB; > + uidev.id.vendor = 0x1; > + uidev.id.product = 0x1; > + uidev.id.version = 1; > + > + if (write(fd, &uidev, sizeof(uidev)) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + > + if (ioctl(fd, UI_DEV_CREATE) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + sleep(1); > +} > + > +static void send_information(void) > +{ > + int nb; > + struct input_event ev; > + > + sleep(1); > + > + for (nb = 0; nb < NB_TEST; ++nb) { > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_X; > + ev.value = X_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_REL; > + ev.code = REL_Y; > + ev.value = Y_VALUE; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + > + memset(&ev, 0, sizeof(struct input_event)); > + ev.type = EV_SYN; > + ev.code = 0; > + ev.value = 0; > + if (write(fd, &ev, sizeof(struct input_event)) < 0) > + tst_brkm(TBROK, cleanup, "write failed"); > + usleep(100); > + > + } > + > + cleanup(); > +} > + > +static int check_information(void) > +{ > + int nb; > + int rd; > + struct input_event iev[64]; > + > + nb = 0; > + > + while (nb == 0) { > + rd = read(fd2, iev, sizeof(struct input_event) * 64); > + if (rd == 0) > + break; > + nb++; > + } > + > + SAFE_CLOSE(NULL, fd2); > + return nb == 0; > +} > + > +static void cleanup(void) > +{ > + if (ioctl(fd, UI_DEV_DESTROY) < 0) > + tst_brkm(TBROK, NULL, "ioctl failed"); > + SAFE_CLOSE(NULL, fd); > +} This is nearly identical to the prevoius one. Most of the code should be in the library. > diff --git a/testcases/kernel/input/input_helper.c b/testcases/kernel/input/input_helper.c > new file mode 100644 > index 0000000..7ba7c60 > --- /dev/null > +++ b/testcases/kernel/input/input_helper.c > @@ -0,0 +1,91 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include > +#include > +#include > +#include "test.h" > +#include "safe_macros.h" > +#include "input_helper.h" > + > +int setup_read(void) > +{ > + DIR *d; > + char namedir1[1024]; > + char *event; > + struct dirent *dp; > + int fd2; > + > + event = NULL; > + > + d = opendir("/sys/devices/virtual/input/"); > + while ((dp = readdir(d))) { > + if (!fnmatch("input[0-9]*", dp->d_name, 0)) { > + memset(namedir1, 0, sizeof(namedir1)); > + strcat(namedir1, "/sys/devices/virtual/input/"); > + strcat(namedir1, dp->d_name); > + if (closedir(d) < 0) > + tst_brkm(TBROK, NULL, "closedir failed"); > + d = opendir(namedir1); > + event = find_event(d, namedir1); > + if (event) > + break; > + } > + } > + > + closedir(d); > + fd2 = SAFE_OPEN(NULL, event, O_RDONLY); > + free(event); > + return fd2; > +} So these two functions looks for input device with VIRTUAL_DEVICE in name, right? Why don't we simply try to open all input devices in /dev/input/ one by one do the EVIOCGNAME ioctl() and do strcmp() on it? > +char *find_event(DIR *d, char *namedir1) > +{ > + char namedir2[1024]; > + char buf[256]; > + char *event; > + struct dirent *dp; > + int fd3; > + int nb; > + > + event = malloc(sizeof(char) * 256); Again sizeof(char) == 1 > + while ((dp = readdir(d))) { > + if (!fnmatch("event*", dp->d_name, 0)) { > + memset(namedir2, 0, sizeof(namedir2)); > + strcpy(namedir2, namedir1); > + strcat(namedir2, "/name"); > + fd3 = open(namedir2, O_RDONLY); > + if (fd3 > 0) { > + nb = read(fd3, &buf, sizeof(VIRTUAL_DEVICE)); > + if (nb < 0) > + tst_brkm(TBROK, NULL, "read failed"); > + close(fd3); > + if (!strncmp(buf, VIRTUAL_DEVICE, > + strlen(VIRTUAL_DEVICE))) { > + memset(event, 0, 256); > + strcat(event, "/dev/input/"); > + strcat(event, dp->d_name); > + return event; > + } > + } > + } > + } > + free(event); > + return NULL; > +} > diff --git a/testcases/kernel/input/input_helper.h b/testcases/kernel/input/input_helper.h > new file mode 100644 > index 0000000..0b62e71 > --- /dev/null > +++ b/testcases/kernel/input/input_helper.h > @@ -0,0 +1,30 @@ > +/* > + * Copyright (c) 2015 Cedric Hnyda > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef INPUT_HELPER_H > +#define INPUT_HELPER_H > + > +#define VIRTUAL_DEVICE "virtual-device-ltp" > + > +#include > +#include > + > +char *find_event(DIR *d, char *namedir1); > +int setup_read(void); > + > +#endif /* INPUT_HELPER_H */ > -- > 2.1.4 > > > -- > Mailing list info: http://lists.linux.it/listinfo/ltp -- Cyril Hrubis chrubis@suse.cz