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 }