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 "lapi/syscalls.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