{ EDIT: Updated the script to enable PCIe Link Power Management. The NVMe ‘Unsafe Shutdown’ counter no longer increments during a Power Off. }
You have hard drive(s) attached to your router. You’re not sure if just yanking power is going to cause corruption.
smartctl --all /dev/nvme0
SMART/Health Information (NVMe Log 0x02, NSID 0xffffffff) Critical Warning: 0x00 Temperature: 47 Celsius Available Spare: 100% Available Spare Threshold: 10% Percentage Used: 0% Data Units Read: 1,080,727 [553 GB] Data Units Written: 109,464 [56.0 GB] Host Read Commands: 4,728,544 Host Write Commands: 618,993 Controller Busy Time: 0 Power Cycles: 23 Power On Hours: 16 Unsafe Shutdowns: 9 <=<=<=<=<=< THIS Media and Data Integrity Errors: 0 Error Information Log Entries: 0 Warning Comp. Temperature Time: 0 Critical Comp. Temperature Time: 0 Temperature Sensor 1: 47 Celsius Temperature Sensor 2: 62 Celsius
If you issue:
halt
… or:
poweroff
… the router just reboots.
So let’s set it up for a graceful shutdown.
First, create the shutdown script:
vi /etc/prep-unplug
… press i to enter editing mode, then paste this code in:
#!/bin/sh echo "Shutting down router... please wait..." service log stop 2>/dev/null ip link set eth0 down 2>/dev/null ip link set eth1 down 2>/dev/null if [ -d /sys/class/leds ]; then for led in /sys/class/leds/*; do echo none > "$led/trigger" 2>/dev/null echo 0 > "$led/brightness" 2>/dev/null done fi block umount 2>/dev/null sync sleep 5 sync sleep 5 # Cut power to the software layer first echo 1 > /sys/bus/pci/devices/0000:01:00.0/remove 2>/dev/null sync # Cut physical slot power echo "auto" > /sys/bus/pci/devices/0000:00:00.0/power/control 2>/dev/null sleep 2 if [ -f /sys/class/gpio/watchdog-enable/value ]; then echo 0 > /sys/class/gpio/watchdog-enable/value 2>/dev/null fi sleep 20 echo "When the router LEDs go dark, it is safe to pull the power." while true; do sleep 1 done
Press Esc to exit editing mode, then :wq to save and exit.
Make that file executable:
chmod +x /etc/prep-unplug
That stops the ‘Unsafe Shutdowns’ counter from incrementing, because the NVMe drive is synced and powered down when power to the router is pulled.
Next:
vi /etc/profile
Press i to enter editing mode, then scroll to the bottom of that file and enter:
alias poweroff='/etc/prep-unplug'
Press Esc to exit editing mode, then :wq to save and exit.
Initialize the changes:
source /etc/profile
The above catches terminal commands. If you issue poweroff from the terminal, it’ll run the /etc/prep-unplug script.
But, if you have automated internal tasks or third-party cron scripts calling /sbin/poweroff explicitly, an alias won’t catch that. You can fix this by dropping a symbolic wrapper script higher up in the system path execution priority (/usr/sbin/).
vi /usr/sbin/poweroff
Press i to enter editing mode, then enter:
#!/bin/sh exec /etc/prep-unplug
Press Esc to exit editing mode, then :wq to save and exit.
Make it executable:
chmod +x /usr/sbin/poweroff
When a service calls poweroff, the system searches /usr/sbin/. The /usr/sbin/poweroff script intercepts the hardware system call, and runs the /etc/prep-unplug script.
Make it all impervious to firmware updates. Under System >> Backup / Flash Firmware >> Configuration tab, add to the list:
/etc/profile /etc/prep-unplug /usr/sbin/poweroff
… then click the Save button at bottom.
Ensure the system sees it:
which poweroff
… which should return:
/usr/sbin/poweroff
Ensure the system sees it:
type poweroff
… which should return:
poweroff is an alias for /etc/prep-unplug