Package: reprepro
Version: 4.14.0-1
Severity: normal
Tags: patch

When reprepro crashes, the database lock file is not released, because the lock
file still exists on the system. A patch is attached that changes the locking
system to use fcntl() to lock the database lockfile instead of open with O_EXCL.
With this change, the lock is correctly released in case of the reprepro process
is crashing.
>From 31c4cb8fa6ecddc164e5fe2f51a91360f4fa402d Mon Sep 17 00:00:00 2001
From: Benjamin Drung <benjamin.dr...@profitbricks.com>
Date: Wed, 11 Jun 2014 17:49:59 +0200
Subject: Use fcntl() to lock the database lockfile instead of open with O_EXCL.

The lock required with fcntl() is correctly released in case of the reprepro
process is crashing.

Signed-off-by: Benjamin Drung <benjamin.dr...@profitbricks.com>
---
 database.c | 41 +++++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/database.c b/database.c
index c6111be..6805b23 100644
--- a/database.c
+++ b/database.c
@@ -90,9 +90,11 @@ static inline char *dbfilename(const char *filename) {
 
 static retvalue database_lock(size_t waitforlock) {
 	char *lockfile;
+	int e;
 	int fd;
 	retvalue r;
 	size_t tries = 0;
+	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, getpid()};
 
 	assert (!rdb_locked);
 	rdb_dircreationdepth = 0;
@@ -103,23 +105,29 @@ static retvalue database_lock(size_t waitforlock) {
 	lockfile = dbfilename("lockfile");
 	if (FAILEDTOALLOC(lockfile))
 		return RET_ERROR_OOM;
-	fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY,
+	fd = open(lockfile, O_WRONLY|O_CREAT|O_NOFOLLOW|O_NOCTTY,
 			S_IRUSR|S_IWUSR);
-	while (fd < 0) {
-		int e = errno;
-		if (e == EEXIST) {
+	if (fd == -1) {
+		e = errno;
+		fprintf(stderr,
+"Error %d creating lock file '%s': %s!\n",
+				e, lockfile, strerror(e));
+		free(lockfile);
+		return RET_ERRNO(e);
+	}
+	while (fcntl(fd, F_SETLK, &fl) < 0) {
+		e = errno;
+		if (e == EACCES || e == EAGAIN) {
 			if (tries < waitforlock && ! interrupted()) {
 				unsigned int timetosleep = 10;
 				if (verbose >= 0)
 					printf(
-"Could not aquire lock: %s already exists!\nWaiting 10 seconds before trying again.\n",
-						lockfile);
-				while (timetosleep > 0)
+"Could not aquire lock: %s is already locked by process %i!\nWaiting %i seconds before trying again.\n",
+						lockfile, fl.l_pid, timetosleep);
+				while (timetosleep > 0) {
 					timetosleep = sleep(timetosleep);
+				}
 				tries++;
-				fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL
-						|O_NOFOLLOW|O_NOCTTY,
-						S_IRUSR|S_IWUSR);
 				continue;
 
 			}
@@ -131,22 +139,11 @@ static retvalue database_lock(size_t waitforlock) {
 
 		} else
 			fprintf(stderr,
-"Error %d creating lock file '%s': %s!\n",
+"Error %d locking lock file '%s': %s!\n",
 					e, lockfile, strerror(e));
 		free(lockfile);
 		return RET_ERRNO(e);
 	}
-	// TODO: do some more locking of this file to avoid problems
-	// with the non-atomity of O_EXCL with nfs-filesystems...
-	if (close(fd) != 0) {
-		int e = errno;
-		fprintf(stderr,
-"(Late) Error %d creating lock file '%s': %s!\n",
-				e, lockfile, strerror(e));
-		(void)unlink(lockfile);
-		free(lockfile);
-		return RET_ERRNO(e);
-	}
 	free(lockfile);
 	rdb_locked = true;
 	return RET_OK;
-- 
1.9.1

Reply via email to