From 174ff59dba8c24f544e354cd43f3b68aea91d265 Mon Sep 17 00:00:00 2001
From: Jan Steffens <jan.steffens@gmail.com>
Date: Sun, 13 Mar 2011 19:06:27 +0100
Subject: [PATCH] Add flock-based locking to chroots

This prevents accidents when chroots are shared between multiple users.
---
 archbuild     | 13 +++++++++++++
 makechrootpkg | 23 +++++++++++++++++++++++
 mkarchroot    | 16 ++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/archbuild b/archbuild
index 7e8c456..9dd4888 100755
--- a/archbuild
+++ b/archbuild
@@ -36,6 +36,19 @@ fi
 
 if ${clean_first} || [ ! -d "${chroots}/${repo}-${arch}" ]; then
 	echo "Creating chroot for [${repo}] (${arch})..."
+
+	for copy in ${chroots}/${repo}-${arch}/*; do
+		[[ -d $copy ]] || continue
+		echo "Deleting chroot copy '$(basename "${copy}")'..."
+
+		# Lock the copy
+		exec 9>${copy}.lock
+		flock 9
+
+		rm -rf ${copy}
+	done
+	exec 9>&-
+
 	rm -rf ${chroots}/${repo}-${arch}
 	mkdir -p ${chroots}/${repo}-${arch}
 	setarch ${arch} mkarchroot \
diff --git a/makechrootpkg b/makechrootpkg
index a38a740..1f6f20a 100755
--- a/makechrootpkg
+++ b/makechrootpkg
@@ -105,11 +105,34 @@ if [ ! -d "$chrootdir/root" ]; then
 fi
 
 umask 0022
+
+# Lock the chroot we want to use. We'll keep this lock until we exit.
+# Note this is the same FD number as in mkarchroot
+exec 9>"$copydir.lock"
+if ! flock -n 9; then
+	echo -n "locking chroot copy '$copy'..."
+	flock 9
+	echo "done"
+fi
+
 if [ ! -d "$copydir" -o "$clean_first" -eq "1" ]; then
+	# Get a read lock on the root chroot to make
+	# sure we don't clone a half-updated chroot
+	exec 8>"$chrootdir/root.lock"
+
+	if ! flock -sn 8; then
+		echo -n "locking clean chroot..."
+		flock -s 8
+		echo "done"
+	fi
+
 	echo -n 'creating clean working copy...'
 	mkdir -p "$copydir"
 	rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir"
 	echo 'done'
+
+	# Drop the read lock again
+	exec 8>&-
 fi
 
 if [ -n "$install_pkg" ]; then
diff --git a/mkarchroot b/mkarchroot
index 254841e..5c6548e 100755
--- a/mkarchroot
+++ b/mkarchroot
@@ -141,6 +141,20 @@ chroot_umount () {
 	umount "${working_dir}/${cache_dir}"
 	[ -n "${host_mirror_path}" ] && umount "${working_dir}/${host_mirror_path}"
 }
+
+chroot_lock () {
+	# Only reopen the FD if it wasn't handed to us
+	if [ "$(readlink -f /dev/fd/9)" != "${working_dir}.lock" ]; then
+	  exec 9>"${working_dir}.lock"
+	fi
+
+	# Lock the chroot. Take note of the FD number.
+	if ! flock -n 9; then
+		echo -n "locking chroot..."
+		flock 9
+		echo "done"
+	fi
+}
 # }}}
 
 umask 0022
@@ -153,6 +167,7 @@ if [ "$RUN" != "" ]; then
 		exit 1
 	fi
 
+	chroot_lock
 	chroot_mount
 	copy_hostconf
 
@@ -169,6 +184,7 @@ else
 	mkdir -p "${working_dir}/var/lib/pacman/sync"
 	mkdir -p "${working_dir}/etc/"
 
+	chroot_lock
 	chroot_mount
 
 	pacargs="--noconfirm --root=${working_dir} --cachedir=${cache_dir}"
-- 
GitLab