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