You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.3 KiB
163 lines
4.3 KiB
#!/bin/sh |
|
# |
|
# Licensed under the GPLv2 |
|
# |
|
# Copyright 2011, Red Hat, Inc. |
|
# Harald Hoyer <harald@redhat.com> |
|
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. |
|
[ -w /dev/console ] && \ |
|
( echo </dev/console &>/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 /oldsys |
|
for i in sys proc run dev; do |
|
mkdir /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 a mp a || [ -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 |
|
|
|
ls -l "/proc/$_pid/exe" 2>&1 | vwarn |
|
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 |
|
( . "$__f" $1 ) |
|
if [ $? -eq 0 ]; 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
|
|
|