1 /*
2  *
3  *   Copyright (c) Red Hat Inc., 2008
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  *	signalfd01.c
23  *
24  * DESCRIPTION
25  *	Check signalfd can receive signals
26  *
27  * USAGE
28  * 	signalfd01
29  *
30  * HISTORY
31  *	9/2008 Initial version by Masatake YAMATO <yamato@redhat.com>
32  *
33  * RESTRICTIONS
34  * 	None
35  */
36 #define _GNU_SOURCE
37 
38 #include "config.h"
39 
40 #include "test.h"
41 
42 #include <errno.h>
43 #include <signal.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <inttypes.h>
47 #include "ltp_signal.h"
48 
49 TCID_DEFINE(signalfd01);
50 int TST_TOTAL = 1;
51 
52 #ifndef HAVE_SIGNALFD
53 #define  USE_STUB
54 #endif
55 
56 #if defined HAVE_SYS_SIGNALFD_H
57 #include <sys/signalfd.h>
58 #elif defined HAVE_LINUX_SIGNALFD_H
59 #include <linux/signalfd.h>
60 #define USE_OWNIMPL
61 #else
62 #define  USE_STUB
63 #endif
64 
65 #ifndef HAVE_STRUCT_SIGNALFD_SIGINFO_SSI_SIGNO
66 #define USE_STUB
67 #endif
68 
69 #ifdef USE_STUB
main(void)70 int main(void)
71 {
72 	tst_brkm(TCONF, NULL, "System doesn't support execution of the test");
73 }
74 
75 #else
76 #if defined USE_OWNIMPL
77 #include "lapi/syscalls.h"
signalfd(int fd,const sigset_t * mask,int flags)78 int signalfd(int fd, const sigset_t * mask, int flags)
79 {
80 	/* Taken from GLIBC. */
81 	return ltp_syscall(__NR_signalfd, fd, mask, SIGSETSIZE);
82 }
83 #endif
84 
85 void cleanup(void);
86 void setup(void);
87 
do_test1(uint32_t sig)88 int do_test1(uint32_t sig)
89 {
90 	int sfd_for_next;
91 	int sfd;
92 	sigset_t mask;
93 	pid_t pid;
94 	struct signalfd_siginfo fdsi;
95 	ssize_t s;
96 
97 	sigemptyset(&mask);
98 	sigaddset(&mask, sig);
99 	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
100 		tst_brkm(TBROK, cleanup,
101 			 "sigprocmask() Failed: errno=%d : %s",
102 			 errno, strerror(errno));
103 	}
104 
105 	TEST(signalfd(-1, &mask, 0));
106 
107 	if ((sfd = TEST_RETURN) == -1) {
108 		tst_resm(TFAIL,
109 			 "signalfd() Failed, errno=%d : %s",
110 			 TEST_ERRNO, strerror(TEST_ERRNO));
111 		sfd_for_next = -1;
112 		return sfd_for_next;
113 
114 	} else {
115 		tst_resm(TPASS, "signalfd is created successfully");
116 		sfd_for_next = sfd;
117 		goto out;
118 	}
119 
120 	if (fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) {
121 		close(sfd);
122 		tst_brkm(TBROK, cleanup,
123 			 "setting signalfd nonblocking mode failed: errno=%d : %s",
124 			 errno, strerror(errno));
125 	}
126 
127 	pid = getpid();
128 	if (kill(pid, sig) == -1) {
129 		close(sfd);
130 		tst_brkm(TBROK, cleanup,
131 			 "kill(self, %s) failed: errno=%d : %s",
132 			 strsignal(sig), errno, strerror(errno));
133 	}
134 
135 	s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
136 	if ((s > 0) && (s != sizeof(struct signalfd_siginfo))) {
137 		tst_resm(TFAIL,
138 			 "getting incomplete signalfd_siginfo data: "
139 			 "actual-size=%zd, expected-size=%zu",
140 			 s, sizeof(struct signalfd_siginfo));
141 		sfd_for_next = -1;
142 		close(sfd);
143 		goto out;
144 	} else if (s < 0) {
145 		if (errno == EAGAIN) {
146 			tst_resm(TFAIL,
147 				 "signalfd_siginfo data is not delivered yet");
148 			sfd_for_next = -1;
149 			close(sfd);
150 			goto out;
151 		} else {
152 			close(sfd);
153 			tst_brkm(TBROK, cleanup,
154 				 "read signalfd_siginfo data failed: errno=%d : %s",
155 				 errno, strerror(errno));
156 		}
157 	} else if (s == 0) {
158 		tst_resm(TFAIL, "got EOF unexpectedly");
159 		sfd_for_next = -1;
160 		close(sfd);
161 		goto out;
162 	}
163 
164 	if (fdsi.ssi_signo == sig) {
165 		tst_resm(TPASS, "got expected signal");
166 		sfd_for_next = sfd;
167 		goto out;
168 	} else {
169 		tst_resm(TFAIL, "got unexpected signal: signal=%d : %s",
170 			 fdsi.ssi_signo, strsignal(fdsi.ssi_signo));
171 		sfd_for_next = -1;
172 		close(sfd);
173 		goto out;
174 	}
175 
176 out:
177 	return sfd_for_next;
178 }
179 
do_test2(int fd,uint32_t sig)180 void do_test2(int fd, uint32_t sig)
181 {
182 	int sfd;
183 	sigset_t mask;
184 	pid_t pid;
185 	struct signalfd_siginfo fdsi;
186 	ssize_t s;
187 
188 	sigemptyset(&mask);
189 	sigaddset(&mask, sig);
190 	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
191 		close(fd);
192 		tst_brkm(TBROK, cleanup,
193 			 "sigprocmask() Failed: errno=%d : %s",
194 			 errno, strerror(errno));
195 	}
196 
197 	TEST(signalfd(fd, &mask, 0));
198 
199 	if ((sfd = TEST_RETURN) == -1) {
200 		tst_resm(TFAIL,
201 			 "reassignment the file descriptor by signalfd() failed, errno=%d : %s",
202 			 TEST_ERRNO, strerror(TEST_ERRNO));
203 		return;
204 	} else if (sfd != fd) {
205 		tst_resm(TFAIL,
206 			 "different fd is returned in reassignment: expected-fd=%d, actual-fd=%d",
207 			 fd, sfd);
208 		close(sfd);
209 		return;
210 
211 	} else {
212 		tst_resm(TPASS, "signalfd is successfully reassigned");
213 		goto out;
214 	}
215 
216 	pid = getpid();
217 	if (kill(pid, sig) == -1) {
218 		close(sfd);
219 		tst_brkm(TBROK, cleanup,
220 			 "kill(self, %s) failed: errno=%d : %s",
221 			 strsignal(sig), errno, strerror(errno));
222 	}
223 
224 	s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
225 	if ((s > 0) && (s != sizeof(struct signalfd_siginfo))) {
226 		tst_resm(TFAIL,
227 			 "getting incomplete signalfd_siginfo data: "
228 			 "actual-size=%zd, expected-size= %zu",
229 			 s, sizeof(struct signalfd_siginfo));
230 		goto out;
231 	} else if (s < 0) {
232 		if (errno == EAGAIN) {
233 			tst_resm(TFAIL,
234 				 "signalfd_siginfo data is not delivered yet");
235 			goto out;
236 		} else {
237 			close(sfd);
238 			tst_brkm(TBROK, cleanup,
239 				 "read signalfd_siginfo data failed: errno=%d : %s",
240 				 errno, strerror(errno));
241 		}
242 	} else if (s == 0) {
243 		tst_resm(TFAIL, "got EOF unexpectedly");
244 		goto out;
245 	}
246 
247 	if (fdsi.ssi_signo == sig) {
248 		tst_resm(TPASS, "got expected signal");
249 		goto out;
250 	} else {
251 		tst_resm(TFAIL, "got unexpected signal: signal=%d : %s",
252 			 fdsi.ssi_signo),
253 			 strsignal(fdsi.ssi_signo);
254 		goto out;
255 	}
256 
257 out:
258 	return;
259 }
260 
main(int argc,char ** argv)261 int main(int argc, char **argv)
262 {
263 	int lc;
264 	int sfd;
265 
266 	if ((tst_kvercmp(2, 6, 22)) < 0) {
267 		tst_resm(TWARN,
268 			 "This test can only run on kernels that are 2.6.22 and higher");
269 		exit(0);
270 	}
271 
272 	tst_parse_opts(argc, argv, NULL, NULL);
273 
274 	setup();
275 	for (lc = 0; TEST_LOOPING(lc); lc++) {
276 		tst_count = 0;
277 
278 		sfd = do_test1(SIGUSR1);
279 		if (sfd < 0)
280 			continue;
281 
282 		do_test2(sfd, SIGUSR2);
283 		close(sfd);
284 	}
285 
286 	cleanup();
287 
288 	tst_exit();
289 }
290 
291 /*
292  * setup() - performs all the ONE TIME setup for this test.
293  */
setup(void)294 void setup(void)
295 {
296 
297 	TEST_PAUSE;
298 }
299 
300 /*
301  * cleanup() - performs all the ONE TIME cleanup for this test at completion
302  * 	       or premature exit.
303  */
cleanup(void)304 void cleanup(void)
305 {
306 
307 }
308 
309 #endif
310