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