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