diff options
author | Karel Zak | 2011-11-21 17:12:33 +0100 |
---|---|---|
committer | Karel Zak | 2011-11-21 17:26:41 +0100 |
commit | eb742a1f66d5e3a7c5b43efce741c113f51bef3b (patch) | |
tree | 0f81af233004f822e6eb424890d6eb771e7578b2 /sys-utils/flock.c | |
parent | flock: timer code refactoring (diff) | |
download | kernel-qcow2-util-linux-eb742a1f66d5e3a7c5b43efce741c113f51bef3b.tar.gz kernel-qcow2-util-linux-eb742a1f66d5e3a7c5b43efce741c113f51bef3b.tar.xz kernel-qcow2-util-linux-eb742a1f66d5e3a7c5b43efce741c113f51bef3b.zip |
flock: use O_RDWR as fallback if O_RDONLY returns EIO
The commit 75aaee08f06b92d119ed827c53d1af5474eb16ff introduces
regression:
$ echo '#!/bin/sh' > test.sh
$ chmod a+rx test.sh
$ flock -eon ./test.sh ./test.sh
flock: ./test.sh: Text file busy
The lock file cannot be opened in read-write mode by default, because
then we cannot use flock(1) to lock executable files.
The read-write mode for lock files is necessary on NFSv4 where
flock(2) is emulated by by fcntl() -- this situation is possible to
detect by flock(2) EIO error.
This patch reverts the default to O_RDONLY and use O_RDWR only if EIO
error is detected.
Reported-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/flock.c')
-rw-r--r-- | sys-utils/flock.c | 68 |
1 files changed, 48 insertions, 20 deletions
diff --git a/sys-utils/flock.c b/sys-utils/flock.c index b5289af08..0d4a8fbf5 100644 --- a/sys-utils/flock.c +++ b/sys-utils/flock.c @@ -100,13 +100,42 @@ static void cancel_timer(struct itimerval *old_timer, struct sigaction *old_sa) sigaction(SIGALRM, old_sa, NULL); } +static int open_file(const char *filename, int *flags) +{ + + int fd; + int fl = *flags == 0 ? O_RDONLY : *flags; + + errno = 0; + fl |= O_NOCTTY | O_CREAT; + fd = open(filename, fl, 0666); + + /* Linux doesn't like O_CREAT on a directory, even though it + * should be a no-op; POSIX doesn't allow O_RDWR or O_WRONLY + */ + if (fd < 0 && errno == EISDIR) { + fl = O_RDONLY | O_NOCTTY; + fd = open(filename, fl); + } + if (fd < 0) { + warn(_("cannot open lock file %s"), filename); + if (errno == ENOMEM || errno == EMFILE || errno == ENFILE) + exit(EX_OSERR); + if (errno == EROFS || errno == ENOSPC) + exit(EX_CANTCREAT); + exit(EX_NOINPUT); + } + *flags = fl; + return fd; +} + int main(int argc, char *argv[]) { struct itimerval timeout, old_timer; int have_timeout = 0; int type = LOCK_EX; int block = 0; - int open_accmode; + int open_flags = 0; int fd = -1; int opt, ix; int do_close = 0; @@ -195,25 +224,8 @@ int main(int argc, char *argv[]) } filename = argv[optind]; - open_accmode = - ((type == LOCK_SH - || access(filename, - R_OK | W_OK) < 0) ? O_RDONLY : O_RDWR); - fd = open(filename, open_accmode | O_NOCTTY | O_CREAT, 0666); - /* Linux doesn't like O_CREAT on a directory, even though it - * should be a no-op; POSIX doesn't allow O_RDWR or O_WRONLY - */ - if (fd < 0 && errno == EISDIR) - fd = open(filename, O_RDONLY | O_NOCTTY); - - if (fd < 0) { - warn(_("cannot open lock file %s"), argv[optind]); - if (errno == ENOMEM || errno == EMFILE || errno == ENFILE) - exit(EX_OSERR); - if (errno == EROFS || errno == ENOSPC) - exit(EX_CANTCREAT); - exit(EX_NOINPUT); - } + fd = open_file(filename, &open_flags); + } else if (optind < argc) { /* Use provided file descriptor */ fd = (int)strtol_or_err(argv[optind], "bad number"); @@ -252,6 +264,22 @@ int main(int argc, char *argv[]) exit(1); /* otherwise try again */ continue; + case EIO: + /* Probably NFSv4 where flock() is emulated by fcntl(). + * Let's try to reopen in read-write mode. + */ + if (!(open_flags & O_RDWR) && + type != LOCK_SH && + access(filename, R_OK | W_OK) == 0) { + + close(fd); + open_flags = O_RDWR; + fd = open_file(filename, &open_flags); + + if (open_flags & O_RDWR) + break; + } + /* go through */ default: /* Other errors */ if (filename) |