• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 Fujitsu Ltd.
3  * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 /*
19  * Description:
20  * Verify that:
21  *     Basic test for fcntl(2) using F_GETOWN, F_SETOWN, F_GETOWN_EX,
22  *     F_SETOWN_EX, F_GETSIG, F_SETSIG argument.
23  */
24 
25 #include <stdio.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <pwd.h>
34 #include <sched.h>
35 
36 #include "test.h"
37 #include "config.h"
38 #include "linux_syscall_numbers.h"
39 #include "safe_macros.h"
40 #include "lapi/fcntl.h"
41 
42 static void setup(void);
43 static void cleanup(void);
44 
45 static void setown_pid_test(void);
46 static void setown_pgrp_test(void);
47 
48 #if defined(HAVE_STRUCT_F_OWNER_EX)
49 static int ownex_enabled;
50 static char *ownex_tconf_msg = "F_GETOWN_EX and F_SETOWN_EX only run on "
51 			"kernels that are 2.6.32 and higher";
52 static void setownex_tid_test(void);
53 static void setownex_pid_test(void);
54 static void setownex_pgrp_test(void);
55 
56 static struct f_owner_ex orig_own_ex;
57 #endif
58 
59 static void signal_parent(void);
60 static void check_io_signal(char *des);
61 static void test_set_and_get_sig(int sig, char *des);
62 
63 static pid_t pid;
64 static pid_t orig_pid;
65 static pid_t pgrp_pid;
66 
67 static struct timespec timeout;
68 static sigset_t newset, oldset;
69 
70 static int test_fd;
71 static int pipe_fds[2];
72 
73 static void (*testfunc[])(void) = {
74 	setown_pid_test, setown_pgrp_test,
75 #if defined(HAVE_STRUCT_F_OWNER_EX)
76 	setownex_tid_test, setownex_pid_test, setownex_pgrp_test
77 #endif
78 };
79 
80 char *TCID = "fcntl31";
81 int TST_TOTAL = ARRAY_SIZE(testfunc);
82 
83 
main(int ac,char ** av)84 int main(int ac, char **av)
85 {
86 	int lc, i;
87 
88 	tst_parse_opts(ac, av, NULL, NULL);
89 
90 	setup();
91 
92 	for (lc = 0; TEST_LOOPING(lc); lc++) {
93 		tst_count = 0;
94 
95 		for (i = 0; i < TST_TOTAL; i++)
96 			(*testfunc[i])();
97 	}
98 
99 	cleanup();
100 	tst_exit();
101 }
102 
setup(void)103 static void setup(void)
104 {
105 	int ret;
106 
107 	tst_sig(FORK, DEF_HANDLER, cleanup);
108 
109 	TEST_PAUSE;
110 
111 	/* we have these tests on pipe */
112 	SAFE_PIPE(cleanup, pipe_fds);
113 	test_fd = pipe_fds[0];
114 	if (fcntl(test_fd, F_SETFL, O_ASYNC) < 0)
115 		tst_brkm(TBROK | TERRNO, cleanup, "fcntl set O_ASYNC failed");
116 
117 	pid = getpid();
118 
119 	ret = setpgrp();
120 	if (ret < 0)
121 		tst_brkm(TBROK | TERRNO, cleanup, "setpgrp() failed");
122 	pgrp_pid = getpgid(0);
123 	if (pgrp_pid < 0)
124 		tst_brkm(TBROK | TERRNO, cleanup, "getpgid() failed");
125 
126 #if defined(HAVE_STRUCT_F_OWNER_EX)
127 	if ((tst_kvercmp(2, 6, 32)) >= 0) {
128 		ownex_enabled = 1;
129 
130 		/* get original f_owner_ex info */
131 		TEST(fcntl(test_fd, F_GETOWN_EX, &orig_own_ex));
132 		if (TEST_RETURN < 0) {
133 			tst_brkm(TFAIL | TTERRNO, cleanup,
134 				 "fcntl get original f_owner_ex info failed");
135 		}
136 	}
137 #endif
138 
139 	/* get original pid info */
140 	TEST(fcntl(test_fd, F_GETOWN));
141 	if (TEST_RETURN < 0) {
142 		tst_brkm(TFAIL | TTERRNO, cleanup,
143 			 "fcntl get original pid info failed");
144 	}
145 	orig_pid = TEST_RETURN;
146 
147 	sigemptyset(&newset);
148 	sigaddset(&newset, SIGUSR1);
149 	sigaddset(&newset, SIGIO);
150 
151 	if (sigprocmask(SIG_SETMASK, &newset, &oldset) < 0)
152 		tst_brkm(TBROK | TERRNO, cleanup, "sigprocmask failed");
153 
154 	timeout.tv_sec = 5;
155 	timeout.tv_nsec = 0;
156 }
157 
setown_pid_test(void)158 static void setown_pid_test(void)
159 {
160 	TEST(fcntl(test_fd, F_SETOWN, pid));
161 	if (TEST_RETURN < 0) {
162 		tst_brkm(TFAIL | TTERRNO, cleanup,
163 			 "fcntl(F_SETOWN) set process id failed");
164 	}
165 	test_set_and_get_sig(SIGUSR1, "F_GETOWN, F_SETOWN for process ID");
166 
167 	TEST(fcntl(test_fd, F_SETOWN, orig_pid));
168 	if (TEST_RETURN < 0) {
169 		tst_brkm(TFAIL | TTERRNO, cleanup,
170 			 "fcntl(F_SETOWN) restore orig_pid failed");
171 	}
172 }
173 
setown_pgrp_test(void)174 static void setown_pgrp_test(void)
175 {
176 	TEST(fcntl(test_fd, F_SETOWN, -pgrp_pid));
177 	if (TEST_RETURN < 0) {
178 		tst_brkm(TFAIL | TTERRNO, cleanup,
179 			 "fcntl(F_SETOWN) set process group id failed");
180 	}
181 	test_set_and_get_sig(SIGUSR1,
182 			     "F_GETOWN, F_SETOWN for process group ID");
183 
184 	TEST(fcntl(test_fd, F_SETOWN, orig_pid));
185 	if (TEST_RETURN < 0) {
186 		tst_brkm(TFAIL | TTERRNO, cleanup,
187 			 "fcntl(F_SETOWN) restore orig_pid failed");
188 	}
189 }
190 
191 #if defined(HAVE_STRUCT_F_OWNER_EX)
setownex_cleanup(void)192 static void setownex_cleanup(void)
193 {
194 	TEST(fcntl(test_fd, F_SETOWN_EX, &orig_own_ex));
195 	if (TEST_RETURN < 0) {
196 		tst_brkm(TFAIL | TTERRNO, cleanup,
197 			 "fcntl F_SETOWN_EX restore orig_own_ex failed");
198 	}
199 }
200 
setownex_tid_test(void)201 static void setownex_tid_test(void)
202 {
203 	static struct f_owner_ex tst_own_ex;
204 
205 	if (ownex_enabled == 0) {
206 		tst_resm(TCONF, "%s", ownex_tconf_msg);
207 		return;
208 	}
209 
210 	tst_own_ex.type = F_OWNER_TID;
211 	tst_own_ex.pid = ltp_syscall(__NR_gettid);
212 
213 	TEST(fcntl(test_fd, F_SETOWN_EX, &tst_own_ex));
214 	if (TEST_RETURN < 0) {
215 		tst_brkm(TFAIL | TTERRNO, cleanup,
216 			 "fcntl F_SETOWN_EX failed");
217 	}
218 	test_set_and_get_sig(SIGUSR1, "F_GETOWN_EX, F_SETOWN_EX for thread ID");
219 
220 	setownex_cleanup();
221 }
222 
setownex_pid_test(void)223 static void setownex_pid_test(void)
224 {
225 	static struct f_owner_ex tst_own_ex;
226 
227 	if (ownex_enabled == 0) {
228 		tst_resm(TCONF, "%s", ownex_tconf_msg);
229 		return;
230 	}
231 
232 	tst_own_ex.type = F_OWNER_PID;
233 	tst_own_ex.pid = pid;
234 
235 	TEST(fcntl(test_fd, F_SETOWN_EX, &tst_own_ex));
236 	if (TEST_RETURN < 0) {
237 		tst_brkm(TFAIL | TTERRNO, cleanup,
238 			 "fcntl F_SETOWN_EX failed");
239 	}
240 	test_set_and_get_sig(SIGUSR1,
241 			     "F_GETOWN_EX, F_SETOWN_EX for process ID");
242 
243 	setownex_cleanup();
244 }
245 
setownex_pgrp_test(void)246 static void setownex_pgrp_test(void)
247 {
248 	static struct f_owner_ex tst_own_ex;
249 
250 	if (ownex_enabled == 0) {
251 		tst_resm(TCONF, "%s", ownex_tconf_msg);
252 		return;
253 	}
254 
255 	tst_own_ex.type = F_OWNER_PGRP;
256 	tst_own_ex.pid = pgrp_pid;
257 
258 	TEST(fcntl(test_fd, F_SETOWN_EX, &tst_own_ex));
259 	if (TEST_RETURN < 0) {
260 		tst_brkm(TFAIL | TTERRNO, cleanup,
261 			 "fcntl F_SETOWN_EX failed");
262 	}
263 	test_set_and_get_sig(SIGUSR1,
264 			     "F_GETOWN_EX, F_SETOWN_EX for process group ID");
265 
266 	setownex_cleanup();
267 }
268 #endif
269 
test_set_and_get_sig(int sig,char * des)270 static void test_set_and_get_sig(int sig, char *des)
271 {
272 	int orig_sig;
273 
274 	TEST(fcntl(test_fd, F_GETSIG));
275 	if (TEST_RETURN < 0) {
276 		tst_brkm(TFAIL | TTERRNO, cleanup,
277 			 "fcntl(fd, F_GETSIG) get orig_sig failed");
278 	}
279 	orig_sig = TEST_RETURN;
280 
281 	if (orig_sig == 0 || orig_sig == SIGIO)
282 		tst_resm(TINFO, "default io events signal is SIGIO");
283 
284 	TEST(fcntl(test_fd, F_SETSIG, sig));
285 	if (TEST_RETURN < 0) {
286 		tst_brkm(TFAIL | TTERRNO, cleanup,
287 			 "fcntl(fd, F_SETSIG, SIG: %d) failed", sig);
288 	}
289 
290 	TEST(fcntl(test_fd, F_GETSIG));
291 	if (TEST_RETURN < 0) {
292 		tst_brkm(TFAIL | TTERRNO, cleanup,
293 			 "fcntl(fd, F_GETSIG) get the set signal failed");
294 	}
295 	if (TEST_RETURN != sig) {
296 		tst_brkm(TFAIL | TTERRNO, cleanup,
297 			 "fcntl F_SETSIG set SIG: %d failed", sig);
298 	}
299 
300 	check_io_signal(des);
301 
302 	/* restore the default signal*/
303 	TEST(fcntl(test_fd, F_SETSIG, orig_sig));
304 	if (TEST_RETURN < 0) {
305 		tst_brkm(TFAIL | TTERRNO, cleanup,
306 			 "fcntl restore default signal failed");
307 	}
308 }
309 
signal_parent(void)310 static void signal_parent(void)
311 {
312 	int ret, fd;
313 
314 	fd = pipe_fds[1];
315 	close(pipe_fds[0]);
316 
317 	ret = setpgrp();
318 	if (ret < 0) {
319 		fprintf(stderr, "child process(%d) setpgrp() failed: %s \n",
320 			getpid(), strerror(errno));
321 	}
322 
323 	/* Wait for parent process to enter sigtimedwait(). */
324 	tst_process_state_wait2(getppid(), 'S');
325 
326 	ret = write(fd, "c", 1);
327 
328 	switch (ret) {
329 	case 0:
330 		fprintf(stderr, "No data written, something is wrong\n");
331 	break;
332 	case -1:
333 		fprintf(stderr, "Failed to write to pipe: %s\n",
334 			strerror(errno));
335 	break;
336 	}
337 
338 	close(fd);
339 	return;
340 }
341 
check_io_signal(char * des)342 static void check_io_signal(char *des)
343 {
344 	int ret;
345 	char c;
346 	pid_t child;
347 
348 	child = tst_fork();
349 	if (child < 0)
350 		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
351 
352 	if (child == 0) {
353 		signal_parent();
354 		exit(0);
355 	} else {
356 		ret = sigtimedwait(&newset, NULL, &timeout);
357 		if (ret == -1) {
358 			tst_brkm(TBROK | TERRNO, NULL,
359 				 "sigtimedwait() failed.");
360 		}
361 
362 		switch (ret) {
363 		case SIGUSR1:
364 			tst_resm(TPASS, "fcntl test %s success", des);
365 		break;
366 		case SIGIO:
367 			tst_resm(TFAIL, "received default SIGIO, fcntl test "
368 				 "%s failed", des);
369 		break;
370 		default:
371 			tst_brkm(TBROK, cleanup, "fcntl io events "
372 				 "signal mechanism work abnormally");
373 		}
374 
375 		SAFE_READ(cleanup, 1, test_fd, &c, 1);
376 		wait(NULL);
377 	}
378 }
379 
cleanup(void)380 static void cleanup(void)
381 {
382 	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
383 		tst_resm(TWARN | TERRNO, "sigprocmask restore oldset failed");
384 
385 	if (pipe_fds[0] > 0 && close(pipe_fds[0]) == -1)
386 		tst_resm(TWARN | TERRNO, "close(%d) failed", pipe_fds[0]);
387 	if (pipe_fds[1] > 0 && close(pipe_fds[1]) == -1)
388 		tst_resm(TWARN | TERRNO, "close(%d) failed", pipe_fds[1]);
389 }
390