• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "linux_syscall_numbers.h"
30 #include "ltp_signal.h"
31 #include "tst_test.h"
32 
33 /* Older versions of glibc don't publish this constant's value. */
34 #ifndef POLLRDHUP
35 #define POLLRDHUP 0x2000
36 #endif
37 
38 #define TYPE_NAME(x) .ttype = x, .desc = #x
39 
40 struct test_case {
41 	int ttype;		   /* test type (enum) */
42 	const char *desc;	   /* test description (name) */
43 	int ret;		   /* expected ret code */
44 	int err;		   /* expected errno code */
45 	short expect_revents;	   /* expected revents value */
46 	unsigned int nfds;	   /* nfds ppoll parameter */
47 	sigset_t *sigmask;	   /* sigmask ppoll parameter */
48 	sigset_t *sigmask_cur;	   /* sigmask set for current process */
49 	struct timespec *ts;	   /* ts ppoll parameter */
50 	struct pollfd *fds;	   /* fds ppoll parameter */
51 	int sigint_count;	   /* if > 0, spawn process to send SIGINT */
52 				   /* 'count' times to current process */
53 	unsigned int sigint_delay; /* delay between SIGINT signals */
54 };
55 
56 enum test_type {
57 	NORMAL,
58 	MASK_SIGNAL,
59 	TIMEOUT,
60 	FD_ALREADY_CLOSED,
61 	SEND_SIGINT,
62 	SEND_SIGINT_RACE_TEST,
63 	INVALID_NFDS,
64 	INVALID_FDS,
65 };
66 
67 static int fd1 = -1;
68 static sigset_t sigmask_empty, sigmask_sigint;
69 static struct pollfd fds_good[1], fds_already_closed[1];
70 
71 static struct timespec ts_short = {
72 	.tv_sec = 0,
73 	.tv_nsec = 200000000,
74 };
75 static struct timespec ts_long = {
76 	.tv_sec = 2,
77 	.tv_nsec = 0,
78 };
79 
80 /* Test cases
81  *
82  *   test status of errors on man page
83  *
84  *   EBADF              can't check because EBADF never happen even though
85  *                      fd was invalid. In this case, information of invalid
86  *                      fd is set in revents
87  *   EFAULT             v ('fds' array in the invalid address space)
88  *   EINTR              v (a non blocked signal was caught)
89  *   EINVAL             v ('nfds' is over the 'RLIMIT_NOFILE' value)
90  *   ENOMEM             can't check because it's difficult to create no-memory
91  */
92 
93 static struct test_case tcase[] = {
94 	{
95 		TYPE_NAME(NORMAL),
96 		.expect_revents = POLLIN | POLLOUT,
97 		.ret = 1,
98 		.err = 0,
99 		.nfds = 1,
100 		.ts = &ts_long,
101 		.fds = fds_good,
102 	},
103 	{
104 		TYPE_NAME(MASK_SIGNAL),
105 		.ret = 0,
106 		.err = 0,
107 		.nfds = 0,
108 		.sigmask = &sigmask_sigint,
109 		.ts = &ts_short,
110 		.fds = fds_good,
111 		.sigint_count = 4,
112 		.sigint_delay = 100000,
113 	},
114 	{
115 		TYPE_NAME(TIMEOUT),
116 		.ret = 0,
117 		.err = 0,
118 		.nfds = 0,
119 		.ts = &ts_short,
120 		.fds = fds_good,
121 	},
122 	{
123 		TYPE_NAME(FD_ALREADY_CLOSED),
124 		.expect_revents = POLLNVAL,
125 		.ret = 1,
126 		.err = 0,
127 		.nfds = 1,
128 		.ts = &ts_long,
129 		.fds = fds_already_closed,
130 	},
131 	{
132 		TYPE_NAME(SEND_SIGINT),
133 		.ret = -1,
134 		.err = EINTR,
135 		.nfds = 0,
136 		.ts = &ts_long,
137 		.fds = fds_good,
138 		.sigint_count = 40,
139 		.sigint_delay = 100000,
140 	},
141 	{
142 		TYPE_NAME(SEND_SIGINT_RACE_TEST),
143 		.ret = -1,
144 		.err = EINTR,
145 		.nfds = 0,
146 		.sigmask = &sigmask_empty,
147 		.sigmask_cur = &sigmask_sigint,
148 		.ts = &ts_long,
149 		.fds = fds_good,
150 		.sigint_count = 1,
151 		.sigint_delay = 0,
152 	},
153 	{
154 		TYPE_NAME(INVALID_NFDS),
155 		.ret = -1,
156 		.err = EINVAL,
157 		.nfds = -1,
158 		.ts = &ts_long,
159 		.fds = fds_good,
160 	},
161 	{
162 		TYPE_NAME(INVALID_FDS),
163 		.ret = -1,
164 		.err = EFAULT,
165 		.nfds = 1,
166 		.ts = &ts_long,
167 		.fds = (struct pollfd *) -1,
168 	},
169 };
170 
sighandler(int sig LTP_ATTRIBUTE_UNUSED)171 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
172 {
173 }
174 
setup(void)175 static void setup(void)
176 {
177 	int fd2;
178 
179 	SAFE_SIGNAL(SIGINT, sighandler);
180 
181 	if (sigemptyset(&sigmask_empty) == -1)
182 		tst_brk(TBROK | TERRNO, "sigemptyset");
183 	if (sigemptyset(&sigmask_sigint) == -1)
184 		tst_brk(TBROK | TERRNO, "sigemptyset");
185 	if (sigaddset(&sigmask_sigint, SIGINT) == -1)
186 		tst_brk(TBROK | TERRNO, "sigaddset");
187 
188 	fd1 = SAFE_OPEN("testfile1", O_CREAT | O_EXCL | O_RDWR,
189 		S_IRUSR | S_IWUSR);
190 	fds_good[0].fd = fd1;
191 	fds_good[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
192 	fds_good[0].revents = 0;
193 
194 	fd2 = SAFE_OPEN("testfile2", O_CREAT | O_EXCL | O_RDWR,
195 		S_IRUSR | S_IWUSR);
196 	fds_already_closed[0].fd = fd2;
197 	fds_already_closed[0].events = POLLIN | POLLPRI | POLLOUT | POLLRDHUP;
198 	fds_already_closed[0].revents = 0;
199 	SAFE_CLOSE(fd2);
200 }
201 
cleanup(void)202 static void cleanup(void)
203 {
204 	if (fd1 != -1)
205 		close(fd1);
206 }
207 
create_sig_proc(int sig,int count,unsigned int usec)208 static pid_t create_sig_proc(int sig, int count, unsigned int usec)
209 {
210 	pid_t pid, cpid;
211 
212 	pid = getpid();
213 	cpid = SAFE_FORK();
214 
215 	if (cpid == 0) {
216 		while (count-- > 0) {
217 			usleep(usec);
218 			if (kill(pid, sig) == -1)
219 				break;
220 		}
221 		exit(0);
222 	}
223 
224 	return cpid;
225 }
226 
do_test(unsigned int i)227 static void do_test(unsigned int i)
228 {
229 	pid_t pid = 0;
230 	int sys_ret, sys_errno = 0, dummy;
231 	struct test_case *tc = &tcase[i];
232 
233 	tst_res(TINFO, "case %s", tc->desc);
234 
235 	/* setup */
236 	if (tc->sigmask_cur) {
237 	       if (sigprocmask(SIG_SETMASK, tc->sigmask_cur, NULL) == -1)
238 			tst_brk(TBROK, "sigprocmask");
239 	}
240 	if (tc->sigint_count > 0) {
241 		pid = create_sig_proc(SIGINT, tc->sigint_count,
242 			tc->sigint_delay);
243 	}
244 
245 	/* test */
246 	sys_ret = tst_syscall(__NR_ppoll, tc->fds, tc->nfds, tc->ts,
247 		tc->sigmask, SIGSETSIZE);
248 	sys_errno = errno;
249 
250 	/* cleanup */
251 	if (tc->sigmask_cur) {
252 		if (sigprocmask(SIG_SETMASK, &sigmask_empty, NULL) == -1)
253 			tst_brk(TBROK, "sigprocmask");
254 	}
255 	if (pid > 0) {
256 		kill(pid, SIGTERM);
257 		SAFE_WAIT(&dummy);
258 	}
259 
260 	/* result check */
261 	if (tc->expect_revents) {
262 		if (tc->fds[0].revents == tc->expect_revents)
263 			tst_res(TPASS, "revents=0x%04x", tc->expect_revents);
264 		else
265 			tst_res(TFAIL, "revents=0x%04x, expected=0x%04x",
266 				tc->fds[0].revents, tc->expect_revents);
267 	}
268 	if (tc->ret >= 0 && tc->ret == sys_ret) {
269 		tst_res(TPASS, "ret: %d", sys_ret);
270 	} else if (tc->ret == -1 && sys_ret == -1 && sys_errno == tc->err) {
271 		tst_res(TPASS, "ret: %d, errno: %s (%d)", sys_ret,
272 			tst_strerrno(sys_errno), sys_errno);
273 	} else {
274 		tst_res(TFAIL, "ret: %d, exp: %d, ret_errno: %s (%d),"
275 			" exp_errno: %s (%d)", tc->ret, sys_ret,
276 			tst_strerrno(sys_errno), sys_errno,
277 			tst_strerrno(tc->err), tc->err);
278 	}
279 }
280 
281 static struct tst_test test = {
282 	.tid = "ppoll01",
283 	.tcnt = ARRAY_SIZE(tcase),
284 	.test = do_test,
285 	.setup = setup,
286 	.cleanup = cleanup,
287 	.forks_child = 1,
288 	.needs_tmpdir = 1,
289 };
290