nixpkgs/modules/system/upstart-events/halt.nix
Eelco Dolstra 9704472d1c Some hacks to support clean shutdowns of VMs that mount the Nix store
ove QEMU (and other NixOS instances that use a remote filesystem like
NFS):

* Don't take down the network interfaces during shutdown.
* Don't try to unmount the Nix store.  Usually, this doesn't work
  because it's still in use, but on remote filesystems like CIFS the
  `-f' umount flag actually works.

svn path=/nixos/branches/modular-nixos/; revision=16036
2009-06-24 13:33:03 +00:00

120 lines
3.3 KiB
Nix

{pkgs, config, ...}:
###### implementation
let
inherit (pkgs) bash utillinux;
jobFun = event : {
name = "sys-" + event;
job = ''
start on ${event}
script
set +e # continue in case of errors
exec < /dev/tty1 > /dev/tty1 2>&1
echo ""
echo "<<< SYSTEM SHUTDOWN >>>"
echo ""
export PATH=${utillinux}/bin:${utillinux}/sbin:$PATH
# Set the hardware clock to the system time.
echo "Setting the hardware clock..."
hwclock --systohc --utc || true
# Do an initial sync just in case.
sync || true
# Kill all remaining processes except init and this one.
echo "Sending the TERM signal to all processes..."
kill -TERM -1 || true
sleep 1 # wait briefly
echo "Sending the KILL signal to all processes..."
kill -KILL -1 || true
# Unmount helper functions.
getMountPoints() {
cat /proc/mounts \
| grep -v '^rootfs' \
| sed 's|^[^ ]\+ \+\([^ ]\+\).*|\1|' \
| grep -v '/proc\|/sys\|/dev'
}
getDevice() {
local mountPoint=$1
cat /proc/mounts \
| grep -v '^rootfs' \
| grep "^[^ ]\+ \+$mountPoint \+" \
| sed 's|^\([^ ]\+\).*|\1|'
}
# Unmount file systems. We repeat this until no more file systems
# can be unmounted. This is to handle loopback devices, file
# systems mounted on other file systems and so on.
tryAgain=1
while test -n "$tryAgain"; do
tryAgain=
for mp in $(getMountPoints); do
device=$(getDevice $mp)
echo "unmounting $mp..."
# !!! Don't unmount /nix/store or /hostfs. This is
# a quick hack to cleanly shutdown VMs that mount
# the Nix store via CIFS. "mount -f" will actually
# work on such filesystems, which makes all commands
# needed below disappear.
if test "$mp" != /nix/store -a "$mp" != /hostfs && umount -f -n "$mp"; then
if test "$mp" != /; then tryAgain=1; fi
else
mount -n -o remount,ro "$mp" || true
fi
# Hack: work around a bug in mount (mount -o remount on a
# loop device forgets the loop=/dev/loopN entry in
# /etc/mtab).
if echo "$device" | grep -q '/dev/loop'; then
echo "removing loop device $device..."
losetup -d "$device" || true
fi
done
done
cat /proc/mounts
# Final sync.
sync || true
# Either reboot or power-off the system. Note that the "halt"
# event also does a power-off.
if test ${event} = reboot; then
exec reboot -f
else
exec halt -f -p
fi
end script
'';
};
in
{
services = {
extraJobs = map jobFun ["reboot" "halt" "system-halt" "power-off"];
};
}