#!/bin/sh # # Licensed under the GPLv2 # # Copyright 2011, Red Hat, Inc. # Harald Hoyer ACTION="$1" # Before trying to use /dev/console, verify that it exists, # and that it can actually be used. When console=null is used, # echo will fail. We do the check in a subshell, because otherwise # the process will be killed when when running as PID 1. # shellcheck disable=SC2217 [ -w /dev/console ] \ && (echo < /dev/console > /dev/null 2> /dev/null) \ && exec < /dev/console >> /dev/console 2>> /dev/console export TERM=linux export PATH=/usr/sbin:/usr/bin:/sbin:/bin . /lib/dracut-lib.sh if [ "$(stat -c '%T' -f /)" = "tmpfs" ]; then mount -o remount,rw / fi mkdir -p /oldsys for i in sys proc run dev; do mkdir -p /oldsys/$i mount --move /oldroot/$i /oldsys/$i done # if "kexec" was installed after creating the initramfs, we try to copy it from the real root # libz normally is pulled in via kmod/modprobe and udevadm if [ "$ACTION" = "kexec" ] && ! command -v kexec > /dev/null 2>&1; then for p in /usr/sbin /usr/bin /sbin /bin; do cp -a /oldroot/${p}/kexec $p > /dev/null 2>&1 && break done hash kexec fi trap "emergency_shell --shutdown shutdown Signal caught!" 0 getarg 'rd.break=pre-shutdown' && emergency_shell --shutdown pre-shutdown "Break before pre-shutdown" source_hook pre-shutdown warn "Killing all remaining processes" killall_proc_mountpoint /oldroot || sleep 0.2 # Timeout for umount calls. The value can be set to 0 to wait forever. _umount_timeout=$(getarg rd.shutdown.timeout.umount) _umount_timeout=${_umount_timeout:-90s} _timed_out_umounts="" umount_a() { local _verbose="n" if [ "$1" = "-v" ]; then _verbose="y" shift exec 7>&2 else exec 7> /dev/null fi local _did_umount="n" while read -r _ mp _ || [ -n "$mp" ]; do strstr "$mp" oldroot || continue strstr "$_timed_out_umounts" " $mp " && continue # Unmount the file system. The operation uses a timeout to avoid waiting # indefinitely if this is e.g. a stuck NFS mount. The command is # invoked in a subshell to silence also the "Killed" message that might # be produced by the shell. ( set +m timeout --signal=KILL "$_umount_timeout" umount "$mp" ) 2>&7 local ret=$? if [ $ret -eq 0 ]; then _did_umount="y" warn "Unmounted $mp." elif [ $ret -eq 137 ]; then _timed_out_umounts="$_timed_out_umounts $mp " warn "Unmounting $mp timed out." elif [ "$_verbose" = "y" ]; then warn "Unmounting $mp failed with status $ret." fi done < /proc/mounts losetup -D 2>&7 exec 7>&- [ "$_did_umount" = "y" ] && return 0 return 1 } _cnt=0 while [ $_cnt -le 40 ]; do umount_a || break _cnt=$((_cnt + 1)) done [ $_cnt -ge 40 ] && umount_a -v if strstr "$(cat /proc/mounts)" "/oldroot"; then warn "Cannot umount /oldroot" for _pid in /proc/*; do _pid=${_pid##/proc/} case $_pid in *[!0-9]*) continue ;; esac [ "$_pid" -eq $$ ] && continue [ -e "/proc/$_pid/exe" ] || continue [ -e "/proc/$_pid/root" ] || continue if strstr "$(ls -l /proc/"$_pid" /proc/"$_pid"/fd 2> /dev/null)" "oldroot"; then warn "Blocking umount of /oldroot [$_pid] $(cat /proc/"$_pid"/cmdline)" else warn "Still running [$_pid] $(cat /proc/"$_pid"/cmdline)" fi # shellcheck disable=SC2012 ls -l "/proc/$_pid/exe" 2>&1 | vwarn # shellcheck disable=SC2012 ls -l "/proc/$_pid/fd" 2>&1 | vwarn done fi _check_shutdown() { local __f local __s=0 for __f in "$hookdir"/shutdown/*.sh; do [ -e "$__f" ] || continue # shellcheck disable=SC1090 disable=SC2240 if (final="$1" . "$__f" "$1"); then rm -f -- "$__f" else __s=1 fi done return $__s } _cnt=0 while [ $_cnt -le 40 ]; do _check_shutdown && break _cnt=$((_cnt + 1)) done [ $_cnt -ge 40 ] && _check_shutdown final getarg 'rd.break=shutdown' && emergency_shell --shutdown shutdown "Break before shutdown" case "$ACTION" in reboot | poweroff | halt) $ACTION -f -n warn "$ACTION failed!" ;; kexec) kexec -e warn "$ACTION failed!" reboot -f -n ;; *) warn "Shutdown called with argument '$ACTION'. Rebooting!" reboot -f -n ;; esac emergency_shell --shutdown shutdown