Initial implementation of flock(1)

Very useful to prevent overlapping cron jobs amongst other things.
This commit is contained in:
sin 2015-10-07 10:16:18 +01:00
parent 23fdd768f0
commit 2652dcfd6c
3 changed files with 105 additions and 0 deletions

View File

@ -97,6 +97,7 @@ BIN =\
expr\ expr\
false\ false\
find\ find\
flock\
fold\ fold\
getconf\ getconf\
grep\ grep\

29
flock.1 Normal file
View File

@ -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

75
flock.c Normal file
View File

@ -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;
}