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