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