#!/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 remove "$devname" ;; dm) read devname <"$1/dm/name" dmsetup remove "$devname" ;; lvm) # disassemble the parent VG read devname <"$1/dm/name" lvm lvdisplay -c "/dev/mapper/$devname" | { IFS=: read _ vgname _ lvm vgchange --noudevsync -an "$vgname" } ;; raid*) mdadm --stop "/dev/$1" ;; dmraid) read devname <"$1/dm/name" dmraid -an "$devname" ;; # 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 } # XXX: Discourage libdevmapper from thinking that udev # might be in a useful state. FS#30995. rm -rf /run/udev printf '%s\n' 'Detaching loop devices.' for loop in loop*/loop; do [ -e "$loop" ] && losetup -d "${loop%/loop}" done printf '%s\n' "Unmounting all devices." # unmount everything in /oldroot findmnt -Rruno TARGET /oldroot | awk ' BEGIN { i = 0 } { i++ mounts[i] = $0 } END { for (j = i; j > 0; j--) { print mounts[j] } } ' | while read -r mount; do umount "$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 ;; *) type kexec >/dev/null && kexec -e reboot -f ;; esac # vim: ft=sh ts=4 sw=4