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