#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1