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