1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * fcntl20.c 23 * 24 * DESCRIPTION 25 * Check locking of regions of a file 26 * 27 * ALGORITHM 28 * Test unlocking sections around a read lock 29 * 30 * USAGE 31 * fcntl20 32 * 33 * HISTORY 34 * 07/2001 Ported by Wayne Boyer 35 * 36 * RESTRICTIONS 37 * None 38 */ 39 40 #include <fcntl.h> 41 #include <errno.h> 42 #include <signal.h> 43 #include <sys/stat.h> 44 #include <sys/types.h> 45 #include <sys/wait.h> 46 #include <inttypes.h> 47 #include "test.h" 48 #include "safe_macros.h" 49 50 #define STRINGSIZE 27 51 #define STRING "abcdefghijklmnopqrstuvwxyz\n" 52 #define STOP 0xFFF0 53 54 int parent_pipe[2]; 55 int child_pipe[2]; 56 int fd; 57 pid_t parent_pid, child_pid; 58 59 void parent_put(); 60 void parent_get(); 61 void child_put(); 62 void child_get(); 63 void stop_child(); 64 void compare_lock(struct flock *, short, short, int, int, pid_t); 65 void unlock_file(); 66 void do_test(struct flock *, short, short, int, int); 67 void catch_child(); 68 char *str_type(); 69 int do_lock(int, short, short, int, int); 70 71 char *TCID = "fcntl20"; 72 int TST_TOTAL = 1; 73 74 void setup(void); 75 void cleanup(void); 76 77 int fail = 0; 78 79 /* 80 * setup 81 * performs all ONE TIME setup for this test 82 */ 83 void setup(void) 84 { 85 char *buf = STRING; 86 char template[PATH_MAX]; 87 struct sigaction act; 88 89 tst_sig(FORK, DEF_HANDLER, cleanup); 90 91 umask(0); 92 93 TEST_PAUSE; 94 95 parent_pid = getpid(); 96 97 SAFE_PIPE(NULL, parent_pipe); 98 SAFE_PIPE(NULL, child_pipe); 99 100 tst_tmpdir(); 101 102 snprintf(template, PATH_MAX, "fcntl20XXXXXX"); 103 104 if ((fd = mkstemp(template)) == -1) 105 tst_resm(TFAIL | TERRNO, "mkstemp failed"); 106 107 SAFE_WRITE(cleanup, 0, fd, buf, STRINGSIZE); 108 109 memset(&act, 0, sizeof(act)); 110 act.sa_handler = catch_child; 111 sigemptyset(&act.sa_mask); 112 sigaddset(&act.sa_mask, SIGCLD); 113 if (sigaction(SIGCLD, &act, NULL) == -1) 114 tst_brkm(TFAIL | TERRNO, cleanup, "SIGCLD signal setup failed"); 115 } 116 117 void cleanup(void) 118 { 119 SAFE_CLOSE(NULL, fd); 120 121 tst_rmdir(); 122 123 } 124 125 void do_child(void) 126 { 127 struct flock fl; 128 129 close(parent_pipe[1]); 130 close(child_pipe[0]); 131 while (1) { 132 child_get(&fl); 133 if (fcntl(fd, F_GETLK, &fl) < 0) { 134 tst_resm(TFAIL | TERRNO, "fcntl on file failed"); 135 fail = 1; 136 } 137 child_put(&fl); 138 } 139 } 140 141 int do_lock(int cmd, short type, short whence, int start, int len) 142 { 143 struct flock fl; 144 145 fl.l_type = type; 146 fl.l_whence = whence; 147 fl.l_start = start; 148 fl.l_len = len; 149 return (fcntl(fd, cmd, &fl)); 150 } 151 152 void do_test(struct flock *fl, short type, short whence, int start, int len) 153 { 154 fl->l_type = type; 155 fl->l_whence = whence; 156 fl->l_start = start; 157 fl->l_len = len; 158 fl->l_pid = (short)0; 159 160 parent_put(fl); 161 parent_get(fl); 162 } 163 164 void 165 compare_lock(struct flock *fl, short type, short whence, int start, int len, 166 pid_t pid) 167 { 168 if (fl->l_type != type) { 169 tst_resm(TFAIL, "lock type is wrong should be %s is %s", 170 str_type(type), str_type(fl->l_type)); 171 fail = 1; 172 } 173 174 if (fl->l_whence != whence) { 175 tst_resm(TFAIL, "lock whence is wrong should be %d is %d", 176 whence, fl->l_whence); 177 fail = 1; 178 } 179 180 if (fl->l_start != start) { 181 tst_resm(TFAIL, "region starts in wrong place, should be" 182 "%d is %" PRId64, start, (int64_t) fl->l_start); 183 fail = 1; 184 } 185 186 if (fl->l_len != len) { 187 tst_resm(TFAIL, 188 "region length is wrong, should be %d is %" PRId64, 189 len, (int64_t) fl->l_len); 190 fail = 1; 191 } 192 193 if (fl->l_pid != pid) { 194 tst_resm(TFAIL, "locking pid is wrong, should be %d is %d", 195 pid, fl->l_pid); 196 fail = 1; 197 } 198 } 199 200 void unlock_file(void) 201 { 202 struct flock fl; 203 204 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 0, 0) < 0) { 205 tst_resm(TFAIL, "fcntl on file failed, errno =%d", errno); 206 fail = 1; 207 } 208 do_test(&fl, F_WRLCK, 0, 0, 0); 209 compare_lock(&fl, (short)F_UNLCK, (short)0, 0, 0, (pid_t) 0); 210 } 211 212 char *str_type(int type) 213 { 214 static char buf[20]; 215 216 switch (type) { 217 case 1: 218 return ("F_RDLCK"); 219 case 2: 220 return ("F_WRLCK"); 221 case 3: 222 return ("F_UNLCK"); 223 default: 224 sprintf(buf, "BAD VALUE: %d", type); 225 return (buf); 226 } 227 } 228 229 void parent_put(struct flock *l) 230 { 231 if (write(parent_pipe[1], l, sizeof(*l)) != sizeof(*l)) { 232 tst_resm(TFAIL, "couldn't send message to child"); 233 fail = 1; 234 } 235 } 236 237 void parent_get(struct flock *l) 238 { 239 if (read(child_pipe[0], l, sizeof(*l)) != sizeof(*l)) { 240 tst_resm(TFAIL, "couldn't get message from child"); 241 fail = 1; 242 } 243 } 244 245 void child_put(struct flock *l) 246 { 247 if (write(child_pipe[1], l, sizeof(*l)) != sizeof(*l)) { 248 tst_resm(TFAIL, "couldn't send message to parent"); 249 fail = 1; 250 } 251 } 252 253 void child_get(struct flock *l) 254 { 255 if (read(parent_pipe[0], l, sizeof(*l)) != sizeof(*l)) { 256 tst_resm(TFAIL, "couldn't get message from parent"); 257 cleanup(); 258 } else if (l->l_type == (short)STOP) { 259 exit(0); 260 } 261 } 262 263 void stop_child(void) 264 { 265 struct flock fl; 266 267 signal(SIGCLD, SIG_DFL); 268 fl.l_type = STOP; 269 parent_put(&fl); 270 wait(0); 271 } 272 273 void catch_child(void) 274 { 275 tst_resm(TFAIL, "Unexpected death of child process"); 276 cleanup(); 277 } 278 279 int main(int ac, char **av) 280 { 281 struct flock tl; 282 283 int lc; 284 285 tst_parse_opts(ac, av, NULL, NULL); 286 #ifdef UCLINUX 287 maybe_run_child(&do_child, "ddddd", &parent_pipe[0], &parent_pipe[1], 288 &child_pipe[0], &child_pipe[1], &fd); 289 #endif 290 291 setup(); /* global setup */ 292 293 /* Check for looping state if -i option is given */ 294 for (lc = 0; TEST_LOOPING(lc); lc++) { 295 /* reset tst_count in case we are looping */ 296 tst_count = 0; 297 298 if ((child_pid = FORK_OR_VFORK()) == 0) { /* child */ 299 #ifdef UCLINUX 300 if (self_exec 301 (av[0], "ddddd", parent_pipe[0], parent_pipe[1], 302 child_pipe[0], child_pipe[1], fd) < 0) { 303 tst_resm(TFAIL, "self_exec failed"); 304 cleanup(); 305 } 306 #else 307 do_child(); 308 #endif 309 } 310 311 if (child_pid < 0) { 312 tst_resm(TFAIL, "Fork failed"); 313 cleanup(); 314 } 315 316 (void)close(parent_pipe[0]); 317 (void)close(child_pipe[1]); 318 319 /* //block1: */ 320 tst_resm(TINFO, "Enter block 1"); 321 /* 322 * Add a read lock to the middle of the file and unlock a 323 * section just before the lock 324 */ 325 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 326 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 327 errno); 328 fail = 1; 329 } 330 331 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 5) < 0) { 332 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 333 errno); 334 fail = 1; 335 } 336 337 /* 338 * Test read lock 339 */ 340 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 341 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid); 342 343 /* 344 * Test that the rest of the file is unlocked 345 */ 346 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0); 347 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t) 0); 348 349 /* 350 * remove all the locks set above 351 */ 352 unlock_file(); 353 354 if (fail) { 355 tst_resm(TINFO, "Test block 1: FAILED"); 356 } else { 357 tst_resm(TINFO, "Test block 1: PASSED"); 358 } 359 tst_resm(TINFO, "Exit block 1"); 360 361 /* //block2: */ 362 tst_resm(TINFO, "Enter block 2"); 363 fail = 0; 364 /* 365 * Set a read lock in the middle and do an unlock that 366 * ends at the first byte of the read lock. 367 */ 368 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 369 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 370 errno); 371 fail = 1; 372 } 373 374 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 6) < 0) { 375 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 376 errno); 377 fail = 1; 378 } 379 380 /* 381 * Test read lock 382 */ 383 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 384 compare_lock(&tl, (short)F_RDLCK, (short)0, 11, 4, parent_pid); 385 386 /* 387 * Test to make sure the rest of the file is unlocked 388 */ 389 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0); 390 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t) 0); 391 392 /* 393 * remove all the locks set above 394 */ 395 unlock_file(); 396 397 if (fail) 398 tst_resm(TINFO, "Test block 2: FAILED"); 399 else 400 tst_resm(TINFO, "Test block 2: PASSED"); 401 tst_resm(TINFO, "Exit block 2"); 402 403 /* //block3: */ 404 tst_resm(TINFO, "Enter block 3"); 405 fail = 0; 406 407 /* 408 * Set a read lock on the middle of the file and do an 409 * unlock that overlaps the front of the read 410 */ 411 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 412 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 413 errno); 414 fail = 1; 415 } 416 417 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 8) < 0) { 418 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 419 errno); 420 fail = 1; 421 } 422 423 /* 424 * Test the read lock 425 */ 426 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 427 compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 2, parent_pid); 428 429 /* 430 * Test to make sure the rest of the file is unlocked 431 */ 432 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0); 433 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t) 0); 434 435 /* 436 * remove all the locks set above 437 */ 438 unlock_file(); 439 440 if (fail) 441 tst_resm(TINFO, "Test block 3: FAILED"); 442 else 443 tst_resm(TINFO, "Test block 3: PASSED"); 444 tst_resm(TINFO, "Exit block 3"); 445 446 /* //block4: */ 447 tst_resm(TINFO, "Enter blcok 4"); 448 fail = 0; 449 450 /* 451 * Set a read lock in the middle of a file and unlock a 452 * section in the middle of it 453 */ 454 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 10) < 0) { 455 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 456 errno); 457 fail = 1; 458 } 459 460 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 13, 5) < 0) { 461 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 462 errno); 463 fail = 1; 464 } 465 466 /* 467 * Test the first read lock 468 */ 469 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 470 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid); 471 472 /* 473 * Test the second read lock 474 */ 475 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0); 476 compare_lock(&tl, (short)F_RDLCK, (short)0, 18, 2, parent_pid); 477 478 /* 479 * Test to make sure the rest of the file is unlocked 480 */ 481 do_test(&tl, (short)F_WRLCK, (short)0, 20, 0); 482 compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, (pid_t) 0); 483 484 /* 485 * remove all the locks set above 486 */ 487 unlock_file(); 488 489 if (fail) 490 tst_resm(TINFO, "Test block 4: FAILED"); 491 else 492 tst_resm(TINFO, "Test block 4: PASSED"); 493 tst_resm(TINFO, "Exit block 4"); 494 495 /* //block5: */ 496 tst_resm(TINFO, "Enter block 5"); 497 fail = 0; 498 499 /* 500 * Set a read lock in the middle of the file and do a 501 * unlock that overlaps the end 502 */ 503 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 504 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 505 errno); 506 fail = 1; 507 } 508 509 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 13, 5) < 0) { 510 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 511 errno); 512 fail = 1; 513 } 514 515 /* 516 * Test the read lock 517 */ 518 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 519 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid); 520 521 /* 522 * Test to make sure the rest of the file is unlocked 523 */ 524 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0); 525 compare_lock(&tl, (short)F_UNLCK, (short)0, 13, 0, (pid_t) 0); 526 527 /* 528 * remove all the locks set above 529 */ 530 unlock_file(); 531 532 if (fail) 533 tst_resm(TINFO, "Test block 5: FAILED"); 534 else 535 tst_resm(TINFO, "Test block 5: PASSED"); 536 tst_resm(TINFO, "Exit block 5"); 537 538 /* //block6: */ 539 tst_resm(TINFO, "Enter block 6"); 540 fail = 0; 541 542 /* 543 * Set read lock in the middle of the file and do an unlock 544 * starting at the last byte of the read lock 545 */ 546 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 547 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 548 errno); 549 fail = 1; 550 } 551 552 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 14, 5) < 0) { 553 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 554 errno); 555 fail = 1; 556 } 557 558 /* 559 * Test read lock 560 */ 561 do_test(&tl, (short)F_WRLCK, (short)0, 10, 0); 562 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 4, parent_pid); 563 564 /* 565 * Test to make sure the end of the file is unlocked 566 */ 567 do_test(&tl, (short)F_WRLCK, (short)0, 14, 0); 568 compare_lock(&tl, (short)F_UNLCK, (short)0, 14, 0, (pid_t) 0); 569 570 /* 571 * remove all the locks set above 572 */ 573 unlock_file(); 574 575 if (fail) 576 tst_resm(TINFO, "Test block 6: FAILED"); 577 else 578 tst_resm(TINFO, "Test block 6: PASSED"); 579 tst_resm(TINFO, "Exit block 6"); 580 581 /* //block7: */ 582 tst_resm(TINFO, "Enter block 7"); 583 fail = 0; 584 585 /* 586 * Set a read lock at the middle of the file and do an 587 * unlock that starts at the byte past the end of the read 588 * lock 589 */ 590 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) { 591 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 592 errno); 593 fail = 1; 594 } 595 596 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 16, 0) < 0) { 597 tst_resm(TFAIL, "fcntl on file failed, errno =%d", 598 errno); 599 fail = 1; 600 } 601 602 /* 603 * Test the read lock 604 */ 605 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0); 606 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid); 607 608 /* 609 * Test to make sure the rest of the file is unlocked 610 */ 611 do_test(&tl, (short)F_WRLCK, (short)0, 16, 0); 612 compare_lock(&tl, (short)F_UNLCK, (short)0, 16, 0, (pid_t) 0); 613 614 /* 615 * remove all the locks set above 616 */ 617 unlock_file(); 618 619 if (fail) 620 tst_resm(TINFO, "Test block 7: FAILED"); 621 else 622 tst_resm(TINFO, "Test block 7: PASSED"); 623 624 tst_resm(TINFO, "Exit block 7"); 625 626 stop_child(); 627 } 628 cleanup(); 629 tst_exit(); 630 } 631