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 }