From 3ccd0713674ee304cbf70898e8130dcb9a3eb588 Mon Sep 17 00:00:00 2001 From: TomasM Date: Sun, 12 Nov 2017 10:56:49 -0500 Subject: [PATCH] better shutdown handling --- initramfs/cleanup | 117 ------------------------------------- initramfs/initramfs_create | 12 ++-- initramfs/shutdown | 72 +++++++++++++++++++++++ livekitlib | 6 +- 4 files changed, 83 insertions(+), 124 deletions(-) delete mode 100644 initramfs/cleanup create mode 100644 initramfs/shutdown diff --git a/initramfs/cleanup b/initramfs/cleanup deleted file mode 100644 index 21a3203..0000000 --- a/initramfs/cleanup +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/sh -# This script must be executed with parameter "--start" at the end of distro shutdown -# What it does is it executes as init (process 1) and unmounts all filesystems -# including union and the USB device (if any), so it can be cleanly removed -# -# Simply add the following as the last command executed by init on your distro -# instead of the actual poweroff or shutdown command: -# -# exec /run/initramfs/lib/cleanup --start poweroff -# or -# exec /run/initramfs/lib/cleanup --start shutdown -# -# on Slackware, add this to rc.0: -# exec /run/initramfs/lib/cleanup --start /sbin/$command -# -# It may be needed to call this script also with --killall5 from your shutdown scripts -# instead of calling regular killall5, to prevent fuse filesystems from being killed -# -# Author: Tomas M -# - -if [ "$1" = "--killall5" ]; then - # kill all unneeded processes, which have smaller ID then the ID of - # current shell's parent process. We can't use killall5, as it would kill some - # processes which may be currently needed, for example fuse filesystems (ntfs-3g). - for pid in $(/run/initramfs/bin/ps | grep -v "PID" | grep -E -v "\[.*\]" | grep -E -v "mount|posixovl|fuse" | sed -r "s/^ +//" | cut -d " " -f 1); do - if [ $pid -lt $PPID ]; then - LIST="$LIST $pid" - fi - done - - kill -15 $LIST 2>/dev/null # SIGTERM - sleep 2 # give processes some time to end properly - kill -9 $LIST 2>/dev/null # SIGKILL -fi - - -if [ "$1" = "--start" ]; then - # This is the part which is to be called from shutdown script. - # We will assume init is running as process 1 and re-executes itself after 'telinit u' - # So we're going to force init to stop and start this script instead as PID 1 - # If your init works differently, you may need to slightly modify few lines below - # - without this, init would be blocking union and it couldn't be unmounted later. - cd /run/initramfs - cp "$0" sbin/init - pivot_root . memory/union - echo "$2 -f" > /lib/command - chroot /memory/union /sbin/telinit u -fi - - -if [ "$1" = "--init" ]; then - # now we're called from init to replace the process nr 1. - # We know that init binary reexecutes itself with --init parameter - # All other processes are already killed - # so our goal now is just to unmount everything and reboot/shutdown - - # First, mount proc and sys again since it will be needed and it was already unmounted - mount -t proc proc /proc >/dev/console 2>&1 - mount -t sysfs sysfs /sys >/dev/console 2>&1 - - # if debug is requested, start commandline prompt here - if grep -q debug /proc/cmdline; then - echo "Starting shell for debug" >/dev/console - setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1' - fi - - # Update devs so we are aware of all active /dev/loop* files. - # Detach loop devices which are no longer used - mdev -s - losetup | cut -d : -f 1 | xargs -n 1 losetup -d - - # next, unmount everything from union, backwards - tac /proc/mounts | grep union | cut -d " " -f 2 | while read LINE; do - umount $LINE >/dev/console 2>&1 - umount -l $LINE - done - - # then free up loop mounts, backwards - tac /proc/mounts | grep loop | cut -d " " -f 2 | while read LINE; do - umount $LINE >/dev/console 2>&1 || \ - umount -l $LINE - done - - # remember from which device we are started, do it now before we lose it - DEVICE="$(cat /proc/mounts | grep /memory/data | grep /dev/ | cut -d " " -f 1)" - - # free up memory mounts, backwards - tac /proc/mounts | grep memory | cut -d " " -f 2 | while read LINE; do - umount $LINE >/dev/console 2>&1 - if [ $? -ne 0 ]; then - mount -o remount,ro $LINE >/dev/console 2>&1 - umount -l $LINE - fi - done - - # eject cdrom device if we were running from it - for i in $(cat /proc/sys/dev/cdrom/info | grep name); do - if [ "$DEVICE" = "/dev/$i" ]; then - echo "Attemptiong to eject /dev/$i..." >/dev/console - eject /dev/$i - echo "CD/DVD tray will close in 6 seconds..." >/dev/console - sleep 6 - eject -t /dev/$i - fi - done - - # and finally, last chance to run some commands by hand - if grep -q debug /proc/cmdline; then - echo "Starting shell for debug" >/dev/console - setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1' - fi - - cat /lib/command >/dev/console - $(cat /lib/command 2>/dev/null) - reboot -f -fi diff --git a/initramfs/initramfs_create b/initramfs/initramfs_create index 4ef6ccd..eec143d 100755 --- a/initramfs/initramfs_create +++ b/initramfs/initramfs_create @@ -45,8 +45,12 @@ rm -Rf $INITRAMFS mkdir -p $INITRAMFS/{bin,dev,etc,lib,lib64,mnt,proc,root,run,sys,tmp,usr,var/log} ln -s bin $INITRAMFS/sbin -cp static/{busybox,mount.*,eject} $INITRAMFS/bin -chmod a+x $INITRAMFS/bin/{busybox,mount.*,eject} +cp static/busybox $INITRAMFS/bin +cp static/eject $INITRAMFS/bin +cp static/mount.dynfilefs $INITRAMFS/bin/@mount.dynfilefs +cp static/mount.httpfs2 $INITRAMFS/bin/@mount.httpfs2 +cp static/mount.ntfs-3g $INITRAMFS/bin/@mount.ntfs-3g +chmod a+x $INITRAMFS/bin/* $INITRAMFS/bin/busybox | grep , | grep -v Copyright | tr "," " " | while read LINE; do for TOOL in $LINE; do @@ -128,8 +132,8 @@ touch $INITRAMFS/etc/{m,fs}tab cp init $INITRAMFS chmod a+x $INITRAMFS/init -cp cleanup $INITRAMFS/lib -chmod a+x $INITRAMFS/lib/cleanup +cp shutdown $INITRAMFS +chmod a+x $INITRAMFS/shutdown ln -s ../init $INITRAMFS/bin/init cp ../livekitlib $INITRAMFS/lib/ cp ../config $INITRAMFS/lib/ diff --git a/initramfs/shutdown b/initramfs/shutdown new file mode 100644 index 0000000..20ed5b9 --- /dev/null +++ b/initramfs/shutdown @@ -0,0 +1,72 @@ +#!/bin/sh +# Shutdown script for initramfs. It's automatically started by +# systemd (if you use it) on shutdown, no need for any tweaks. +# Purpose of this script is to unmount everything cleanly. +# +# Author: Tomas M +# + +. /lib/config +. /lib/livekitlib + +debug_start + +debug_log "Entering shutdown procedures of Linux Live Kit" +debug_log "Called with arguments: " "$*" + +# if debug is enabled, run shell now +debug_shell + +detach_free_loops() +{ + losetup | cut -d : -f 1 | xargs -r -n 1 losetup -d +} + +# $1=dir +umount_all() +{ + tac /proc/mounts | cut -d " " -f 2 | grep ^$1 | while read LINE; do + umount $LINE 2>/dev/null + done +} + +# Update devs so we are aware of all active /dev/loop* files. +# Detach loop devices which are no longer used +mdev -s +detach_free_loops + +# do it the dirty way, simply try to umount everything to get rid of most mounts +umount_all /oldroot + +# free aufs of /run mount, and umount aufs +mkdir /run2 +mount --move /oldroot/run /run2 +umount /oldroot + +# remember from which device we are started, so we can eject it later +DEVICE="$(cat /proc/mounts | grep /memory/data | grep /dev/ | cut -d " " -f 1)" + +umount_all /run2 +detach_free_loops +umount_all /run2 +detach_free_loops +umount_all /run2 + +/bin/bash + +# eject cdrom device if we were running from it +for i in $(cat /proc/sys/dev/cdrom/info | grep name); do + if [ "$DEVICE" = "/dev/$i" ]; then + echo "Attemptiong to eject /dev/$i..." >/dev/console + eject /dev/$i + echo "CD/DVD tray will close in 6 seconds..." >/dev/console + sleep 6 + eject -t /dev/$i + fi +done + +debug_shell + +$1 -f + +reboot -f diff --git a/livekitlib b/livekitlib index ecab77c..58ecb19 100644 --- a/livekitlib +++ b/livekitlib @@ -404,7 +404,7 @@ mount_data_http() if [ "$(network_device)" != "" ]; then echo "* Mounting remote file..." >&2 mkdir -p "$2" - mount.httpfs2 -r 9999 -t 5 $CACHE -c /dev/null "$1" "$2" >/dev/null 2>/dev/null + @mount.httpfs2 -r 9999 -t 5 $CACHE -c /dev/null "$1" "$2" -o ro >/dev/null 2>/dev/null mount -o loop "$2"/* "$2" # self mount echo "$2/$LIVEKITNAME" fi @@ -595,7 +595,7 @@ persistent_changes() echo "* Activating dynamic sized storage for persistent changes" rm "$T1" "$T2" 2>/dev/null - mount.dynfilefs "$CHANGES/changes.dat" 4000 "$2" + @mount.dynfilefs "$CHANGES/changes.dat" 4000 "$2" if [ "$(device_bestfs "$2/loop.fs" | tr -d " ")" = "-t" ]; then mke2fs -F "$2/loop.fs" >/dev/null fi @@ -709,7 +709,7 @@ union_append_bundles() echo "* $BUNDLE" BUN="$(basename "$BUNDLE")" mkdir -p "$2/$BUN" - mount -o loop -t squashfs "$1/$BUNDLE" "$2/$BUN" + mount -o loop,ro -t squashfs "$1/$BUNDLE" "$2/$BUN" mount -o remount,add:1:"$2/$BUN" aufs "$3" done }