summaryrefslogtreecommitdiffstats
path: root/shutdown
diff options
context:
space:
mode:
Diffstat (limited to 'shutdown')
-rwxr-xr-xshutdown64
1 files changed, 64 insertions, 0 deletions
diff --git a/shutdown b/shutdown
index aad0198..f664d6e 100755
--- a/shutdown
+++ b/shutdown
@@ -1,5 +1,59 @@
#!/usr/bin/ash
+# teardown a single device by node name
+# $1: device node name, e.g. md0, dm-2
+stop_device() {
+ local devtype= devname=
+
+ # the device must still be active
+ [ -e "/sys/class/block/$1" ] || return 1
+
+ # this can sometimes fail on stopped md devices, when the
+ # sysfs node doesn't go away as quickly as i'd like it to.
+ devtype=$(lsblk -drno TYPE "/dev/$1" 2>/dev/null) || return 1
+ case $devtype in
+ crypt)
+ read devname <"$1/dm/name"
+ cryptsetup luksClose "$devname"
+ ;;
+ dm|lvm)
+ # disassemble the parent VG
+ read devname <"$1/dm/name"
+ lvm lvdisplay -c "/dev/mapper/$devname" | {
+ IFS=: read _ vgname _
+ lvm vgchange -an "$vgname"
+ }
+ ;;
+ raid*)
+ mdadm --stop "/dev/$1"
+ ;;
+ dmraid)
+ # XXX: i have no idea how dmraid works
+ dmraid -an
+ ;;
+ # silently ignore unstacked devices
+ esac
+}
+
+# recursively disassemble a device chain
+# $1: device node name, e.g. md0, dm-2
+disassemble() {
+ local holder=
+
+ for holder in "$1"/holders/*; do
+ if [ ! -e "$holder" ]; then
+ # end of the chain, recurse back up
+ stop_device "$1"
+ return
+ fi
+ disassemble "${holder##*/}"
+ stop_device "$1"
+ done
+}
+
+printf '%s\n' "Unmounting all devices."
+
+# unmount everything, but leave the API mounts
findmnt -Rruno TARGET /oldroot | awk '
BEGIN { i = 0 }
! /^\/(proc|dev|sys)/ {
@@ -15,6 +69,16 @@ END {
umount -l "$mount"
done
+printf '%s\n' "Disassembling stacked devices."
+
+# chdir, so that we can avoid a lot of path chopping
+cd /sys/class/block
+
+# iterate over devices with holders
+for part in */holders/*; do
+ [ -e "$part" ] && disassemble "${part%%/*}"
+done
+
case $1 in
poweroff|shutdown|halt)
"$1" -f