1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2018 Joyent, Inc. 14 */ 15 16 /* 17 * Validate various fcntl(2) and flock(3C) operations. 18 */ 19 20 #include "util.h" 21 #include <err.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <libgen.h> 25 #include <signal.h> 26 #include <stdlib.h> 27 #include <strings.h> 28 #include <sys/debug.h> 29 #include <sys/file.h> 30 #include <sys/stat.h> 31 #include <sys/wait.h> 32 #include <unistd.h> 33 34 35 #define LOCKFILE_FMT "/tmp/.lockfile-%s-%ld" 36 #define LOCKDIR_FMT "/tmp/.lockdir-%s-%ld" 37 38 typedef struct lockinfo { 39 char *lf_name; 40 char *lf_path; 41 int lf_fd; 42 } lockinfo_t; 43 44 45 static void assert_write_locked_by(lockinfo_t *, pid_t); 46 static void assert_read_locked_by(lockinfo_t *, pid_t); 47 static void assert_unlocked(lockinfo_t *); 48 static void assert_all_unlocked(void); 49 50 static int flock_copyfil(lockinfo_t *, lockinfo_t *); 51 static int flock_mkfil(lockinfo_t *); 52 static int flock_mkdir(lockinfo_t *); 53 static void flock_rminfo(lockinfo_t *); 54 55 static void flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl); 56 static void flock_run(lock_style_t, boolean_t, lockinfo_t *, 57 pid_t *, int[]); 58 static int flock_wait(pid_t pid); 59 static void flock_cleanup_child(pid_t, int []); 60 61 static void flock_test_invalid(lockinfo_t *, int, short, short, 62 off_t, off_t); 63 static void flock_test_invalid64(lockinfo_t *, int, short, short, 64 off_t, off_t); 65 static void flock_test_exclusive(lock_style_t, lock_style_t, 66 lockinfo_t *, lockinfo_t *, boolean_t); 67 static void flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *, 68 lockinfo_t *, boolean_t); 69 static void flock_test_upgrade_downgrade(void); 70 71 static char *acqprog = NULL; 72 73 static lockinfo_t flock_fileA = { "a", NULL, -1 }; 74 static lockinfo_t flock_fileB = { "b", NULL, -1 }; 75 static lockinfo_t flock_dirA = { "a", NULL, -1 }; 76 static lockinfo_t flock_dirB = { "b", NULL, -1 }; 77 78 79 static short cmds[8] = { 80 F_SETLK, F_SETLKW, F_GETLK, 81 F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK, 82 F_FLOCK, F_FLOCKW 83 }; 84 85 static short cmds64[3] = { 86 F_OFD_SETLK64, F_OFD_SETLKW64, F_OFD_GETLK64 87 }; 88 89 90 static void 91 flock_kill(pid_t pid) 92 { 93 while (kill(pid, SIGKILL) == -1) { 94 if (errno == EINTR) 95 continue; 96 97 err(EXIT_FAILURE, "kill failed"); 98 } 99 } 100 101 102 static void 103 flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl) 104 { 105 if (fcntl(lf->lf_fd, cmd, fl) == -1) { 106 err(EXIT_FAILURE, "fcntl failed"); 107 } 108 } 109 110 111 static void 112 assert_write_locked_by(lockinfo_t *lf, pid_t pid) 113 { 114 struct flock fl; 115 116 flock_reinit(&fl, F_WRLCK); 117 flock_fcntl(lf, F_GETLK, &fl); 118 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); 119 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 120 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 121 122 flock_reinit(&fl, F_WRLCK); 123 flock_fcntl(lf, F_OFD_GETLK, &fl); 124 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); 125 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 126 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 127 128 flock_reinit(&fl, F_RDLCK); 129 flock_fcntl(lf, F_GETLK, &fl); 130 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); 131 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 132 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 133 134 flock_reinit(&fl, F_RDLCK); 135 flock_fcntl(lf, F_OFD_GETLK, &fl); 136 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); 137 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 138 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 139 } 140 141 142 static void 143 assert_read_locked_by(lockinfo_t *lf, pid_t pid) 144 { 145 struct flock fl; 146 147 flock_reinit(&fl, F_WRLCK); 148 flock_fcntl(lf, F_GETLK, &fl); 149 VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short); 150 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 151 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 152 153 flock_reinit(&fl, F_WRLCK); 154 flock_fcntl(lf, F_OFD_GETLK, &fl); 155 VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short); 156 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 157 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); 158 159 flock_reinit(&fl, F_RDLCK); 160 flock_fcntl(lf, F_GETLK, &fl); 161 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 162 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 163 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 164 165 flock_reinit(&fl, F_RDLCK); 166 flock_fcntl(lf, F_OFD_GETLK, &fl); 167 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 168 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 169 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 170 } 171 172 static void 173 assert_unlocked(lockinfo_t *lf) 174 { 175 struct flock fl; 176 177 flock_reinit(&fl, F_WRLCK); 178 flock_fcntl(lf, F_GETLK, &fl); 179 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 180 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 181 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 182 183 flock_reinit(&fl, F_WRLCK); 184 flock_fcntl(lf, F_OFD_GETLK, &fl); 185 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 186 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 187 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 188 189 flock_reinit(&fl, F_RDLCK); 190 flock_fcntl(lf, F_GETLK, &fl); 191 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 192 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 193 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 194 195 flock_reinit(&fl, F_RDLCK); 196 flock_fcntl(lf, F_OFD_GETLK, &fl); 197 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); 198 VERIFY3_IMPL(fl.l_sysid, ==, 0, int); 199 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); 200 } 201 202 203 static void 204 assert_all_unlocked(void) 205 { 206 assert_unlocked(&flock_fileA); 207 assert_unlocked(&flock_fileB); 208 assert_unlocked(&flock_dirA); 209 assert_unlocked(&flock_dirB); 210 } 211 212 213 static int 214 flock_copyfil(lockinfo_t *src, lockinfo_t *dst) 215 { 216 dst->lf_name = NULL; 217 dst->lf_path = NULL; 218 if ((dst->lf_fd = open(src->lf_path, O_RDWR)) == -1) { 219 warn("Failed to open %s", src->lf_path); 220 return (-1); 221 } 222 223 return (0); 224 } 225 226 227 static int 228 flock_mkfil(lockinfo_t *lf) 229 { 230 if (asprintf(&lf->lf_path, LOCKFILE_FMT, lf->lf_name, getpid()) < 0) { 231 warnx("Failed to generate lockfile name"); 232 return (-1); 233 } 234 235 if ((lf->lf_fd = open(lf->lf_path, O_RDWR|O_CREAT, 0600)) == -1) { 236 warn("Failed to open %s", lf->lf_path); 237 return (-1); 238 } 239 240 return (0); 241 } 242 243 244 static int 245 flock_mkdir(lockinfo_t *lf) 246 { 247 if (asprintf(&lf->lf_path, LOCKDIR_FMT, lf->lf_name, getpid()) < 0) { 248 warnx("Failed to generate lockfile name"); 249 return (-1); 250 } 251 252 if (mkdir(lf->lf_path, 0700) == -1) { 253 warn("Failed to make %s", lf->lf_path); 254 return (-1); 255 } 256 257 if ((lf->lf_fd = open(lf->lf_path, O_RDONLY)) == -1) { 258 warn("Failed to open %s", lf->lf_path); 259 return (-1); 260 } 261 262 return (0); 263 } 264 265 266 static void 267 flock_rminfo(lockinfo_t *lf) 268 { 269 if (lf->lf_fd != -1) { 270 (void) close(lf->lf_fd); 271 } 272 if (lf->lf_path != NULL) { 273 (void) unlink(lf->lf_path); 274 free(lf->lf_path); 275 } 276 } 277 278 279 static void 280 flock_run(lock_style_t style, boolean_t is_exclusive, lockinfo_t *lf, 281 pid_t *pid, int fds[]) 282 { 283 char *stylestr = flock_stylestr(style); 284 char *modestr = is_exclusive ? "exclusive" : "shared"; 285 char *argv[5] = { acqprog, stylestr, modestr, lf->lf_path, NULL }; 286 int ret = pipe(fds); 287 if (ret == -1) { 288 err(EXIT_FAILURE, "pipe failed"); 289 } 290 291 *pid = fork(); 292 if (*pid == (pid_t)-1) { 293 err(EXIT_FAILURE, "fork failed"); 294 } else if (*pid == (pid_t)0) { 295 /* Set up pipe for communicating with child */ 296 ret = dup2(fds[1], 0); 297 if (ret == -1) { 298 err(EXIT_FAILURE, "dup2 failed"); 299 } 300 ret = dup2(fds[1], 1); 301 if (ret == -1) { 302 err(EXIT_FAILURE, "dup2 failed"); 303 } 304 closefrom(3); 305 306 (void) execv(acqprog, argv); 307 err(EXIT_FAILURE, "Failed to execute %s", acqprog); 308 } 309 } 310 311 312 static int 313 flock_wait(pid_t pid) 314 { 315 int childstat = 0; 316 317 while (waitpid(pid, &childstat, 0) == -1) { 318 if (errno == EINTR) 319 continue; 320 321 err(EXIT_FAILURE, "Failed to wait on child"); 322 } 323 324 if (WIFEXITED(childstat)) { 325 return (WEXITSTATUS(childstat)); 326 } else if (WIFSIGNALED(childstat)) { 327 return (1); 328 } else { 329 abort(); 330 return (1); 331 } 332 } 333 334 335 static void 336 flock_cleanup_child(pid_t pid, int fds[]) 337 { 338 (void) flock_wait(pid); 339 (void) close(fds[0]); 340 (void) close(fds[1]); 341 } 342 343 344 static void 345 flock_test_upgrade_downgrade(void) 346 { 347 lockinfo_t afd1, afd2, afd3; 348 pid_t pid; 349 int fds[2]; 350 351 VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); 352 VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); 353 VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); 354 355 flock_log("Acquiring shared locks 1, 2 and 3..."); 356 VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); 357 VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); 358 VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); 359 assert_read_locked_by(&flock_fileA, -1); 360 flock_log(" ok\n"); 361 362 flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK..."); 363 VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 364 VERIFY3U(errno, ==, EWOULDBLOCK); 365 assert_read_locked_by(&flock_fileA, -1); 366 flock_log(" ok\n"); 367 368 flock_log("Upgrading 3 should succeed after releasing locks 1 & 2..."); 369 VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); 370 VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); 371 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 372 assert_write_locked_by(&flock_fileA, -1); 373 flock_log(" ok\n"); 374 375 376 flock_log("Starting up child, then downgrading lock 3 to shared..."); 377 flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds); 378 VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t); 379 VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); 380 flock_block(fds[0]); 381 assert_read_locked_by(&flock_fileA, -1); 382 flock_log(" ok\n"); 383 384 flock_log("Releasing child and upgrading..."); 385 flock_alert(fds[0]); 386 flock_cleanup_child(pid, fds); 387 assert_read_locked_by(&flock_fileA, -1); 388 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 389 assert_write_locked_by(&flock_fileA, -1); 390 flock_log(" ok\n"); 391 392 flock_log("Releasing lock 3..."); 393 VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); 394 flock_rminfo(&afd1); 395 flock_rminfo(&afd2); 396 flock_rminfo(&afd3); 397 assert_all_unlocked(); 398 flock_log(" ok\n"); 399 } 400 401 402 static void 403 flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence, 404 off_t l_start, off_t l_len) 405 { 406 struct flock fl = { 407 .l_type = l_type, 408 .l_whence = l_whence, 409 .l_start = l_start, 410 .l_len = l_len 411 }; 412 413 flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...", 414 flock_cmdname(cmd), l_type, l_whence, l_start, l_len); 415 VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1); 416 VERIFY3U(errno, ==, EINVAL); 417 flock_log(" ok\n"); 418 } 419 420 static void 421 flock_test_invalid64(lockinfo_t *lf, int cmd, short l_type, short l_whence, 422 off_t l_start, off_t l_len) 423 { 424 struct flock64 fl = { 425 .l_type = l_type, 426 .l_whence = l_whence, 427 .l_start = l_start, 428 .l_len = l_len 429 }; 430 431 flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...", 432 flock_cmdname(cmd), l_type, l_whence, l_start, l_len); 433 VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1); 434 VERIFY3U(errno, ==, EINVAL); 435 flock_log(" ok\n"); 436 } 437 438 static void 439 flock_test_exclusive(lock_style_t styleA, lock_style_t styleB, 440 lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) 441 { 442 pid_t pidA, pidB; 443 int fdsA[2], fdsB[2]; 444 445 flock_log("Running %s + %s tests (%s)...", 446 flock_stylename(styleA), flock_stylename(styleB), 447 kill_firstborn ? "kill child" : "child exits"); 448 449 /* Create child, and wait for it to acquire the lock */ 450 flock_run(styleA, B_TRUE, lock1, &pidA, fdsA); 451 flock_block(fdsA[0]); 452 453 /* Create second child, which shouldn't acquire & signal */ 454 flock_run(styleB, B_TRUE, lock1, &pidB, fdsB); 455 VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t); 456 457 /* lock1 is blocked for reading and writing */ 458 assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); 459 assert_unlocked(lock2); 460 461 /* Tell pidA to exit */ 462 if (kill_firstborn) { 463 flock_kill(pidA); 464 } else { 465 flock_alert(fdsA[0]); 466 } 467 flock_cleanup_child(pidA, fdsA); 468 469 /* Wait for pidB to signal us */ 470 flock_block(fdsB[0]); 471 472 /* lock1 is blocked for reading and writing */ 473 assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); 474 assert_unlocked(lock2); 475 476 /* Tell pidB to exit */ 477 flock_alert(fdsB[0]); 478 479 flock_cleanup_child(pidB, fdsB); 480 481 /* 482 * Tests after child has released lock 483 */ 484 assert_all_unlocked(); 485 486 flock_log(" ok\n"); 487 } 488 489 490 static void 491 flock_test_shared(lock_style_t styleA, lock_style_t styleB, 492 lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) 493 { 494 pid_t pidA, pidB; 495 int fdsA[2], fdsB[2]; 496 497 flock_log("Running %s + %s tests (%s)...", 498 flock_stylename(styleA), flock_stylename(styleB), 499 kill_firstborn ? "kill child" : "child exits"); 500 501 /* Create children, and wait for it to acquire the lock */ 502 flock_run(styleB, B_FALSE, lock1, &pidB, fdsB); 503 flock_block(fdsB[0]); 504 flock_run(styleA, B_FALSE, lock1, &pidA, fdsA); 505 flock_block(fdsA[0]); 506 507 /* testfileA is only blocked for writing */ 508 assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); 509 assert_unlocked(lock2); 510 511 /* Tell pidA to exit */ 512 if (kill_firstborn) { 513 flock_kill(pidA); 514 } else { 515 flock_alert(fdsA[0]); 516 } 517 flock_cleanup_child(pidA, fdsA); 518 519 /* testfileA is still blocked for writing by pidB */ 520 assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); 521 assert_unlocked(lock2); 522 523 /* Tell pidB to exit */ 524 flock_alert(fdsB[0]); 525 flock_cleanup_child(pidB, fdsB); 526 527 assert_all_unlocked(); 528 529 flock_log(" ok\n"); 530 } 531 532 533 static void 534 flock_test_ofd_sameproc(void) 535 { 536 lockinfo_t afd1, afd2, afd3; 537 538 VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); 539 VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); 540 VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); 541 542 flock_log("Acquiring first two shared locks..."); 543 VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); 544 VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); 545 assert_read_locked_by(&flock_fileA, -1); 546 flock_log(" ok\n"); 547 548 flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK..."); 549 VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 550 VERIFY3U(errno, ==, EWOULDBLOCK); 551 flock_log(" ok\n"); 552 553 flock_log("Releasing to acquire an exclusive lock..."); 554 VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); 555 VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); 556 flock_log(" ok\n"); 557 558 flock_log("Acquiring an exclusive lock..."); 559 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 560 assert_write_locked_by(&flock_fileA, -1); 561 flock_log(" ok\n"); 562 563 flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK..."); 564 VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 565 VERIFY3U(errno, ==, EWOULDBLOCK); 566 VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 567 VERIFY3U(errno, ==, EWOULDBLOCK); 568 flock_log(" ok\n"); 569 570 flock_log("Releasing exclusive lock..."); 571 VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); 572 assert_all_unlocked(); 573 flock_log(" ok\n"); 574 575 flock_rminfo(&afd1); 576 flock_rminfo(&afd2); 577 flock_rminfo(&afd3); 578 } 579 580 581 static void 582 flock_runtests(void) 583 { 584 lock_style_t first, second; 585 int i; 586 587 flock_log("# Exclusive lock tests\n"); 588 for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { 589 for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { 590 flock_test_exclusive(first, second, 591 &flock_fileA, &flock_fileB, B_TRUE); 592 flock_test_exclusive(first, second, 593 &flock_fileA, &flock_fileB, B_FALSE); 594 } 595 } 596 597 flock_log("# Shared lock tests\n"); 598 for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { 599 for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { 600 flock_test_shared(first, second, 601 &flock_fileA, &flock_fileB, B_TRUE); 602 flock_test_shared(first, second, 603 &flock_fileA, &flock_fileB, B_FALSE); 604 } 605 } 606 607 flock_log("# flock(3C) directory lock tests\n"); 608 flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, 609 &flock_dirA, &flock_dirB, B_TRUE); 610 flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, 611 &flock_dirA, &flock_dirB, B_FALSE); 612 flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, 613 &flock_dirA, &flock_dirB, B_TRUE); 614 flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, 615 &flock_dirA, &flock_dirB, B_FALSE); 616 617 618 flock_log("# Invalid fcntl(2) parameters tests\n"); 619 for (i = 0; i < sizeof (cmds) / sizeof (short); i++) { 620 flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0); 621 flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0); 622 } 623 for (i = 3; i < sizeof (cmds) / sizeof (short); i++) { 624 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0); 625 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0); 626 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1); 627 } 628 for (i = 0; i < sizeof (cmds64) / sizeof (short); i++) { 629 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 1, 0, 0); 630 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 1, 0); 631 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 0, 1); 632 } 633 634 flock_log("# Testing that multiple OFD locks work in a process\n"); 635 flock_test_ofd_sameproc(); 636 637 flock_log("# Testing flock(3C) upgrade/downgrade tests\n"); 638 flock_test_upgrade_downgrade(); 639 } 640 641 642 int 643 main(int argc, char *argv[]) 644 { 645 char *basestr, *suffix, *dirstr, *dirpath; 646 pid_t testrunner; 647 int exval; 648 649 LOG = B_TRUE; 650 651 if (argc < 1) { 652 errx(EXIT_FAILURE, "Can't find program name!"); 653 } 654 655 dirstr = strdup(argv[0]); 656 dirpath = dirname(dirstr); 657 basestr = strdup(argv[0]); 658 suffix = basename(basestr); 659 660 while (*suffix != '.' && *suffix != '\0') { 661 suffix += 1; 662 } 663 664 if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) { 665 errx(EXIT_FAILURE, 666 "Can't generate lock acquisition program name!"); 667 } 668 669 if (access(acqprog, X_OK) != 0) { 670 err(EXIT_FAILURE, 671 "Can't run lock acquisition program %s", acqprog); 672 } 673 674 /* Create several lockfiles for testing */ 675 if (flock_mkfil(&flock_fileA) != 0 || 676 flock_mkfil(&flock_fileB) != 0 || 677 flock_mkdir(&flock_dirA) != 0 || 678 flock_mkdir(&flock_dirB) != 0) { 679 exval = 1; 680 goto cleanup; 681 } 682 683 /* 684 * We run the tests in a child process so that when tests fail 685 * we can still clean up our temporary files. 686 */ 687 testrunner = fork(); 688 if (testrunner == (pid_t)-1) { 689 err(EXIT_FAILURE, "Unable to fork to run tests"); 690 } else if (testrunner == (pid_t)0) { 691 flock_runtests(); 692 return (0); 693 } 694 695 exval = flock_wait(testrunner); 696 697 cleanup: 698 free(basestr); 699 free(dirstr); 700 flock_rminfo(&flock_fileA); 701 flock_rminfo(&flock_fileB); 702 flock_rminfo(&flock_dirA); 703 flock_rminfo(&flock_dirB); 704 return (exval); 705 } 706