#include #include #include #include #include #include #include #include "file_lock.h" int main(int argc, char *const argv[]) { int wait_for_lock = 1; int exit_status_on_lock_failure = 1; int program_holds_lock = 1; int lock_fd; int option; const char *lock_file_name; int (*locker)(int); int child_pid; char *const *new_argv; int child_status; while ((option = getopt(argc, argv, "nNxXcC")) != -1) { switch (option) { case 'n': wait_for_lock = 0; break; case 'N': wait_for_lock = 1; break; case 'x': exit_status_on_lock_failure = 0; break; case 'X': exit_status_on_lock_failure = 1; break; case 'c': program_holds_lock = 0; break; case 'C': program_holds_lock = 1; break; } } if (optind + 1 >= argc) { fprintf(stderr, "Usage: %s lock_file command...\n", argv[0]); exit(1); } lock_file_name = argv[optind]; new_argv = argv + optind + 1; lock_fd = open(lock_file_name, O_WRONLY|O_CREAT|O_NONBLOCK, 0600); if (lock_fd == -1) { perror("open of lock file failed"); exit(exit_status_on_lock_failure); } /* Choose a lock function */ locker = wait_for_lock ? file_lock : file_trylock; file_lock_init(); if (locker(lock_fd) != 0) { perror("Could not lock file"); exit(exit_status_on_lock_failure); } /* If we must prevent the program from holding the lock fd, we need * to fork-exec the process, close the fd, and wait for its * completion while we hold the lock */ if (!program_holds_lock) { child_pid = fork(); if (child_pid < 0) { perror("fork"); exit(1); } else if (child_pid > 0) { /* Wait for the child to complete */ if (waitpid(child_pid, &child_status, 0) < 0) { perror("Error waiting for child"); exit(1); } exit(WEXITSTATUS(child_status)); } else { /* I'm the lockless child. Close the lock and run the * program */ close(lock_fd); } } execvp(*new_argv, new_argv); perror("execvp"); exit(1); }