Home | History | Annotate | Download | only in fcntl
      1 /*
      2  * Copyright (c) 2014 Fujitsu Ltd.
      3  * Author: Xiaoguang Wang <wangxg.fnst (at) 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 
     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 
    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 
    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 
    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)
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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