commit 2652dcfd6ce23f9efae3f96cda0becb873b676eb
parent 23fdd768f04feeea72d1ab8c8982585a930687d1
Author: sin <sin@2f30.org>
Date: Wed, 7 Oct 2015 10:16:18 +0100
Initial implementation of flock(1)
Very useful to prevent overlapping cron jobs amongst other things.
Diffstat:
M | Makefile | | | 1 | + |
A | flock.1 | | | 29 | +++++++++++++++++++++++++++++ |
A | flock.c | | | 75 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -97,6 +97,7 @@ BIN =\
expr\
false\
find\
+ flock\
fold\
getconf\
grep\
diff --git a/flock.1 b/flock.1
@@ -0,0 +1,29 @@
+.Dd October 7, 2015
+.Dt FLOCK 1
+.Os sbase
+.Sh NAME
+.Nm flock
+.Nd tool to manage locks on files
+.Sh SYNOPSIS
+.Nm
+.Op Fl nsux
+.Ar file
+.Ar cmd Op arg ...
+.Sh DESCRIPTION
+.Nm
+is used to manage advisory locks on open files. It is commonly used to prevent
+long running cron jobs from running in parallel. If
+.Ar file
+does not exist, it will be created.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl n
+Set non-blocking mode on the lock. Fail immediately if the lock
+cannot be acquired.
+.It Fl s
+Acquire a shared lock.
+.It Fl u
+Release the lock.
+.It Fl x
+Acquire an exclusive lock. This is the default.
+.El
diff --git a/flock.c b/flock.c
@@ -0,0 +1,75 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/file.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "util.h"
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-nsux] file cmd [arg ...]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fd, status, savederrno, flags = LOCK_EX, nonblk = 0;
+ pid_t pid;
+
+ ARGBEGIN {
+ case 'n':
+ nonblk = LOCK_NB;
+ break;
+ case 's':
+ flags = LOCK_SH;
+ break;
+ case 'u':
+ flags = LOCK_UN;
+ break;
+ case 'x':
+ /* for compat */
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc < 2)
+ usage();
+
+ if ((fd = open(*argv, O_RDONLY | O_CREAT)) < 0)
+ eprintf("open %s:", *argv);
+
+ if (flock(fd, flags | nonblk)) {
+ if (nonblk && errno == EWOULDBLOCK)
+ return 1;
+ eprintf("flock:");
+ }
+
+ switch ((pid = fork())) {
+ case -1:
+ eprintf("fork:");
+ case 0:
+ argv++;
+ execvp(*argv, argv);
+ savederrno = errno;
+ weprintf("execvp %s:", *argv);
+ _exit(126 + (savederrno == ENOENT));
+ default:
+ break;
+ }
+ waitpid(pid, &status, 0);
+
+ if (WIFSIGNALED(status))
+ return 128 + WTERMSIG(status);
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+
+ if (close(fd) < 0)
+ eprintf("close:");
+
+ return 0;
+}