From 2652dcfd6ce23f9efae3f96cda0becb873b676eb Mon Sep 17 00:00:00 2001 From: sin Date: Wed, 7 Oct 2015 10:16:18 +0100 Subject: [PATCH] Initial implementation of flock(1) Very useful to prevent overlapping cron jobs amongst other things. --- Makefile | 1 + flock.1 | 29 ++++++++++++++++++++++ flock.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 flock.1 create mode 100644 flock.c diff --git a/Makefile b/Makefile index f99a038..c2d8266 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ BIN =\ expr\ false\ find\ + flock\ fold\ getconf\ grep\ diff --git a/flock.1 b/flock.1 new file mode 100644 index 0000000..344ec2e --- /dev/null +++ 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 new file mode 100644 index 0000000..f81a551 --- /dev/null +++ b/flock.c @@ -0,0 +1,75 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include +#include +#include + +#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; +}