Add -w option to lockf(1).

By default, lockf(1) opens its lock file O_RDONLY|O_EXLOCK.  On NFS, if the
file already exists, this is split into opening the file read-only and then
requesting an exclusive lock -- and the second step fails because NFS does
not permit exclusive locking on files which are opened read-only.

The new -w option changes the open flags to O_WRONLY|O_EXLOCK, allowing it
to work on NFS -- at the cost of not working if the file cannot be opened
for writing.

(Whether the traditional BSD behaviour of allowing exclusive locks to be
obtained on a file which cannot be opened for writing is a good idea is
perhaps questionable since it may allow less-privileged users to perform
a local denial of service; however this behaviour has been present for a
long time and changing it now seems like it would cause problems.)

Reviewed by:	rmacklem
Differential Revision:	https://reviews.freebsd.org/D26005
This commit is contained in:
cperciva 2020-08-26 19:26:48 +00:00
parent cb6e502fff
commit d0e6339a5a
2 changed files with 17 additions and 6 deletions

View File

@ -1,4 +1,4 @@
.\" .\"
.\" Copyright (C) 1998 John D. Polstra. All rights reserved. .\" Copyright (C) 1998 John D. Polstra. All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
@ -24,7 +24,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd June 18, 2020 .Dd August 26, 2020
.Dt LOCKF 1 .Dt LOCKF 1
.Os .Os
.Sh NAME .Sh NAME
@ -32,7 +32,7 @@
.Nd execute a command while holding a file lock .Nd execute a command while holding a file lock
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl kns .Op Fl knsw
.Op Fl t Ar seconds .Op Fl t Ar seconds
.Ar file .Ar file
.Ar command .Ar command
@ -121,6 +121,14 @@ When a lock times out,
is is
.Em not .Em not
executed. executed.
.It Fl w
Causes
.Nm
to open
.Ar file
for writing rather than reading.
This is necessary on filesystems (including NFSv4) where a file which
has been opened read-only cannot be exclusively locked.
.El .El
.Pp .Pp
In no event will In no event will

View File

@ -62,9 +62,9 @@ main(int argc, char **argv)
pid_t child; pid_t child;
silent = keep = 0; silent = keep = 0;
flags = O_CREAT; flags = O_CREAT | O_RDONLY;
waitsec = -1; /* Infinite. */ waitsec = -1; /* Infinite. */
while ((ch = getopt(argc, argv, "sknt:")) != -1) { while ((ch = getopt(argc, argv, "sknt:w")) != -1) {
switch (ch) { switch (ch) {
case 'k': case 'k':
keep = 1; keep = 1;
@ -84,6 +84,9 @@ main(int argc, char **argv)
"invalid timeout \"%s\"", optarg); "invalid timeout \"%s\"", optarg);
} }
break; break;
case 'w':
flags = (flags & ~O_RDONLY) | O_WRONLY;
break;
default: default:
usage(); usage();
} }
@ -171,7 +174,7 @@ acquire_lock(const char *name, int flags)
{ {
int fd; int fd;
if ((fd = open(name, O_RDONLY|O_EXLOCK|flags, 0666)) == -1) { if ((fd = open(name, O_EXLOCK|flags, 0666)) == -1) {
if (errno == EAGAIN || errno == EINTR) if (errno == EAGAIN || errno == EINTR)
return (-1); return (-1);
else if (errno == ENOENT && (flags & O_CREAT) == 0) else if (errno == ENOENT && (flags & O_CREAT) == 0)