1 /*
2 * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd
3 * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
4 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
5 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
6 * Copyright (c) 2016 Linux Test Project
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU General Public License for more details.
17 */
18
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22
23 #include <errno.h>
24 #include <poll.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include "lapi/syscalls.h"
30 #include "ltp_signal.h"
31 #include "tst_sig_proc.h"
32 #include "tst_test.h"
33
34 /* Older versions of glibc don't publish this constant's value. */
35 #ifndef POLLRDHUP
36 #define POLLRDHUP 0x2000
37 #endif
38
39 #define TYPE_NAME(x) .ttype = x, .desc = #x
40
41 struct test_case {
42 int ttype; /* test type (enum) */
43 const char *desc; /* test description (name) */
44 int ret; /* expected ret code */
45 int err; /* expected errno code */
46 short expect_revents; /* expected revents value */
47 unsigned int nfds; /* nfds ppoll parameter */
48 sigset_t *sigmask; /* sigmask ppoll parameter */
49 sigset_t *sigmask_cur; /* sigmask set for current process */
50 struct timespec *ts; /* ts ppoll parameter */
51 struct pollfd *fds; /* fds ppoll parameter */
52 int sigint_count; /* if > 0, spawn process to send SIGINT */
53 /* 'count' times to current process */
54 unsigned int sigint_delay; /* delay between SIGINT signals */
55 };
56
57 enum test_type {
58 NORMAL,
59 MASK_SIGNAL,
60 TIMEOUT,
61 FD_ALREADY_CLOSED,
62 SEND_SIGINT,
63 SEND_SIGINT_RACE_TEST,
64 INVALID_NFDS,
65 INVALID_FDS,
66 };
67
68 static int fd1 = -1;
69 static sigset_t sigmask_empty, sigmask_sigint;
70 static struct pollfd fds_good[1], fds_already_closed[1];
71
72 static struct timespec ts_short = {
73 .tv_sec = 0,
74 .tv_nsec = 200000000,
75 };
76 static struct timespec ts_long = {
77 .tv_sec = 2,
78 .tv_nsec = 0,
79 };
80
81 /* Test cases
82 *
83 * test status of errors on man page
84 *
85 * EBADF can't check because EBADF never happen even though
86 * fd was invalid. In this case, information of invalid
87 * fd is set in revents
88 * EFAULT v ('fds' array in the invalid address space)
89 * EINTR v (a non blocked signal was caught)
90 * EINVAL v ('nfds' is over the 'RLIMIT_NOFILE' value)
91 * ENOMEM can't check because it's difficult to create no-memory
92 */
93
94 static struct test_case tcase[] = {
95 {
96 TYPE_NAME(NORMAL),
97 .expect_revents = POLLIN | POLLOUT,
98 .ret = 1,
99 .err = 0,
100 .nfds = 1,
101 .ts = &ts_long,
102 .fds = fds_good,
103 },
104 {
105 TYPE_NAME(MASK_SIGNAL),
106 .ret = 0,
107 .err = 0,
108 .nfds = 0,
109 .sigmask = &sigmask_sigint,
110 .ts = &ts_short,
111 .fds = fds_good,
112 .sigint_count = 4,
113 .sigint_delay = 100000,
114 },
115 {
116 TYPE_NAME(TIMEOUT),
117 .ret = 0,
118 .err = 0,
119 .nfds = 0,
120 .ts = &ts_short,
121 .fds = fds_good,
122 },
123 {
124 TYPE_NAME(FD_ALREADY_CLOSED),
125 .expect_revents = POLLNVAL,
126 .ret = 1,
127 .err = 0,
128 .nfds = 1,
129 .ts = &ts_long,
130 .fds = fds_already_closed,
131 },
132 {
133 TYPE_NAME(SEND_SIGINT),
134 .ret = -1,
135 .err = EINTR,
136 .nfds = 0,
137 .ts = &ts_long,
138 .fds = fds_good,
139 .sigint_count = 40,
140 .sigint_delay = 100000,
141 },
142 {
143 TYPE_NAME(SEND_SIGINT_RACE_TEST),
144 .ret = -1,
145 .err = EINTR,
146 .nfds = 0,
147 .sigmask = &sigmask_empty,
148 .sigmask_cur = &sigmask_sigint,
149 .ts = &ts_long,
150 .fds = fds_good,
151 .sigint_count = 1,
152 .sigint_delay = 0,
153 },
154 {
155 TYPE_NAME(INVALID_NFDS),
156 .ret = -1,
157 .err = EINVAL,
158 .nfds = -1,
159 .ts = &ts_long,
160 .fds = fds_good,
161 },
162 {
163 TYPE_NAME(INVALID_FDS),
164 .ret = -1,
165 .err = EFAULT,
166 .nfds = 1,
167 .ts = &ts_long,
168 .fds = (struct pollfd *) -1,
169 },
170 };
171
sighandler(int sig LTP_ATTRIBUTE_UNUSED)172 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
173 {
174 }
175
setup(void)176 static void setup(void)
177 {
178 int fd2;
179
180 SAFE_SIGNAL(SIGINT, sighandler);
181
182 if (sigemptyset(&sigmask_empty) == -1)
183 tst_brk(TBROK | TERRNO, "sigemptyset");
184 if (sigemptyset(&sigmask_sigint) == -1)
185 tst_brk(TBROK | TERRNO, "sigemptyset");
186 if (sigaddset(&sigmask_sigint, SIGINT) == -1)
187 tst_brk(TBROK | TERRNO, "sigaddset");
188
189 fd1 = SAFE_OPEN("testfile1", O_CREAT | O_EXCL | O_RDWR,
190 S_IRUSR | S_IWUSR);
191 fds_good[0].fd = fd1;
192 fds_good[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
193 fds_good[0].revents = 0;
194
195 fd2 = SAFE_OPEN("testfile2", O_CREAT | O_EXCL | O_RDWR,
196 S_IRUSR | S_IWUSR);
197 fds_already_closed[0].fd = fd2;
198 fds_already_closed[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
199 fds_already_closed[0].revents = 0;
200 SAFE_CLOSE(fd2);
201 }
202
cleanup(void)203 static void cleanup(void)
204 {
205 if (fd1 != -1)
206 SAFE_CLOSE(fd1);
207 }
208
do_test(unsigned int i)209 static void do_test(unsigned int i)
210 {
211 pid_t pid = 0;
212 int sys_ret, sys_errno = 0, dummy;
213 struct test_case *tc = &tcase[i];
214 struct timespec ts, *tsp = NULL;
215
216 if (tc->ts) {
217 memcpy(&ts, tc->ts, sizeof(ts));
218 tsp = &ts;
219 }
220
221 tst_res(TINFO, "case %s", tc->desc);
222
223 /* setup */
224 if (tc->sigmask_cur) {
225 if (sigprocmask(SIG_SETMASK, tc->sigmask_cur, NULL) == -1)
226 tst_brk(TBROK, "sigprocmask");
227 }
228 if (tc->sigint_count > 0) {
229 pid = create_sig_proc(SIGINT, tc->sigint_count,
230 tc->sigint_delay);
231 }
232
233 /* test */
234 errno = 0;
235 sys_ret = tst_syscall(__NR_ppoll, tc->fds, tc->nfds, tsp,
236 tc->sigmask, SIGSETSIZE);
237 sys_errno = errno;
238
239 /* cleanup */
240 if (tc->sigmask_cur) {
241 if (sigprocmask(SIG_SETMASK, &sigmask_empty, NULL) == -1)
242 tst_brk(TBROK, "sigprocmask");
243 }
244 if (pid > 0) {
245 kill(pid, SIGTERM);
246 SAFE_WAIT(&dummy);
247 }
248
249 /* result check */
250 if (tc->expect_revents) {
251 if (tc->fds[0].revents == tc->expect_revents)
252 tst_res(TPASS, "revents=0x%04x", tc->expect_revents);
253 else
254 tst_res(TFAIL, "revents=0x%04x, expected=0x%04x",
255 tc->fds[0].revents, tc->expect_revents);
256 }
257 if (tc->ret >= 0 && tc->ret == sys_ret) {
258 tst_res(TPASS, "ret: %d", sys_ret);
259 } else if (tc->ret == -1 && sys_ret == -1 && sys_errno == tc->err) {
260 tst_res(TPASS, "ret: %d, errno: %s (%d)", sys_ret,
261 tst_strerrno(sys_errno), sys_errno);
262 } else {
263 tst_res(TFAIL, "ret: %d, exp: %d, ret_errno: %s (%d),"
264 " exp_errno: %s (%d)", sys_ret, tc->ret,
265 tst_strerrno(sys_errno), sys_errno,
266 tst_strerrno(tc->err), tc->err);
267 }
268 }
269
270 static struct tst_test test = {
271 .tcnt = ARRAY_SIZE(tcase),
272 .test = do_test,
273 .setup = setup,
274 .cleanup = cleanup,
275 .forks_child = 1,
276 .needs_tmpdir = 1,
277 };
278