summaryrefslogtreecommitdiffstats
path: root/sys-utils/flock.c
diff options
context:
space:
mode:
authorKarel Zak2011-11-21 17:12:33 +0100
committerKarel Zak2011-11-21 17:26:41 +0100
commiteb742a1f66d5e3a7c5b43efce741c113f51bef3b (patch)
tree0f81af233004f822e6eb424890d6eb771e7578b2 /sys-utils/flock.c
parentflock: timer code refactoring (diff)
downloadkernel-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.c68
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)