/* * Copyright (c) 2016 Fujitsu Ltd. * Author: Guangwen Feng * * 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 will 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. */ /* * Description: * 1) epoll_wait(2) fails if epfd is not a valid file descriptor * 2) epoll_wait(2) fails if epfd is not an epoll file descriptor * 3) epoll_wait(2) fails if maxevents is less than zero * 4) epoll_wait(2) fails if maxevents is equal to zero * 5) epoll_wait(2) fails if the memory area pointed to by events * is not accessible with write permissions. * * Expected Result: * 1) epoll_wait(2) should return -1 and set errno to EBADF * 2) epoll_wait(2) should return -1 and set errno to EINVAL * 3) epoll_wait(2) should return -1 and set errno to EINVAL * 4) epoll_wait(2) should return -1 and set errno to EINVAL * 5) epoll_wait(2) should return -1 and set errno to EFAULT */ #include #include #include #include #include #include "test.h" #include "safe_macros.h" static int page_size, fds[2], epfd, inv_epfd, bad_epfd = -1; static struct epoll_event epevs[1] = { {.events = EPOLLOUT} }; static struct epoll_event *ev_rdwr = epevs; static struct epoll_event *ev_rdonly; static struct test_case_t { int *epfd; struct epoll_event **ev; int maxevents; int exp_errno; } tc[] = { /* test1 */ {&bad_epfd, &ev_rdwr, 1, EBADF}, /* test2 */ {&inv_epfd, &ev_rdwr, 1, EINVAL}, /* test3 */ {&epfd, &ev_rdwr, -1, EINVAL}, /* test4 */ {&epfd, &ev_rdwr, 0, EINVAL}, /* test5 */ {&epfd, &ev_rdonly, 1, EFAULT} }; char *TCID = "epoll_wait03"; int TST_TOTAL = ARRAY_SIZE(tc); static void setup(void); static void verify_epoll_wait(struct test_case_t *tc); static void cleanup(void); int main(int ac, char **av) { int lc, i; tst_parse_opts(ac, av, NULL, NULL); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; i < TST_TOTAL; i++) verify_epoll_wait(&tc[i]); } cleanup(); tst_exit(); } static void setup(void) { tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; page_size = getpagesize(); ev_rdonly = SAFE_MMAP(NULL, NULL, page_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); SAFE_PIPE(NULL, fds); epfd = epoll_create(1); if (epfd == -1) { tst_brkm(TBROK | TERRNO, cleanup, "failed to create epoll instance"); } epevs[0].data.fd = fds[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[0])) { tst_brkm(TBROK | TERRNO, cleanup, "failed to register epoll target"); } } static void verify_epoll_wait(struct test_case_t *tc) { TEST(epoll_wait(*(tc->epfd), *(tc->ev), tc->maxevents, -1)); if (TEST_RETURN != -1) { tst_resm(TFAIL, "epoll_wait() succeed unexpectedly"); } else { if (tc->exp_errno == TEST_ERRNO) { tst_resm(TPASS | TTERRNO, "epoll_wait() fails as expected"); } else { tst_resm(TFAIL | TTERRNO, "epoll_wait() fails unexpectedly, " "expected %d: %s", tc->exp_errno, tst_strerrno(tc->exp_errno)); } } } static void cleanup(void) { if (epfd > 0 && close(epfd)) tst_resm(TWARN | TERRNO, "failed to close epfd"); if (close(fds[0])) tst_resm(TWARN | TERRNO, "close(fds[0]) failed"); if (close(fds[1])) tst_resm(TWARN | TERRNO, "close(fds[1]) failed"); }