#!/bin/sh # Called by systemd-shutdown after process termination and filesystem teardown. # Only normal poweroff is replaced; reboot, halt and kexec return immediately. [ "${1:-}" = poweroff ] || exit 0 PATH=/usr/bin:/usr/sbin:/bin:/sbin export PATH stty -F /dev/ttyS1 115200 cs8 -parenb -cstopb 2>/dev/null || : log() { printf 'BMC shutdown hook: %s\n' "$*" >/dev/console 2>/dev/null || : if [ -c /dev/ttyS1 ]; then printf 'BMC shutdown hook: %s\r\n' "$*" >/dev/ttyS1 2>/dev/null || : fi } log 'poweroff final hook entered' # systemd runs shutdown hooks in parallel. Let the installed firmware/MD # cleanup hooks finish before cutting power; never interrupt their work. sleep 2 i=0 while :; do busy=0 for file in /proc/[0-9]*/comm; do read -r name <"$file" 2>/dev/null || continue case "$name" in fwupd.shutdown|fwupdtool|mdadm.shutdown|mdadm) # Parallel hook children may stay as zombies until systemd # has waited for all hooks, including this one. state=$(awk '/^State:/ { print $2; exit }' "${file%/comm}/status" 2>/dev/null) case "$state" in Z|X) log "cleanup already exited: $name ($state)"; continue ;; '') continue ;; esac busy=1 ;; esac done [ "$busy" -eq 0 ] && break i=$((i + 1)) if [ "$i" -ge 20 ]; then log 'firmware/MD cleanup still active; keeping normal poweroff path' exit 0 fi sleep 1 done # Refuse to cut power if persistent storage is still mounted writable. if ! awk ' ($1 ~ /^\/dev\// || $3 ~ /^(overlay|zfs|btrfs|ext[234]|xfs|vfat|ntfs3|fuseblk|nfs|nfs4|cifs)$/) && $4 ~ /(^|,)rw(,|$)/ { bad=1 } END { exit bad } ' /proc/mounts; then log 'persistent writable mount remains; keeping normal poweroff path' exit 0 fi if ! awk 'NR > 1 { bad=1 } END { exit bad }' /proc/swaps; then log 'active swap remains; keeping normal poweroff path' exit 0 fi mounts=$(awk '$1 ~ /^\/dev\// { print $1, $2, $3, $4 }' /proc/mounts) log "persistent mounts read-only or unmounted; active swap absent: $mounts" if ! timeout 15 sync; then log 'sync did not finish; keeping normal poweroff path' exit 0 fi # Ubuntu's openipmi.service unloads ipmi_devintf and removes /dev/ipmi0 # during service shutdown. Restore the local interface without udev/systemd. if ! timeout 10 modprobe ipmi_si || ! timeout 10 modprobe ipmi_devintf; then log 'could not restore local IPMI drivers; keeping normal poweroff path' exit 0 fi if [ ! -c /dev/ipmi0 ]; then major=$(awk '$2 == "ipmidev" { print $1; exit }' /proc/devices) if [ -z "$major" ] || ! mknod -m 0600 /dev/ipmi0 c "$major" 0; then log 'could not restore /dev/ipmi0; keeping normal poweroff path' exit 0 fi fi log 'local IPMI interface ready' log 'sending ipmitool -I open chassis power off' if result=$(timeout 15 ipmitool -I open chassis power off 2>&1); then log "$result" log 'BMC accepted Force Off; waiting up to 15 seconds for power removal' sleep 15 log 'power still present; keeping normal poweroff path' else log "BMC command failed; keeping normal poweroff path: $result" fi exit 0