#!/bin/sh
# Filename: forensic-mark-readonly
-# Purpose: force device to readonly mode when booting with bootoption forensic/readonly
+# Purpose: force block devices to read-only mode when booting with boot option read-only
# Authors: grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
# Bug-Reports: see http://grml.org/bugs/
# License: This file is licensed under the GPL v2 or any later version.
################################################################################
-# check for forensic/readonly bootoption
-if grep -qe forensic -qe readonly /proc/cmdline ; then
- # we get $DEVNAME via udev's environment
- if [ -n "$DEVNAME" ] ; then
- if [ "$(blockdev --getro $DEVNAME)" = "1" ] ; then
- logger "forensic mode: device $DEVNAME already set to readonly mode, nothing to do"
- else
- logger "forensic mode: setting $DEVNAME [$ID_SERIAL] to readonly"
- if blockdev --setro "$DEVNAME" ; then
- logger "|-> done; execute 'blockdev --setrw $DEVNAME' to unlock"
- else
- logger "|-> error while executing blockdev: $(blockdev --setro $DEVNAME 2>&1)"
- fi
- fi
- fi
+# check for read-only bootoption
+if ! grep -q read-only /proc/cmdline ; then
+ exit 0
+fi
+
+# see linux source -> Documentation/admin-guide/sysfs-rules.rst
+get_blockdev_dir() {
+ for dir in /sys/subsystem/block/ /sys/class/block/ /sys/block/ ; do
+ [ -d "${dir}" ] && echo "${dir}" && return
+ done
+}
+
+base() {
+ echo "${1##*/}"
+}
+
+dir() {
+ echo "${1%/*}"
+}
+
+is_ro() {
+ [ "$(blockdev --getro "$1")" = "1" ] && return 0 || return 1
+}
+
+if [ -z "${1:-}" ] ; then
+ echo "Error: usage: <$0> <blockdevice>" >&2
+ exit 1
+fi
+
+# accept /dev/foo from command line but also just "foo" from udev
+case "$1" in
+ /dev/*)
+ BLOCK_DEVICE="$1"
+ ;;
+ *)
+ BLOCK_DEVICE="/dev/$1"
+ ;;
+esac
+
+SYS_DIR="$(get_blockdev_dir)"
+
+# support configuration file
+if [ -r /etc/grml/forensic.conf ] ; then
+ READONLY_MODE=""
+ READONLY_IGNORE=""
+
+ . /etc/grml/forensic.conf
+
+ if [ "${READONLY_MODE:-}" = "disable" ] ; then
+ logger -t forensic-mark-readonly "not setting '${BLOCK_DEVICE}' to read-only as disabled via config"
+ exit 0
+ fi
+
+ if [ -n "${READONLY_IGNORE:-}" ] ; then
+ case ${READONLY_IGNORE:-} in
+ "${BLOCK_DEVICE}")
+ logger -t forensic-mark-readonly "not setting '${BLOCK_DEVICE}' to read-only as present in ignore list"
+ exit 0
+ ;;
+ esac
+ fi
+fi
+
+base_device=$(base "${BLOCK_DEVICE}")
+if [ -n "${SYS_DIR}" ] && [ -n "${base_device}" ] ; then
+ tmp_parent="${SYS_DIR}/*/${base_device}"
+ if [ -d "${tmp_parent}" ] ; then
+ parent_device=$(dir "${tmp_parent}")
+ parent_device=$(base "${parent_device}")
+ parent_device="/dev/${parent_device}"
+ fi
+ unset tmp_parent
+fi
+
+if is_ro "${BLOCK_DEVICE}" ; then
+ logger -t forensic-mark-readonly "device ${BLOCK_DEVICE} already set to read-only mode, nothing to do"
+elif [ -n "${parent_device}" ] && ! is_ro "${parent_device}" ; then
+ logger -t forensic-mark-readonly "parent device ${parent_device} is set read-write, not modifying"
+ logger -t forensic-mark-readonly "use blockdev --setro ${BLOCK_DEVICE} to set it manually"
+else
+ logger -t forensic-mark-readonly "setting ${BLOCK_DEVICE} [${ID_SERIAL}] to read-only"
+
+ if blockdev --setro "${BLOCK_DEVICE}" ; then
+ logger -t forensic-mark-readonly "|-> done; execute 'blockdev --setrw ${BLOCK_DEVICE}' to unlock"
+ else
+ logger -t forensic-mark-readonly "|-> error while executing blockdev: $(blockdev --setro "${BLOCK_DEVICE}" 2>&1)"
+ fi
fi
## END OF FILE #################################################################