#!/bin/bash # Copyright 2021 Stuart Winter, Donostia, Spain. # All rights reserved. # # Redistribution and use of this script, with or without modification, is # permitted provided that the following conditions are met: # # 1. Redistributions of this script must retain the above copyright # notice, this list of conditions and the following disclaimer. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ################################################################################### # Program: /usr/sbin/os-initrd-mgr # Purpose: Manage the Slackware ARM / AArch64 OS InitRD. # Author : Stuart Winter # Date...: 20-Sep-2021 # Version: 1.02 ################################################################################### # Changelog: # v1.02 - 20-Sep-2021 # * Support /etc/mdadm.conf # v1.01 - 18-Aug-2021 # * Added -F/--force-rebuild to enable easy removal of local customisations. # If the Slackware ARM Kernel Module Loader local customisation files aren't # present within /boot/local, remove them from the OS InitRD. # v1.00 - 20-May-2021 ################################################################################### # Todo: # Automatically detect whether the mdadm.conf and other customisations should be # updated/removed using a file hash. # Perhaps /boot/.customisation_hashes # For mdadm.conf it require extra handling though - don't include it if the file # is 100% comments. # Logic: # If mdadm.conf is within the OS InitRD but is absent within /etc, or copy in # /etc/ is pure comments: # remove from OS InitRD, remove entry from hash file. # # If mdadm.conf present within OS InitRD and /etc/, but has different hash: # re-include version from /etc, update entry in hash file. # # If mdadm.conf absent within OS InitRD, but present in /etc and isn't pure comments: # include within OS InitRD and add entry to hash file. # # At present /etc/mdadm.conf is only re-included or removed if local customisations # are found, or if -F was supplied. # This means that any /etc/mdadm.conf may be skipped during the Kernel package # upgrade process. # However, this is low priority since init tries to set up Software RAID by itself. ################################################################################### # Version PROGNAME=os-initrd-mgr VERSION="${PROGNAME} v1.02 by Stuart Winter " # Settings: BOOTDIR=/boot INITRDCUSTOMISATIONSDIR=$BOOTDIR/local INITRDDETAILS=$BOOTDIR/.boot_details QUIETMODE=No FORCEREBUILD=No # Kernel Module Loader customisation files: KMODLOADCUSTS="load_kernel_modules.pre load_kernel_modules.pre-modload \ load_kernel_modules.post" # Possible customisations (configs and scripts) that the user may # place within /boot/local for reincorporation into the OS InitRD: CUSTOMISATIONS="rootdev rootfs wait-for-root resumedev luksdev lukstrim \ lukskey keymap initrd-name \ $KMODLOADCUSTS" # Test if getopt is available. It's not available within the Slackware Installer # which is fine, since there's no need to run this tool during the initial # installation of the Kernel package. [ ! -x /bin/getopt ] && exit 0 # Temporary location into which the OS InitRD will be unpacked: TMPDIR="$( mktemp -d /tmp/os-initrd-mgr.XXXXXX )" # Exit status: # 0 if OK # 1 any error. There is no requirement to surface different codes # as os-initrd-mgr is not designed to be called by any # tool that will handle the effects of this tool in any # manner. ############################## Functions################################### function display_usage () { printf "Usage: ${PROGNAME} [options]\n" printf "By default, ${PROGNAME} will scan for any local additions\n" printf "within $INITRDCUSTOMISATIONSDIR and will reincorporate them within\n" printf "the OS Initial RAM Disk." if [ ! -z "$1" ]; then echo "Use $( basename $0 ) --help for a list of options" fi } function display_help() { printf "${VERSION}\n\n$( display_usage ) Main options: -q, --quiet Surpress output messages if there are no user customisations within /boot/local. This option is used by the kernel package's post installation script to surpress any messages attached to inaction on the part of this tool, with the intention of only supplying informative messages should any actions need to be taken. -F, --force-rebuild Force rebuilding of the OS InitRD even when no local customisations are found. -h, --help Output this help text. -v, --version Display version information. " } function cleanup() { echo "Cleaning up ..." rm -rf $TMPDIR } function unpackinitrd() { local initrdfile="$1" if [ -s $initrdfile ]; then cd $TMPDIR echo "Unpacking $initrdfile ..." zcat $initrdfile | cpio --quiet -di return $? else echo "Error: $initrdfile does not exist or is of zero bytes." return 1 fi } # In theory we shouldn't have any issues repacking the initrd # (at least from a storage capacity perspective) because we're # unpacking outside of /boot, and we're only adding scripts to the # initrd, and we're repacking in place. function packinitrd() { local found_customisations=$1 local initrdfile="$2" local bootdetailsfile="$3" local bootcustomisationsdir="$4" local initrdsize local customisation cd $TMPDIR #printf "Adding customisation script:" # There may be no customisations if --force-rebuild was set. # Handle all customisations - Kernel Module Loader and initrd config files: if [ $found_customisations -eq 1 ]; then printf "Adding customisations ...\n" for customisation in $CUSTOMISATIONS ; do if [ -f $bootcustomisationsdir/$customisation ]; then #printf " $customisation" install -pm644 $bootcustomisationsdir/$customisation . # config lives in the OS InitRD's root directory. fi done fi # Handle the case where there are Kernel Module Loader customisation # scripts within the unpacked initrd, but not present within the OS' /boot/local # This indicates that the user wants to remove them, and will have supplied # the -F option to os-initrd-mgr # Our PWD is presently the root of the OS InitRD: # TOFIX: Note: we cannot remove the initrd customisations because /sbin/init # performs no sanity checking on the presence of those files. # This requires a patch to be merged upstream, but should be simple. for customisation in $KMODLOADCUSTS ; do if [ -f $customisation -a ! -f $bootcustomisationsdir/$customisation ]; then printf "Removing customisation script from the OS InitRD: $customisation\n" rm -f $customisation fi done # Include RAID support in initrd # Note: Slackware ARM/AArch64 OS InitRD ships /etc/mdadm.conf by default # because the mkinitrd tool packages it plus the binaries and udev rule. if [ -s /etc/mdadm.conf ] ; then # By default Slackware ships a fully commented mdadm.conf, so # before copying it to the OS InitRD, we'll check if it's a functional # config: if egrep -qv '^#' /etc/mdadm.conf ; then printf "Installing /etc/mdadm.conf\n" cp -fa /etc/mdadm.conf etc/ fi else # /etc/mdadm.conf is managed within the OS. If that file is absent yet there # is a copy within the OS InitRD, this indicates RAID support is no longer # required. if [ -s etc/mdadm.conf ]; then printf "/etc/mdadm.conf no longer present, removing from the OS InitRD\n" rm -f etc/mdadm.conf fi fi printf "Repacking $initrdfile ...\n" initrdsize=$( du -sb . | awk '{print $1}' ) # Update the size information: sed -i 's?^initrdsize=.*?initrdsize='"$initrdsize"'?g' $bootdetailsfile # Pack: find . | cpio --quiet -o -H newc | gzip -9f > $initrdfile return $? } function preallocate() { local tmpdir=$1 local size=$2 local exitval mkdir -p $tmpdir fallocate -l $size $tmpdir/testfile-$size > /dev/null 2>&1 exitval=$? rm -f $tmpdir/testfile-$size return $exitval } ############################################################################### # Trap errors and clean up: trap cleanup 1 2 14 15 # trap CTRL+C and kill PARAMS="$( getopt -qn "$( basename $0 )" -o h,q,v,F -l help,quiet,version,force-rebuild -- "$@" )" # If params are incorrect then if [ $? -gt 0 ]; then display_help ; exit 2 ; fi eval set -- "${PARAMS}" for param in $*; do case "$param" in -q|--quiet) QUIETMODE=Yes shift 1;; -F|--force-rebuild) FORCEREBUILD=Yes shift 1;; -h|--help) display_help ; exit ;; -v|--version) printf "${VERSION}\n" ; exit;; --) shift; break;; esac done # Check if we have the boot details. We need these to # determine whether we can safely unpack the OS Init RD: # I may add this to the scope of the --force-rebuild option here at some point. if [ ! -s $INITRDDETAILS ]; then echo "Error: unable to locate details file $INITRDDETAILS" echo " You may need to reinstall the kernel package." exit 1 fi # Load in the details file: . $INITRDDETAILS || exit 1 # We'll detect the platform now, but it should also be included within # /boot/.boot_details if [ -z "$platform" ]; then case "$( uname -m )" in arm*) platform="armv7";; aarch64) platform="armv8";; i?86) platform="x86";; *) platform=$( uname -m );; esac fi # Versionless symlink to the OS InitRD: # On ARM / AArch64 the file name is /boot/initrd-armv{7,8} OSINITRDFILE=$BOOTDIR/initrd-$platform # Check if there are any local customisations: found_customisations=0 [ "$QUIETMODE" = "No" ] && printf "Searching for local customisations ... " for customisation in $CUSTOMISATIONS ; do if [ -f $INITRDCUSTOMISATIONSDIR/$customisation ]; then [ $found_customisations = 0 ] && printf "\n" #[ "$QUIETMODE" = "No" ] && printf "Found: $INITRDCUSTOMISATIONSDIR/$customisation\n" printf "Found: $INITRDCUSTOMISATIONSDIR/$customisation\n" found_customisations=1 fi done if [ $found_customisations -eq 0 -a "$FORCEREBUILD" = "No" ]; then [ "$QUIETMODE" = "No" ] && printf " none found, quitting.\n" cleanup > /dev/null # It's not an error not to have local customisations, it just means # that this script has no actions to take by default. exit 0 else printf "\n" fi # initrdsize is set within the boot details file (the file name is # set within the $INITRDDETAILS variable). # preallocate $TMPDIR $initrdsize if [ $? -gt 0 ]; then echo "Error: Insufficient temporary storage capacity to extract" echo " the OS Init RD ($initrdsize bytes required)" cleanup > /dev/null exit 1 fi unpackinitrd $OSINITRDFILE $INITRDDETAILS if [ $? -gt 0 ]; then echo "Error: Unable to successfully unpack the OS InitRD to" echo " temporary storage" echo " See the error messages above and take corrective" echo " action." cleanup > /dev/null exit 1 fi packinitrd $found_customisations $OSINITRDFILE $INITRDDETAILS $INITRDCUSTOMISATIONSDIR if [ $? -gt 0 ]; then echo "Warning: The OS InitRD may be corrupt." echo " You may need to ensure that there is adequate storage" echo " ($initrdsize bytes) within $BOOTDIR and reinstall the" echo " kernel package." cleanup exit 1 else echo "Successfully rebuilt the OS InitRD." cleanup > /dev/null exit 0 fi