summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile49
-rw-r--r--molly-guard.xml344
-rw-r--r--rc11
-rwxr-xr-xrun.d/10-print-message22
-rwxr-xr-xrun.d/30-query-hostname98
-rwxr-xr-xshutdown.in126
6 files changed, 650 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..67f0b05
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+PREFIX?=/usr
+cfgdir?=/etc/molly-guard
+libdir?=/lib
+sbindir?=/sbin
+REALPATH?=$(libdir)/molly-guard
+
+all: molly-guard.8 shutdown
+
+%.8: DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl
+%.8: XP=xsltproc -''-nonet
+%.8: %.xml
+ $(XP) $(DB2MAN) $<
+
+man: molly-guard.8
+ man -l $<
+.PHONY: man
+
+clean:
+ rm -f shutdown
+ rm -f molly-guard.8
+.PHONY: clean
+
+shutdown: shutdown.in
+ sed -e 's,@cfgdir@,$(cfgdir),g;s,@REALPATH@,$(REALPATH),g' $< > $@
+
+install: shutdown molly-guard.8
+ mkdir -m755 --parent $(DESTDIR)$(libdir)/molly-guard
+ install -m755 -oroot -oroot shutdown $(DESTDIR)$(libdir)/molly-guard/molly-guard
+
+ mkdir -m755 --parent $(DESTDIR)$(sbindir)
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/poweroff
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/halt
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/reboot
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/shutdown
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/coldreboot
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/pm-hibernate
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/pm-suspend
+ ln -s $(libdir)/molly-guard/molly-guard $(DESTDIR)$(sbindir)/pm-suspend-hybrid
+
+ mkdir -m755 --parent $(DESTDIR)$(cfgdir)
+ install -m644 -oroot -oroot rc $(DESTDIR)$(cfgdir)
+ cp -r run.d $(DESTDIR)$(cfgdir) \
+ && chown root.root $(DESTDIR)$(cfgdir)/run.d && chmod 755 $(DESTDIR)$(cfgdir)/run.d
+
+ mkdir -m755 --parent $(DESTDIR)$(cfgdir)/messages.d
+
+ mkdir -m755 --parent $(DESTDIR)$(PREFIX)/share/man/man8
+ install -m644 -oroot -groot molly-guard.8 $(DESTDIR)$(PREFIX)/share/man/man8
+.PHONY: install
diff --git a/molly-guard.xml b/molly-guard.xml
new file mode 100644
index 0000000..9c01f2f
--- /dev/null
+++ b/molly-guard.xml
@@ -0,0 +1,344 @@
+<?xml version='1.0' encoding='ISO-8859-1'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+
+<!--
+
+Process this file with an XSLT processor: `xsltproc \
+-''-nonet /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\
+manpages/docbook.xsl manpage.dbk'. A manual page
+<package>.<section> will be generated. You may view the
+manual page with: nroff -man <package>.<section> | less'. A
+typical entry in a Makefile or Makefile.am is:
+
+DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/\
+manpages/docbook.xsl
+XP=xsltproc -''-nonet
+
+manpage.1: manpage.dbk
+ $(XP) $(DB2MAN) $<
+
+The xsltproc binary is found in the xsltproc package. The
+XSL files are in docbook-xsl. Please remember that if you
+create the nroff version in one of the debian/rules file
+targets (such as build), you will need to include xsltproc
+and docbook-xsl in your Build-Depends control field.
+
+-->
+
+ <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+ <!ENTITY dhfirstname "<firstname>martin f.</firstname>">
+ <!ENTITY dhsurname "<surname>krafft</surname>">
+ <!-- Please adjust the date whenever revising the manpage. -->
+ <!ENTITY dhdate "<date>Apr 19, 2008</date>">
+ <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+ allowed: see man(7), man(1). -->
+ <!ENTITY dhsection "<manvolnum>8</manvolnum>">
+ <!ENTITY dhemail "<email>madduck@madduck.net</email>">
+ <!ENTITY dhusername "martin f. krafft">
+ <!ENTITY dhucpackage "<refentrytitle>molly-guard</refentrytitle>">
+ <!ENTITY dhpackage "molly-guard">
+ <!ENTITY dhcommand "<command>molly-guard</command>">
+
+ <!ENTITY debian "<productname>Debian</productname>">
+ <!ENTITY gnu "<acronym>GNU</acronym>">
+ <!ENTITY gpl "&gnu; <acronym>GPL</acronym>">
+]>
+
+<refentry>
+ <refentryinfo>
+ <address>
+ &dhemail;
+ </address>
+ <copyright>
+ <year>2008</year>
+ <holder>&dhusername;</holder>
+ </copyright>
+ &dhdate;
+ </refentryinfo>
+ <refmeta>
+ &dhucpackage;
+
+ &dhsection;
+ </refmeta>
+ <refnamediv>
+ <refname>&dhcommand;</refname>
+
+ <refpurpose>guard against accidental shutdowns/reboots</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>shutdown</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>halt</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>reboot</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>poweroff</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>coldreboot</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>pm-hibernate</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>pm-suspend</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>pm-suspend-hybrid</command>
+ <arg choice="opt">
+ -<option>hV</option>
+ </arg>
+ <arg choice="opt">
+ <option>--molly-guard-do-nothing</option>
+ </arg>
+ <arg choice="opt">
+ -- <replaceable>script_options</replaceable>
+ </arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para> &dhcommand; attempts to prevent you from accidentally shutting down
+ or rebooting machines. It does this by injecting a couple of checks
+ before the existing commands: <command>coldreboot</command>,
+ <command>halt</command>, <command>reboot</command>,
+ <command>shutdown</command>, <command>poweroff</command>,
+ <command>pm-hibernate</command>,<command>pm-suspend</command>
+ and <command>pm-suspend-hybrid</command>.</para>
+
+ <para> Before &dhcommand; invokes the real command, all scripts in
+ <filename>/etc/molly-guard/run.d/</filename> have to run and exit
+ successfully; else, it aborts the command.
+ <command>run-parts(1)</command> is used to process the directory.</para>
+
+ <para> &dhcommand; passes any <replaceable>script_options</replaceable> to the
+ scripts, and also populates the environment with the following
+ variables:</para>
+
+ <itemizedlist>
+ <listitem><para><envar>MOLLYGUARD_CMD</envar> - the actual command
+ invoked by the user.</para></listitem>
+
+ <listitem><para><envar>MOLLYGUARD_DO_NOTHING</envar> - set to
+ <option>1</option> if this is a demo-run.</para></listitem>
+
+ <listitem><para><envar>MOLLYGUARD_SETTINGS</envar> - the path to
+ a shell script snippet which scripts can source to obtain
+ settings.</para></listitem>
+ </itemizedlist>
+
+ <para> &dhcommand; prints the contents of
+ <filename>/etc/molly-guard/messages.d/COMMAND</filename> or
+ <filename>/etc/molly-guard/messages.d/default</filename> to the console,
+ if either exists. This is due to
+ <filename>/etc/molly-guard/run.d/10-print-message</filename>.</para>
+
+ </refsect1>
+ <refsect1>
+ <title>GUARDING SSH SESSIONS</title>
+
+ <para> &dhcommand; was primarily designed to shield SSH connections. This
+ functionality (which should arguably be provided by the
+ <package>openssh-server</package> package) is implemented in
+ <filename>/etc/molly-guard/run.d/30-query-hostname</filename>.</para>
+
+ <para> This script first tests whether the command is being executed from
+ a <filename>tty</filename> which has been created by
+ <command>sshd</command>. It also checks whether the variable
+ <envar>SSH_CONNECTION</envar> is defined. If any of these tests are
+ successful, test script queries the user for the machine's hostname,
+ which should be sufficient to prevent the user from doing something by
+ accident.</para>
+
+ <para> You can pass the <option>--pretend-ssh</option> script option to
+ &dhcommand; to pretend that those tests succeeds. Alternatively, setting
+ <envar>ALWAYS_QUERY_HOSTNAME</envar> in
+ <filename>/etc/molly-guard/rc</filename> causes the script to
+ always query.</para>
+
+ <para> The following situations are still UNGUARDED. If you can think of
+ ways to protect against those, please let me know!</para>
+
+ <itemizedlist>
+ <listitem><para>running <application>sudo</application> within
+ <application>screen</application> or <application>screen</application> within
+ <application>sudo</application>; <application>sudo</application> eats the
+ <envar>SSH_CONNECTION</envar> variable, and
+ <application>screen</application> creates a new
+ <filename>pty</filename>.</para></listitem>
+ <listitem><para>executing those command in a remote terminal window,
+ that is a <application>XTerm</application> started on a remote
+ machine but displaying on the local <application>X</application>
+ server.</para></listitem>
+ </itemizedlist>
+
+ <para> You have been warned. You can use the
+ <option>--molly-guard-do-nothing</option> switch to prevent anything
+ from happening, e.g. <userinput>halt
+ --molly-guard-do-nothing</userinput>. </para>
+ </refsect1>
+
+ <refsect1>
+ <title>OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>--molly-guard-do-nothing</term>
+ <listitem>
+ <para>
+ Cause &dhcommand; to print the command which would be executed,
+ after processing all scripts, instead of executing it.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <term>--help</term>
+ <listitem>
+ <para>
+ Display usage information.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-V</term>
+ <term>--version</term>
+ <listitem>
+ <para>
+ Display version information.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>shutdown</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>halt</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>reboot</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>poweroff</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ <citerefentry>
+ <refentrytitle>coldreboot</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ <citerefentry>
+ <refentrytitle>pm-hibernate</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ <citerefentry>
+ <refentrytitle>pm-suspend</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ <citerefentry>
+ <refentrytitle>pm-suspend-hybrid</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>LEGALESE</title>
+
+ <para>
+ &dhpackage; is copyright by &dhusername;. Andrew Ruthven came up with
+ the idea of using the scripts directory and submitted a patch, which
+ I modified a bit.
+ </para>
+
+ <para>
+ This manual page was written by &dhusername; &dhemail;.
+ </para>
+
+ <para>
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the Artistic License 2.0
+ </para>
+
+ </refsect1>
+</refentry>
diff --git a/rc b/rc
new file mode 100644
index 0000000..c6cab51
--- /dev/null
+++ b/rc
@@ -0,0 +1,11 @@
+# molly-guard settings
+#
+# ALWAYS_QUERY_HOSTNAME
+# when set, causes the 30-query-hostname script to always ask for the
+# hostname, even if no SSH session was detected.
+#ALWAYS_QUERY_HOSTNAME=true
+
+# USE_FQDN
+# when set, causes the 30-query-hostname script to ask for the fully-qualified
+# hostname, rather than the short name
+#USE_FQDN=true
diff --git a/run.d/10-print-message b/run.d/10-print-message
new file mode 100755
index 0000000..0e19526
--- /dev/null
+++ b/run.d/10-print-message
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# 10-print-message - print a (command-specific or default) message
+#
+# Copyright © Andrew Ruthven <andrew@etc.gen.nz>
+# Copyright © martin f. krafft <madduck@madduck.net>
+# Released under the terms of the Artistic Licence 2.0
+#
+# Prints either /etc/molly-guard/messages.d/$MOLLYGUARD_CMD
+# or /etc/molly-guard/messages.d/default
+# depending on whether the first exists.
+#
+set -eu
+
+MESSAGESDIR=/etc/molly-guard/messages.d
+
+for i in $MOLLYGUARD_CMD default; do
+ if [ -f "$MESSAGESDIR/$i" ] && [ -r "$MESSAGESDIR/$i" ]; then
+ cat $MESSAGESDIR/$i
+ exit 0
+ fi
+done
diff --git a/run.d/30-query-hostname b/run.d/30-query-hostname
new file mode 100755
index 0000000..d34ce06
--- /dev/null
+++ b/run.d/30-query-hostname
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# 30-ask-hostname - request the user to type in the hostname of the local host
+#
+# Copyright © 2006-2009 martin f. krafft <madduck@madduck.net>
+# Copyright © 2012 Ludovico Gardenghi <lu@dovi.co>
+# Copyright © 2014 Josh Triplett <josh@joshtriplett.org>
+# Copyright © 2015 Francois Marier <francois@debian.org>
+# Copyright © 2017 Simó Albert i Beltran <sim6@probeta.net>
+# Released under the terms of the Artistic Licence 2.0
+#
+set -eu
+
+ME=molly-guard
+
+# Walk up the process tree until PID 1 is reached or a process with 'sshd' in
+# its /proc/<pid>/cmdline is met. Return success if such a process is found.
+is_child_of_sshd_or_mosh_server() {
+ pid=$$
+ ppid=$PPID
+ # Be a bit paranoid with the guard, should some horribly broken system
+ # provide a strange process hierarchy. '[ $pid -ne 1 ]' should be enough for
+ # sane systems.
+ [ -z "$pid" ] || [ -z "$ppid" ] && return 2
+ while [ $pid -gt 1 ] && [ $pid -ne $ppid ]; do
+ if egrep -q 'sshd|mosh-server' /proc/$ppid/cmdline; then
+ return 0
+ fi
+ pid=$ppid
+ ppid=$(grep ^PPid: /proc/$pid/status | tr -dc 0-9)
+ done
+ return 1
+}
+
+[ -f "$MOLLYGUARD_SETTINGS" ] && . "$MOLLYGUARD_SETTINGS"
+
+PRETEND_SSH=0
+for arg in "$@"; do
+ case "$arg" in
+ (*-pretend-ssh) PRETEND_SSH=1;;
+ esac
+done
+
+# require an interactive terminal connected to stdin
+test -t 0 || exit 0
+
+# we've been asked to always protect this host
+case "${ALWAYS_QUERY_HOSTNAME:-0}" in
+ 0|false|False|no|No|off|Off)
+ # only run if we are being called over SSH, that is if the current terminal
+ # was created by sshd.
+ command -v tty >/dev/null 2>&1 || exit 0
+ PTS=$(tty)
+ if ! pgrep -f "^sshd.+${PTS#/dev/}\>" >/dev/null \
+ && [ -z "${SSH_CONNECTION:-}" ] \
+ && ! is_child_of_sshd_or_mosh_server; then
+ if [ $PRETEND_SSH -eq 1 ]; then
+ echo "I: $ME: this is not an SSH session, but --pretend-ssh was given..." >&2
+ else
+ exit 0
+ fi
+ else
+ echo "W: $ME: SSH session detected!" >&2
+ fi
+ ;;
+ *)
+ echo "I: $ME: $MOLLYGUARD_CMD is always molly-guarded on this system." >&2
+ ;;
+esac
+
+case "${USE_FQDN:-0}" in
+ 0|false|False|no|No|off|Off)
+ HOSTNAME="$(hostname --short)"
+ ;;
+ *)
+ HOSTNAME="$(hostname --fqdn)"
+ ;;
+esac
+
+sigh()
+{
+ echo "Good thing I asked; I won't $MOLLYGUARD_CMD $HOSTNAME ..." >&2
+ exit 1
+}
+
+trap 'echo;sigh' 1 2 3 9 10 12 15
+
+echo -n "Please type in hostname of the machine to $MOLLYGUARD_CMD: "
+read HOSTNAME_USER || :
+
+HOSTNAME="$(echo "$HOSTNAME" | tr '[:upper:]' '[:lower:]')"
+HOSTNAME_USER="$(echo "$HOSTNAME_USER" | tr '[:upper:]' '[:lower:]')"
+
+[ "$HOSTNAME_USER" = "$HOSTNAME" ] || sigh
+
+trap - 1 2 3 9 10 12 15
+
+exit 0
diff --git a/shutdown.in b/shutdown.in
new file mode 100755
index 0000000..08579aa
--- /dev/null
+++ b/shutdown.in
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# shutdown -- wrapper script to guard against accidental shutdowns
+#
+# Copyright © martin f. krafft <madduck@madduck.net>
+# Released under the terms of the Artistic Licence 2.0
+#
+set -eu
+
+ME=molly-guard
+VERSION=0.4
+
+SCRIPTSDIR="@cfgdir@/run.d"
+
+CMD="${0##*/}"
+EXEC="@REALPATH@/$CMD"
+
+case "$CMD" in
+ halt|reboot|shutdown|poweroff|coldreboot|pm-hibernate|pm-suspend|pm-suspend-hybrid)
+ if [ ! -f $EXEC ]; then
+ echo "E: not a regular file: $EXEC" >&2
+ exit 4
+ fi
+ if [ ! -x $EXEC ]; then
+ echo "E: not an executable: $EXEC" >&2
+ exit 3
+ fi
+ ;;
+ *)
+ echo "E: unsupported command: $CMD" >&2
+ exit 1
+ ;;
+esac
+
+usage()
+{
+ cat <<-_eousage
+ Usage: $ME [options] [-- script options]
+ (shielding $EXEC)
+
+ molly-guard's primary goal is to guard against accidental
+ shutdowns/reboots. $ME will run all scripts in $SCRIPTSDIR and only
+ invokes $EXEC if all scripts exited successfully.
+
+ Specifying --molly-guard-do-nothing as argument to the command will
+ make $ME echo the command it would execute rather than actually
+ executing it.
+
+ Options following the double hyphen will be passed unchanged to the
+ scripts.
+
+ Please see molly-guard(8) for more information.
+
+ The actual command's help output follows:
+
+ _eousage
+}
+
+CMDARGS=
+SCRIPTARGS=
+END_OF_ARGS=0
+DO_NOTHING=0
+for arg in "$@"; do
+ case "$arg" in
+ (*-molly-guard-do-nothing) DO_NOTHING=1;;
+ (*-help)
+ usage 2>&1
+ eval $EXEC --help 2>&1
+ exit 0
+ ;;
+ --) END_OF_ARGS=1;;
+ *\"*)
+ echo 'E: cannot use double-quotes (") in arguments' >&2
+ exit 1
+ ;;
+ *)
+ if [ $END_OF_ARGS -eq 0 ]; then
+ CMDARGS="${CMDARGS:+$CMDARGS }\"$arg\""
+ else
+ SCRIPTARGS="${SCRIPTARGS:+$SCRIPTARGS }--arg \"$arg\""
+ fi
+ ;;
+ esac
+done
+
+do_real_cmd()
+{
+ if [ $DO_NOTHING -eq 1 ]; then
+ echo "$ME: would run: $EXEC $CMDARGS"
+ exit 0
+ else
+ eval exec $EXEC "$CMDARGS"
+ fi
+}
+
+if [ $DO_NOTHING -eq 1 ]; then
+ echo "I: demo mode; $ME will not do anything due to --molly-guard-do-nothing." >&2
+fi
+
+if [ -n "${MOLLYGUARD_CMD:-}" ]; then
+ do_real_cmd
+fi
+
+MOLLYGUARD_CMD=$CMD; export MOLLYGUARD_CMD
+MOLLYGUARD_DO_NOTHING=$DO_NOTHING; export MOLLYGUARD_DO_NOTHING
+MOLLYGUARD_SETTINGS="@cfgdir@/rc"; export MOLLYGUARD_SETTINGS
+
+# pass through certain commands
+case "$CMD $CMDARGS" in
+ (*shutdown\ *-c*|*halt\ *-w*|*halt\ *-f*|*reboot\ *-f*)
+ # allow canceling shutdowns, only write wtmp and force immediate halt
+ echo "I: executing $CMD $CMDARGS regardless of check results." >&2
+ do_real_cmd
+ ;;
+esac
+
+for script in $(run-parts --test $SCRIPTSDIR); do
+ ret=0
+ eval $script $SCRIPTARGS || ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "W: aborting $CMD due to ${script##*/} exiting with code $ret." >&2
+ exit $ret
+ fi
+done
+
+do_real_cmd