[pacman-dev] [PATCH] Use file locks (flock) to stop multiple pacman instances from running concurrently. This improves the current model by automatically removing locks held by programs has failed to remove the lock, for example at a crash, forced kill or power outage.

Mattias Andrée maandree at operamail.com
Wed Aug 14 18:03:33 EDT 2013


This allows for further improvement of pacman where shared locks
could also be used, in cases there pacman only reads the database
and does not edit it.

File locks also makes it easy to let pacman wait until the
block instance has finished, by just not using the LOCK_NB flag.
---
 lib/libalpm/be_sync.c           |  5 +----
 lib/libalpm/handle.c            | 26 ++++++++++++++------------
 lib/libalpm/handle.h            |  2 +-
 lib/libalpm/trans.c             |  7 +------
 scripts/pacman-db-upgrade.sh.in |  9 +++++----
 scripts/pacman-optimize.sh.in   |  9 +++++----
 6 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index 0b99684..e7c8c4b 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -284,10 +284,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 
 cleanup:
 
-	if(_alpm_handle_unlock(handle)) {
-		_alpm_log(handle, ALPM_LOG_WARNING, _("could not remove lock file %s\n"),
-				handle->lockfile);
-	}
+	_alpm_handle_unlock(handle);
 	free(syncpath);
 	umask(oldmask);
 	return ret;
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 53c86c5..5d1cfb7 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <syslog.h>
 #include <sys/stat.h>
+#include <sys/file.h>
 #include <fcntl.h>
 
 /* libalpm */
@@ -44,6 +45,7 @@ alpm_handle_t *_alpm_handle_new(void)
 
 	CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL);
 	handle->deltaratio = 0.0;
+	handle->lckstream = -1;
 
 	return handle;
 }
@@ -95,7 +97,7 @@ int _alpm_handle_lock(alpm_handle_t *handle)
 	char *dir, *ptr;
 
 	ASSERT(handle->lockfile != NULL, return -1);
-	ASSERT(handle->lckstream == NULL, return 0);
+	ASSERT(handle->lckstream < 0, return 0);
 
 	/* create the dir of the lockfile first */
 	dir = strdup(handle->lockfile);
@@ -110,14 +112,14 @@ int _alpm_handle_lock(alpm_handle_t *handle)
 	FREE(dir);
 
 	do {
-		fd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL, 0000);
+		fd = open(handle->lockfile, O_WRONLY | O_CREAT);
 	} while(fd == -1 && errno == EINTR);
 	if(fd >= 0) {
-		FILE *f = fdopen(fd, "w");
-		fprintf(f, "%ld\n", (long)getpid());
-		fflush(f);
 		fsync(fd);
-		handle->lckstream = f;
+		if(flock(fd, LOCK_EX | LOCK_NB) < 0) {
+			return -1;
+		}
+		handle->lckstream = fd;
 		return 0;
 	}
 	return -1;
@@ -127,14 +129,14 @@ int _alpm_handle_lock(alpm_handle_t *handle)
 int _alpm_handle_unlock(alpm_handle_t *handle)
 {
 	ASSERT(handle->lockfile != NULL, return -1);
-	ASSERT(handle->lckstream != NULL, return 0);
-
-	fclose(handle->lckstream);
-	handle->lckstream = NULL;
+	ASSERT(handle->lckstream >= 0, return 0);
 
-	if(unlink(handle->lockfile) && errno != ENOENT) {
-		return -1;
+	flock(handle->lckstream, LOCK_UN);
+	if(flock(handle->lckstream, LOCK_EX | LOCK_NB) == 0) {
+		unlink(handle->lockfile);
+		flock(handle->lckstream, LOCK_UN);
 	}
+	handle->lckstream = NULL;
 	return 0;
 }
 
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 5e84d58..7ca90ff 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -55,7 +55,7 @@ struct __alpm_handle_t {
 	alpm_db_t *db_local;       /* local db pointer */
 	alpm_list_t *dbs_sync;  /* List of (alpm_db_t *) */
 	FILE *logstream;        /* log file stream pointer */
-	FILE *lckstream;        /* lock file stream pointer if one exists */
+	int lckstream;        /* lock file file descriptor if one exists */
 	alpm_trans_t *trans;
 
 #ifdef HAVE_LIBCURL
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index 8d4e0e7..122f35b 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -215,12 +215,7 @@ int SYMEXPORT alpm_trans_release(alpm_handle_t *handle)
 
 	/* unlock db */
 	if(!nolock_flag) {
-		if(_alpm_handle_unlock(handle)) {
-			_alpm_log(handle, ALPM_LOG_WARNING, _("could not remove lock file %s\n"),
-					handle->lockfile);
-			alpm_logaction(handle, ALPM_CALLER_PREFIX,
-				"warning: could not remove lock file %s\n", handle->lockfile);
-		}
+		_alpm_handle_unlock(handle);
 	}
 
 	return 0;
diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in
index a1630c5..20cf035 100644
--- a/scripts/pacman-db-upgrade.sh.in
+++ b/scripts/pacman-db-upgrade.sh.in
@@ -102,12 +102,12 @@ dbroot="${dbroot%/}"
 # form the path to our lockfile location
 lockfile="${dbroot}/db.lck"
 
-# make sure pacman isn't running
-if [[ -f $lockfile ]]; then
+# make sure pacman isn't running and stop other instances for starting
+exec 100<>"$lockfile"
+if ! flock -x --nonblock 100; then
+	flock --close 100
 	die "$(gettext "Pacman lock file was found. Cannot run while pacman is running.")"
 fi
-# do not let pacman run while we do this
-touch "$lockfile"
 
 # pacman-3.4 to 3.5 upgrade - merge depends into desc
 if [[ $(find "$dbroot"/local -name depends) ]]; then
@@ -123,5 +123,6 @@ fi
 
 # remove the lock file
 rm -f "$lockfile"
+flock --close 100
 
 # vim: set ts=2 sw=2 noet:
diff --git a/scripts/pacman-optimize.sh.in b/scripts/pacman-optimize.sh.in
index 47fbb49..8c6e556 100644
--- a/scripts/pacman-optimize.sh.in
+++ b/scripts/pacman-optimize.sh.in
@@ -114,12 +114,12 @@ dbroot="${dbroot%/}"
 lockfile="${dbroot}/db.lck"
 localdb="${dbroot}/local"
 
-# make sure pacman isn't running
-if [[ -f $lockfile ]]; then
+# make sure pacman isn't running and stop other instances for starting
+exec 100<>"$lockfile"
+if ! flock -x --nonblock 100; then
+	flock --close 100
 	die "$(gettext "Pacman lock file was found. Cannot run while pacman is running.")"
 fi
-# do not let pacman run while we do this
-touch "$lockfile"
 
 workdir=$(mktemp -d "${TMPDIR:-/tmp}/pacman-optimize.XXXXXXXXXX") ||
 	die_r "$(gettext "Can not create temp directory for database building.")\n" >&2
@@ -178,6 +178,7 @@ rm -rf "$localdb.old"
 
 # remove the lock file and our working directory with sums and tarfile
 rm -f "$lockfile"
+flock --close 100
 rm -rf "$workdir"
 
 echo
-- 
1.8.3.4



More information about the pacman-dev mailing list