• 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 "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