summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@parabola.nu>2017-05-05 18:41:00 -0400
committerErich Eckner <git@eckner.net>2017-07-14 06:54:28 +0200
commite9e3fc8b50b1b492f0ee77bd503a729bfc2c98fe (patch)
treec92e5574dc7bf11a536a043011bb4e7f272c2c89
parent89e08408ff3e28268a992c5279713c8cf44d7eef (diff)
downloaddevtools-e9e3fc8b50b1b492f0ee77bd503a729bfc2c98fe.tar.xz
makechrootpkg: sync_chroot: Make more general.
This is inspired by the thought that went in to the delete_chroot is_subvolume commit. sync_chroot($chrootdir, $copydir) copies `$chrootdir/root` to `$copydir`. That seems a little silly; why do we care about "$chrootdir"? Have it just be sync_chroot(source, destination) like every other sync/copy command. Where this becomes tricky is check to decide if we are going to use btrfs subvolumes or not. We don't care if "$source/.." is on btrfs; the root could be a directly-mounted subvolume, but and the destination could be another subvolume of the same btrfs mounted somewhere else. The things we do care about are: - The source is a btrfs subvolume (so that we can snapshot it) - The source is on the same filesystem as the directory that the copy will be created in. - If the destination exists: * that it is not a mountpoint (so that we can delete and recreate it) * that it is a btrfs subvolume (so that we can quickly delete it) On the last point, it isn't necessary for creating the new snapshot, just for quick deletion. That can be a separate check, where we use regular `rm` for deleting the existing copy, but use subvolume snapshots for creating the new one.
-rw-r--r--lib/archroot.sh8
-rw-r--r--makechrootpkg.in32
2 files changed, 27 insertions, 13 deletions
diff --git a/lib/archroot.sh b/lib/archroot.sh
index 87c28a2..6b1b52e 100644
--- a/lib/archroot.sh
+++ b/lib/archroot.sh
@@ -34,6 +34,14 @@ is_subvolume() {
}
##
+# usage : is_same_fs( $path_a, $path_b )
+# return : whether $path_a and $path_b are on the same filesystem
+##
+is_same_fs() {
+ [[ "$(stat -c %d "$1")" == "$(stat -c %d "$1")" ]]
+}
+
+##
# usage : subvolume_delete_recursive( $path )
#
# Find all btrfs subvolumes under and including $path and delete them.
diff --git a/makechrootpkg.in b/makechrootpkg.in
index 9a77441..53235ee 100644
--- a/makechrootpkg.in
+++ b/makechrootpkg.in
@@ -98,31 +98,37 @@ load_vars() {
return 0
}
-# Usage: sync_chroot $chrootdir $copydir [$copy]
+# Usage: sync_chroot $rootdir $copydir [$copy]
sync_chroot() {
- local chrootdir=$1
+ local rootdir=$1
local copydir=$2
local copy=${3:-$2}
- if [[ "$chrootdir/root" -ef "$copydir" ]]; then
+ if [[ "$rootdir" -ef "$copydir" ]]; then
error 'Cannot sync copy with itself: %s' "$copydir"
return 1
fi
# Get a read lock on the root chroot to make
# sure we don't clone a half-updated chroot
- slock 8 "$chrootdir/root.lock" \
- "Locking clean chroot [%s]" "$chrootdir/root"
-
- stat_busy "Synchronizing chroot copy [%s] -> [%s]" "$chrootdir/root" "$copy"
- if is_btrfs "$chrootdir" && ! mountpoint -q "$copydir"; then
- subvolume_delete_recursive "$copydir" ||
- die "Unable to delete subvolume %s" "$copydir"
- btrfs subvolume snapshot "$chrootdir/root" "$copydir" >/dev/null ||
+ slock 8 "$rootdir.lock" \
+ "Locking clean chroot [%s]" "$rootdir"
+
+ stat_busy "Synchronizing chroot copy [%s] -> [%s]" "$rootdir" "$copy"
+ if is_subvolume "$rootdir" && is_same_fs "$rootdir" "$(dirname -- "$copydir")" && ! mountpoint -q "$copydir"; then
+ if is_subvolume "$copydir"; then
+ subvolume_delete_recursive "$copydir" ||
+ die "Unable to delete subvolume %s" "$copydir"
+ else
+ # avoid change of filesystem in case of an umount failure
+ rm --recursive --force --one-file-system "$copydir" ||
+ die "Unable to delete %s" "$copydir"
+ fi
+ btrfs subvolume snapshot "$rootdir" "$copydir" >/dev/null ||
die "Unable to create subvolume %s" "$copydir"
else
mkdir -p "$copydir"
- rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir"
+ rsync -a --delete -q -W -x "$rootdir/" "$copydir"
fi
stat_done
@@ -375,7 +381,7 @@ main() {
lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy"
if [[ ! -d $copydir ]] || $clean_first; then
- sync_chroot "$chrootdir" "$copydir" "$copy"
+ sync_chroot "$chrootdir/root" "$copydir" "$copy"
fi
$update_first && arch-nspawn "$copydir" \