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