Skip to content

Commit

Permalink
flock: support locking with byte-range
Browse files Browse the repository at this point in the history
New options, --start and --length are for specifying the byte-range.
The options assume used with --fcntl option.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed Feb 24, 2025
1 parent 20509a3 commit 04649d5
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
2 changes: 2 additions & 0 deletions bash-completion/flock
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ _flock_module()
--command
--no-fork
--fcntl
--start
--length
--help
--version"
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
Expand Down
6 changes: 6 additions & 0 deletions sys-utils/flock.1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ Instead of flock(2), apply an fcntl(2) open file description lock (that is, usin

This is only available on kernel versions >= 3.15.

*--start* _offset_::
The starting offset for lock. Ths option implies *--fcntl*.

*--length* _number_::
The number of bytes to lock. Ths option implies *--fcntl*.

*--verbose*::
Report how long it took to acquire the lock, or why the lock could not be obtained.

Expand Down
29 changes: 23 additions & 6 deletions sys-utils/flock.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_( " -c, --command <command> run a single command string through the shell\n"), stdout);
fputs(_( " -F, --no-fork execute command without forking\n"), stdout);
fputs(_( " --fcntl use fcntl(F_OFD_SETLK) rather than flock()\n"), stdout);
fputs(_( " --start <offset> starting offset for lock (implies --fcntl)\n"), stdout);
fputs(_( " --length <number> number of bytes to lock (implies --fcntl)\n"), stdout);
fputs(_( " --verbose increase verbosity\n"), stdout);
fputs(USAGE_SEPARATOR, stdout);
fprintf(stdout, USAGE_HELP_OPTIONS(26));
Expand Down Expand Up @@ -152,25 +154,25 @@ static int flock_to_fcntl_type(int op)
}
}

static int fcntl_lock(int fd, int op, int block)
static int fcntl_lock(int fd, int op, int block, off_t start, off_t len)
{
struct flock arg = {
.l_type = flock_to_fcntl_type(op),
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0,
.l_start = start,
.l_len = len,
};
int cmd = (block & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW;
return fcntl(fd, cmd, &arg);
}

static int do_lock(int api, int fd, int op, int block)
static int do_lock(int api, int fd, int op, int block, off_t start, off_t len)
{
switch (api) {
case API_FLOCK:
return flock(fd, op | block);
case API_FCNTL_OFD:
return fcntl_lock(fd, op, block);
return fcntl_lock(fd, op, block, start, len);
/*
* Should never happen, api can never have values other than
* API_*.
Expand All @@ -197,6 +199,7 @@ int main(int argc, char *argv[])
int verbose = 0;
int api = API_FLOCK;
struct timeval time_start = { 0 }, time_done = { 0 };
off_t start = 0, length = 0;
/*
* The default exit code for lock conflict or timeout
* is specified in man flock.1
Expand All @@ -207,6 +210,8 @@ int main(int argc, char *argv[])
enum {
OPT_VERBOSE = CHAR_MAX + 1,
OPT_FCNTL,
OPT_FCNTL_START,
OPT_FCNTL_LENGTH,
};
static const struct option long_options[] = {
{"shared", no_argument, NULL, 's'},
Expand All @@ -221,6 +226,8 @@ int main(int argc, char *argv[])
{"no-fork", no_argument, NULL, 'F'},
{"verbose", no_argument, NULL, OPT_VERBOSE},
{"fcntl", no_argument, NULL, OPT_FCNTL},
{"start", required_argument, NULL, OPT_FCNTL_START},
{"length", required_argument, NULL, OPT_FCNTL_LENGTH},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
Expand Down Expand Up @@ -278,6 +285,16 @@ int main(int argc, char *argv[])
case OPT_FCNTL:
api = API_FCNTL_OFD;
break;
case OPT_FCNTL_START:
start = strtosize_or_err(optarg,
_("invalid as start offset"));
api = API_FCNTL_OFD;
break;
case OPT_FCNTL_LENGTH:
length = strtosize_or_err(optarg,
_("invalid as lenght of lock range"));
api = API_FCNTL_OFD;
break;
case OPT_VERBOSE:
verbose = 1;
break;
Expand Down Expand Up @@ -348,7 +365,7 @@ int main(int argc, char *argv[])

if (verbose)
gettime_monotonic(&time_start);
while (do_lock(api, fd, type, block)) {
while (do_lock(api, fd, type, block, start, length)) {
switch (errno) {
case EWOULDBLOCK:
/*
Expand Down

0 comments on commit 04649d5

Please sign in to comment.