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