Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/makechrootpkg.in
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2017-01-29 22:59:49 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2017-01-29 22:59:49 -0500
commitca57df0221baa2eddb01d53d45e3f9f5f6420d3b (patch)
tree57b5a8e3e31607aace7d622501399c963d485701 /makechrootpkg.in
parent3154c90714ef2bcd21c325be4902a6e69aedcaff (diff)
makechrootpkg: Be recursive when deleting subvolumes.
This fixes https://labs.parabola.nu/issues/1201
Diffstat (limited to 'makechrootpkg.in')
-rw-r--r--makechrootpkg.in59
1 files changed, 57 insertions, 2 deletions
diff --git a/makechrootpkg.in b/makechrootpkg.in
index a77d14a..127514d 100644
--- a/makechrootpkg.in
+++ b/makechrootpkg.in
@@ -80,6 +80,61 @@ load_vars() {
return 0
}
+# Usage: btrfs_subvolume_id $SUBVOLUME
+btrfs_subvolume_id() (
+ set -o pipefail
+ LC_ALL=C btrfs subvolume show "$1" | sed -n 's/^\tSubvolume ID:\s*//p'
+)
+
+# Usage: btrfs_subvolume_list_all $FILEPATH
+#
+# Given $FILEPATH somewhere on a mounted btrfs filesystem, print the
+# ID and full path of every subvolume on the filesystem, one per line
+# in the format "$ID $PATH".
+btrfs_subvolume_list_all() (
+ set -o pipefail
+ local mountpoint
+ mountpoint="$(df --output=target "$1" | sed 1d)" || return $?
+ LC_ALL=C btrfs subvolume list -a "$mountpoint" | sed -r 's|^ID ([0-9]+) .* path (<FS_TREE>/)?(\S*).*|\1 \3|'
+)
+
+# Usage: btrfs_subvolume_list $SUBVOLUME
+#
+# Assuming that $SUBVOLUME is a btrfs subvolume, list all child
+# subvolumes; from most deeply nested to most shallowly nested.
+#
+# This is intended to be a sane version of `btrfs subvolume list`.
+btrfs_subvolume_list() {
+ local subvolume=$1
+
+ local id all path subpath
+ id="$(btrfs_subvolume_id "$subvolume")" || return $?
+ all="$(btrfs_subvolume_list_all "$subvolume")" || return $?
+ path="$(sed -n "s/^$id //p" <<<"$all")"
+ while read -r id subpath; do
+ if [[ "$subpath" = "$path"/* ]]; then
+ printf '%s\n' "${subpath#"${path}/"}"
+ fi
+ done <<<"$all" | LC_ALL=C sort --reverse
+}
+
+# Usage: btrfs_subvolume_delete $SUBVOLUME
+#
+# Assuming that $SUBVOLUME is a btrfs subvolume, delete it and all
+# subvolumes below it.
+#
+# This is intended to be a recursive version of
+# `btrfs subvolume delete`.
+btrfs_subvolume_delete() {
+ local dir="$1"
+ local subvolumes subvolume
+ subvolumes=($(btrfs_subvolume_list "$dir")) || return $?
+ for subvolume in "${subvolumes[@]}"; do
+ btrfs subvolume delete "$dir/$subvolume" || return $?
+ done
+ btrfs subvolume delete "$dir"
+}
+
create_chroot() {
# Lock the chroot we want to use. We'll keep this lock until we exit.
lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy"
@@ -92,7 +147,7 @@ create_chroot() {
stat_busy "Creating clean working copy [%s]" "$copy"
if [[ "$chroottype" == btrfs ]] && ! mountpoint -q "$copydir"; then
if [[ -d $copydir ]]; then
- btrfs subvolume delete "$copydir" >/dev/null ||
+ btrfs_subvolume_delete "$copydir" >/dev/null ||
die "Unable to delete subvolume %s" "$copydir"
fi
btrfs subvolume snapshot "$chrootdir/root" "$copydir" >/dev/null ||
@@ -114,7 +169,7 @@ create_chroot() {
clean_temporary() {
stat_busy "Removing temporary copy [%s]" "$copy"
if [[ "$chroottype" == btrfs ]] && ! mountpoint -q "$copydir"; then
- btrfs subvolume delete "$copydir" >/dev/null ||
+ btrfs_subvolume_delete "$copydir" >/dev/null ||
die "Unable to delete subvolume %s" "$copydir"
else
# avoid change of filesystem in case of an umount failure