__attribute__((format(printf,3,4)))
__attribute__((noreturn))
error(int errnum, int exitcode, const char *fmt, ...) {
- va_list ap;
- fprintf(stderr, "%s: ", progname);
- va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
- if (errnum) fprintf(stderr, ": %s\n", strerror(errnum));
- else fputs("\n", stderr);
- exit(exitcode);
+ va_list ap;
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
+ if (errnum)
+ fprintf(stderr, ": %s\n", strerror(errnum));
+ else
+ fputs("\n", stderr);
+ exit(exitcode);
}
static const char *lckfile;
static int quiet;
static void sigalarm(int sig) {
- if (quiet)
- _exit(EX_TEMPFAIL);
- error(0, EX_TEMPFAIL,
- "lock file `%s' is already locked (timeout waiting)", lckfile);
- sig = sig;
+ if (quiet)
+ _exit(EX_TEMPFAIL);
+ error(0, EX_TEMPFAIL,
+ "lock file `%s' is already locked (timeout waiting)", lckfile);
}
int main(int argc, char **argv) {
- int fd;
- int c;
- int create = O_CREAT;
- int dofork = 1;
- int waittime = 0;
- int shared = 0;
- int test = 0;
- int fdn = -1;
+ int fd;
+ int c;
+ int create = O_CREAT;
+ int dofork = 1;
+ int waittime = 0;
+ int shared = 0;
+ int test = 0;
+ int fdn = -1;
#ifndef USE_FLOCK
- struct flock fl;
+ struct flock fl;
#endif
- if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0];
- else argv[0] = ++progname;
-
- if (argc == 1) {
- printf(
-"%s: execute a program with a lock set.\n"
-"Usage: %s [options] lockfile program [arguments]\n"
-"where options are:\n"
-" -w - if the lock is already held by another process,\n"
-" wait for it to complete instead of failing immediately\n"
-" -W sec - the same as -w but wait not more than sec seconds\n"
-" -e - execute the program directly, no fork/wait\n"
-" (keeps extra open file descriptor)\n"
-" -E nnn - set the fd# to keep open in -e case (implies -e)\n"
-" -n - do not create the lock file if it does not exist\n"
-" -q - produce no output if lock is already held\n"
-" -s - lock in shared (read) mode\n"
-" -x - lock in exclusive (write) mode (default)\n"
-" -t - test for lock existence"
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ argv[0] = ++progname;
+
+ if (argc == 1) {
+ printf(
+ "%s: execute a program with a lock set.\n"
+ "Usage: %s [options] lockfile program [arguments]\n"
+ "where options are:\n"
+ " -w - if the lock is already held by another process,\n"
+ " wait for it to complete instead of failing immediately\n"
+ " -W sec - the same as -w but wait not more than sec seconds\n"
+ " -e - execute the program directly, no fork/wait\n"
+ " (keeps extra open file descriptor)\n"
+ " -E nnn - set the fd# to keep open in -e case (implies -e)\n"
+ " -n - do not create the lock file if it does not exist\n"
+ " -q - produce no output if lock is already held\n"
+ " -s - lock in shared (read) mode\n"
+ " -x - lock in exclusive (write) mode (default)\n"
+ " -t - test for lock existence"
#ifndef USE_FLOCK
- " (just prints pid if any with -q)\n"
+ " (just prints pid if any with -q)\n"
#endif
-" (implies -n)\n"
- , progname, progname);
- return 0;
- }
-
- while((c = getopt(argc, argv, "+wW:neE:sxtq")) != EOF)
- switch(c) {
- case 'w':
- if (!waittime)
- waittime = -1;
- break;
- case 'W':
- if ((waittime = atoi(optarg)) < 1)
- error(0, EX_USAGE, "invalid wait time `%s'", optarg);
- break;
- case 't':
- test = 1;
- /* fall */
- case 'n':
- create = 0;
- break;
- case 'E':
- if ((fdn = atoi(optarg)) < 0 || fdn == 2)
- error(0, EX_USAGE, "invalid fd# `%s'", optarg);
- /* fall */
- case 'e':
- dofork = 0;
- break;
- case 's':
- shared = 1;
- break;
- case 'x':
- shared = 0;
- break;
- case 'q':
- quiet = 1;
- break;
- default:
- return EX_USAGE;
- }
-
- argc -= optind; argv += optind;
- if (!argc || (!test && argc < 2))
- error(0, EX_USAGE, "too few arguments given");
-
- lckfile = *argv++;
+ " (implies -n)\n"
+ , progname, progname);
+ return 0;
+ }
+
+ while ((c = getopt(argc, argv, "+wW:neE:sxtq")) != EOF) {
+ switch(c) {
+ case 'w':
+ if (!waittime)
+ waittime = -1;
+ break;
+ case 'W':
+ if ((waittime = atoi(optarg)) < 1)
+ error(0, EX_USAGE, "invalid wait time `%s'", optarg);
+ break;
+ case 't':
+ test = 1;
+ /* fall thru */
+ case 'n':
+ create = 0;
+ break;
+ case 'E':
+ if ((fdn = atoi(optarg)) < 0 || fdn == 2)
+ error(0, EX_USAGE, "invalid fd# `%s'", optarg);
+ /* fall thru */
+ case 'e':
+ dofork = 0;
+ break;
+ case 's':
+ shared = 1;
+ break;
+ case 'x':
+ shared = 0;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ default:
+ return EX_USAGE;
+ }
+ }
+
+ argc -= optind; argv += optind;
+ if (!argc || (!test && argc < 2))
+ error(0, EX_USAGE, "too few arguments given");
+
+ lckfile = *argv++;
#ifdef USE_FLOCK
- create |= O_RDONLY;
+ create |= O_RDONLY;
#else
- if (!test)
- create |= shared ? O_RDONLY : O_WRONLY;
+ if (!test)
+ create |= shared ? O_RDONLY : O_WRONLY;
#endif
- fd = open(lckfile, create, 0666);
- if (fd < 0) {
- if (test && errno == ENOENT) {
- if (!quiet)
- printf("lockfile `%s' is not locked\n", lckfile);
- return 0;
- }
- error(errno, EX_CANTCREAT, "unable to open `%s'", lckfile);
- }
-
- if (!test && fdn >= 0) {
- /* dup it early to comply with stupid POSIX fcntl locking semantics */
- if (dup2(fd, fdn) < 0)
- error(errno, EX_OSERR, "dup2(%d,%d) failed", fd, fdn);
- close(fd);
- fd = fdn;
- }
-
- if (test)
- waittime = 0;
- else if (waittime > 0) {
- alarm(waittime);
- signal(SIGALRM, sigalarm);
- }
+ fd = open(lckfile, create, 0666);
+ if (fd < 0) {
+ if (test && errno == ENOENT) {
+ if (!quiet)
+ printf("lockfile `%s' is not locked\n", lckfile);
+ return 0;
+ }
+ error(errno, EX_CANTCREAT, "unable to open `%s'", lckfile);
+ }
+
+ if (!test && fdn >= 0) {
+ /* dup it early to comply with stupid POSIX fcntl locking
+ * semantics */
+ if (dup2(fd, fdn) < 0)
+ error(errno, EX_OSERR, "dup2(%d,%d) failed", fd, fdn);
+ close(fd);
+ fd = fdn;
+ }
+
+ if (test)
+ waittime = 0;
+ else if (waittime > 0) {
+ alarm(waittime);
+ signal(SIGALRM, sigalarm);
+ }
#ifdef USE_FLOCK
- c = flock(fd, (shared ? LOCK_SH : LOCK_EX) | (waittime ? 0 : LOCK_NB));
- if (test && c < 0 &&
- (errno == EWOULDBLOCK || errno == EAGAIN || errno == EACCES)) {
- if (!quiet)
- printf("lockfile `%s' is locked\n", lckfile);
- else
- printf("locked\n");
- return EX_TEMPFAIL;
- }
+ c = flock(fd, (shared ? LOCK_SH : LOCK_EX) | (waittime ? 0 : LOCK_NB));
+ if (test && c < 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN || errno == EACCES)) {
+ if (!quiet)
+ printf("lockfile `%s' is locked\n", lckfile);
+ else
+ printf("locked\n");
+ return EX_TEMPFAIL;
+ }
#else
- memset(&fl, 0, sizeof(fl));
- fl.l_type = shared ? F_RDLCK : F_WRLCK;
- c = fcntl(fd, test ? F_GETLK : waittime ? F_SETLKW : F_SETLK, &fl);
- if (test && c == 0) {
- if (fl.l_type == F_UNLCK) {
- if (!quiet)
- printf("lockfile `%s' is not locked\n", lckfile);
- return 0;
- }
- if (!quiet)
- printf("lockfile `%s' is locked by process %d\n", lckfile, fl.l_pid);
- else
- printf("%d\n", fl.l_pid);
- return EX_TEMPFAIL;
- }
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = shared ? F_RDLCK : F_WRLCK;
+ c = fcntl(fd, test ? F_GETLK : waittime ? F_SETLKW : F_SETLK, &fl);
+ if (test && c == 0) {
+ if (fl.l_type == F_UNLCK) {
+ if (!quiet)
+ printf("lockfile `%s' is not locked\n", lckfile);
+ return 0;
+ }
+ if (!quiet)
+ printf("lockfile `%s' is locked by process %d\n", lckfile, fl.l_pid);
+ else
+ printf("%d\n", fl.l_pid);
+ return EX_TEMPFAIL;
+ }
#endif
- if (waittime > 0)
- alarm(0);
- if (c < 0) {
- if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EACCES)
- error(errno, EX_OSERR, "unable to lock `%s'", lckfile);
- else if (quiet)
- return EX_TEMPFAIL;
- else
- error(0, EX_TEMPFAIL, "lockfile `%s' is already locked", lckfile);
- }
-
- if (dofork) {
- pid_t pid;
- int flags = fcntl(fd, F_GETFD, 0);
- if (flags < 0)
- error(errno, EX_OSERR, "fcntl() failed");
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
- pid = fork();
- if (pid < 0)
- error(errno, EX_OSERR, "unable to fork");
- else if (pid) {
- if (wait(&c) < 0)
- error(errno, EX_OSERR, "wait() failed");
- if (WIFSIGNALED(c))
- error(0, EX_SOFTWARE, "%s: %s", *argv, strsignal(WTERMSIG(c)));
- return WEXITSTATUS(c);
- }
- }
- execvp(*argv, argv);
- error(errno, EX_OSERR, "unable to execute %s", *argv);
+ if (waittime > 0)
+ alarm(0);
+ if (c < 0) {
+ if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EACCES)
+ error(errno, EX_OSERR, "unable to lock `%s'", lckfile);
+ else if (quiet)
+ return EX_TEMPFAIL;
+ else
+ error(0, EX_TEMPFAIL, "lockfile `%s' is already locked", lckfile);
+ }
+
+ if (dofork) {
+ pid_t pid;
+ int flags = fcntl(fd, F_GETFD, 0);
+ if (flags < 0)
+ error(errno, EX_OSERR, "fcntl() failed");
+ fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ pid = fork();
+ if (pid < 0)
+ error(errno, EX_OSERR, "unable to fork");
+ else if (pid) {
+ if (wait(&c) < 0)
+ error(errno, EX_OSERR, "wait() failed");
+ if (WIFSIGNALED(c))
+ error(0, EX_SOFTWARE, "%s: %s", *argv,
+ strsignal(WTERMSIG(c)));
+ return WEXITSTATUS(c);
+ }
+ }
+ execvp(*argv, argv);
+ error(errno, EX_OSERR, "unable to execute %s", *argv);
}