sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 8cf394af2ad8b1716fae692f3520b09d655824e5
parent 145e8024077ac197ee300714809ff2f807e1b815
Author: sin <sin@2f30.org>
Date:   Wed Oct  7 10:16:18 +0100

Initial implementation of flock(1)

Very useful to prevent overlapping cron jobs amongst other things.

Diffstat:
Makefile | 1+
flock.1 | 29+++++++++++++++++++++++++++++
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; +}