| #!/bin/sh |
| |
| fail(){ |
| echo "$@" >&2 |
| # The behaviour on failure of systemd when shutting down without a |
| # shutdownramfs is to freeze if it fails, but the behaviour of an initramfs |
| # on failure is to drop you into a recovery shell. The latter seems more |
| # useful. |
| exec /bin/sh |
| } |
| |
| startswith(){ |
| # Filter out lines that don't start with $1 |
| # grep ^EXPR is usually sufficient, but would require escaping of EXPR. |
| # Instead this compares the line to the line with its prefix stripped, |
| # so if the line is different, then it started with that prefix. |
| # It's ugly, but is less logic than escaping the regular expression and |
| # using grep, more reliable than not making any effort to escape, and |
| # less surprising than requiring the parameter to be pre-escaped. |
| while read -r line; do |
| if [ "${line#"$1"}" != "$line" ]; then |
| printf '%s\n' "$line" |
| fi |
| done |
| } |
| |
| recursive_umount(){ |
| # Recursively unmount every mountpoint under $1. |
| # This works by filtering to select mountpoints from mountinfo that start |
| # with the absolute path of the directory given. |
| # It unmounts in reverse-order, so that it may unmount dependent mounts |
| # first, and it has to handle the paths having octal escape sequences. |
| set -- "$(readlink -f "$1")" |
| cut -d' ' -f5 /proc/self/mountinfo | startswith "$1" \ |
| | sort -r | while read -r mp; do |
| umount "$(echo -e "$mp")" |
| done |
| } |
| |
| # Give the rootfs another chance to write its state to disk. |
| sync |
| |
| # Kill any http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/ |
| # as we don't have any facility to cleanly shut them down in this initramfs. |
| killall5 |
| |
| # Recursively unmount the old root, so they have a chance of performing |
| # unmount-time cleanup. |
| recursive_umount /oldroot |
| |
| case "$1" in |
| reboot|poweroff|halt) |
| if ! "$1" -f; then |
| fail "$1 command failed" |
| fi |
| ;; |
| kexec) |
| # probably don't have this, but we'll try anyway |
| if ! kexec -e; then |
| fail "$1 command failed" |
| fi |
| ;; |
| *) |
| fail "Unrecognized shutdown verb $1" |
| ;; |
| esac |
| |