zur Übersicht: Linux: meine Software und Konfigurationstipps

shutdown reboot switch

21.03.2006

Das Problem

Manchmal hilft eben auch unter (meinem /ndash; das nehme ich auf mich) Linux nur der Affengriff. Mich störte, dass man darüber den Rechner nur fest herunterfahren oder neu starten kann, je nach Konfiguration von /etc/inittab.

der Lösungsansatz

Mein Ziel war, auf einfache Weise zwischen Neustart und Herunterfahren umschalten zu können, ohne die Trivialität der Affengriff-Steuerung zu kompromittieren. Mehrfaches Drücken soll zwischen beiden Optionen umschalten. Da init das natürlich nicht kann, war ein Wrapper-Script gefordert.

Implementierung

init ruft ein Shellscript auf, das sich den aktuellen "Affengriff-Status" merkt und die jeweilige Aktion auslöst. Ich habe daher die Zeile

# ca::ctrlaltdel:/sbin/shutdown -r -t 4 now

auskommentiert (das "#" am Zeilenanfang) und eine Modifikation dieser Zeile hinzugefügt:

ca::ctrlaltdel:/sbin/ctrl-alt-del

/sbin/ctrl-alt-del ist dementsprechend mein Wrapper-Script. Im Kern besteht es aus diesen zwei Funktionen, die fallweise aufgerufen werden:

do_shutdown () {
        test -d "$check_dir" && echo shutdown > "${check_dir}/${check_file}"
        echo $'\n'"The system is being shut down. 
Press <Ctrl>-<Alt>-<Del> again for rebooting."$'\n' > $REDIRECT
        sleep 2
        /sbin/telinit q # <Ctrl>-<Alt>-<Del> reaktivieren
        /sbin/shutdown -h -t 4 now
}

do_reboot () {
        test -d "$check_dir" && echo reboot > "${check_dir}/${check_file}"
        echo $'\n'"The system is rebooting.
Press <Ctrl>-<Alt>-<Del> again for powering off."$'\n' > $REDIRECT
        sleep 3
        /sbin/telinit q # <Ctrl>-<Alt>-<Del> reaktivieren
        /sbin/shutdown -h -t 4 now
}

Der Rest des Scripts befasst sich im wesentlichen mit der Frage, ob die Konfiguration dahingehend korrekt ist, dass die Steuerdatei bei jedem Bootvorgang gelöscht wird. Viel Code um nichts. :-) Mein Tribut an das Ideal ordentlicher Programmierung.

Der Aufruf von /sbin/telinit q ist nötig, weil nur dadurch bei erneutem Affengriff das Script noch mal aufgerufen wird.

Download

Und natürlich freue ich mich über einen Hinweis per Mail, wenn jemand meine Software benutzt. Kleine Änderungswünsche versuche ich zu berücksichtigen.

das Script

#!/bin/bash

# 31.12.2005, Hauke Laging, http://www.hauke-laging.de/, software@hauke-laging.de

# This script switches between reboot and system halt between its calls.
# If this script is called from the ctrlaltdel line in /etc/inittab
# then you can switch between reboot and system halt by pressing

# LICENSE
# This code is licensed to you under the GNU General Public License.
# See http://www.fsf.org/

# REQUIREMENTS
# - GNU date.

# USAGE
# You should configure this script and your system so that the variables
# $check_dir and $check_file together point to a file which does not exist
# after a reboot. This can be achieved by adding these commands to your
# boot.local file:
# test -e /var/run/empty_on_reboot && rm -r /var/run/empty_on_reboot
# mkdir -p /var/run/empty_on_reboot

check_dir=/var/run/empty_on_reboot
check_file=ctrl-alt-del
REDIRECT=/dev/tty1
first_action=do_reboot

do_shutdown () {
        test -d "$check_dir" && echo shutdown > "${check_dir}/${check_file}"
        echo $'\n'"The system is being shut down.
Press <Ctrl>-<Alt>-<Del> again for rebooting."$'\n' > $REDIRECT
        sleep 2
        /sbin/telinit q # <Ctrl>-<Alt>-<Del> reaktivieren
        /sbin/shutdown -h -t 4 now
}

do_reboot () {
        test -d "$check_dir" && echo reboot > "${check_dir}/${check_file}"
        echo $'\n'"The system is rebooting.
Press <Ctrl>-<Alt>-<Del> again for powering off."$'\n' > $REDIRECT
        sleep 3
        /sbin/telinit q # <Ctrl>-<Alt>-<Del> reaktivieren
        /sbin/shutdown -h -t 4 now
}

# standard action if the directory does not exist
test -e "$check_dir" || { "$first_action"; exit; }
if [ -f "${check_dir}/${check_file}" ]
        then
        # BEGIN: check if the file is older than the lifetime of the init process
        init_hours=0
        init_days=0
        init_etime=$(echo $(/bin/ps --pid 1 -o etime | sed 1d))
        init_seconds=${init_etime##*:}
        tmp=${init_etime%?????}
        init_minutes=${init_etime#${tmp}}
        init_minutes=${init_minutes%???}
        if [ -n "$tmp" ]
                then
                days_hours=${tmp%:}
                if [ ${#days_hours} -gt 2 ]
                        then
                        init_days=${days_hours%???}
                        init_hours=${days_hours%???}
                else
                        init_hours=$days_hours
                fi
        fi
        # COMMENT: These always have two digits
        init_seconds=${init_seconds#0}
        init_minutes=${init_minutes#0}
        # COMMENT: These have two digits only when set from ps output.
        test ${#init_hours} -gt 1 && init_hours=${init_hours#0}
        test ${#init_days} -gt 1 && init_days=${init_days#0}
        init_elapsed_seconds=$((init_seconds+init_minutes*60+init_hours*60*60+init_days*60*60*24))
        if date +%s &>/dev/null # GNU date available?
                then
                seconds_checkfile=$(/bin/date --reference="${check_dir}/${check_file}" +%s)
                seconds_system_currently=$(/bin/date +%s)
                seconds_system_boot=$((seconds_system_currently-init_elapsed_seconds))
                if [ "$seconds_system_boot" -gt "$seconds_checkfile" ]
                        then
                        "$first_action"
                        exit
                fi
        fi
        # END: check if the file is older than the lifetime of the init process
        state="$(cat "${check_dir}/${check_file}")"
else
        "$first_action"
        exit
fi
if [ "$state" = reboot ]
        then
        do_shutdown
else
        echo reboot > "${check_dir}/${check_file}"
        do_reboot
fi