From a100257d960edf1c8e9cd11e8b73442f078ecdba Mon Sep 17 00:00:00 2001 From: "Gerd v. Egidy" Date: Sun, 27 Mar 2022 14:07:38 +0000 Subject: [PATCH] Add script and config.yaml parameter for late-loading of SystemRescueModules --- ChangeLog | 1 + .../systemd/scripts/sysrescue-initialize.py | 12 + airootfs/usr/bin/sysrescue-configuration.lua | 1 + airootfs/usr/share/sysrescue/bin/load-srm | 263 ++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100755 airootfs/usr/share/sysrescue/bin/load-srm diff --git a/ChangeLog b/ChangeLog index 8436f83..b4b58e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ SystemRescue ChangeLog ------------------------------------------------------------------------------- 9.02 (YYYY-MM-DD): ------------------------------------------------------------------------------- +* Add script and config.yaml parameter for late-loading of SystemRescueModules (SRM) (Gerd v. Egidy) * Fix the type of the default definition of parameter "ar_attempts" (#266) * Added scripts and documentation to help build the ISO image in a docker container * Reduce compression ratio for initramfs on i686 to prevent a crash at build time (#261) diff --git a/airootfs/etc/systemd/scripts/sysrescue-initialize.py b/airootfs/etc/systemd/scripts/sysrescue-initialize.py index 187f1b4..aa51139 100755 --- a/airootfs/etc/systemd/scripts/sysrescue-initialize.py +++ b/airootfs/etc/systemd/scripts/sysrescue-initialize.py @@ -38,6 +38,7 @@ print(f"config['global']['nofirewall']={config['global']['nofirewall']}") print(f"config['global']['dostartx']={config['global']['dostartx']}") print(f"config['global']['noautologin']={config['global']['noautologin']}") print(f"config['global']['dovnc']={config['global']['dovnc']}") +print(f"config['global']['late_load_srm']={config['global']['late_load_srm']}") # ============================================================================== # Apply the effective configuration @@ -151,6 +152,17 @@ if config['sysconfig']['ca-trust']: print(f"Updating CA trust configuration ...") p = subprocess.run(["update-ca-trust"], text=True) +# ============================================================================== +# late-load a SystemRescueModule (SRM) +# ============================================================================== + +late_load_srm = config['global']['late_load_srm'] +if (late_load_srm != None) and (late_load_srm != ""): + print(f"====> Late-loading SystemRescueModule (SRM) ...") + p = subprocess.run(["/usr/share/sysrescue/bin/load-srm", late_load_srm], text=True) + # the SRM could contain changes to systemd units -> let them take effect + p = subprocess.run(["/usr/bin/systemctl", "daemon-reload"], text=True) + # ============================================================================== # End of the script # ============================================================================== diff --git a/airootfs/usr/bin/sysrescue-configuration.lua b/airootfs/usr/bin/sysrescue-configuration.lua index e76d9c0..22ae7ad 100755 --- a/airootfs/usr/bin/sysrescue-configuration.lua +++ b/airootfs/usr/bin/sysrescue-configuration.lua @@ -161,6 +161,7 @@ config = { ['copytoram'] = false, ['checksum'] = false, ['loadsrm'] = false, + ['late_load_srm'] = "", ['dostartx'] = false, ['dovnc'] = false, ['noautologin'] = false, diff --git a/airootfs/usr/share/sysrescue/bin/load-srm b/airootfs/usr/share/sysrescue/bin/load-srm new file mode 100755 index 0000000..81ca393 --- /dev/null +++ b/airootfs/usr/share/sysrescue/bin/load-srm @@ -0,0 +1,263 @@ +#! /usr/bin/env bash +# +# load-srm - late-load a SystemRescueModule (SRM) by copying it's content onto the Copy-on-Write (CoW) space +# +# Author: Gerd v. Egidy +# SPDX-License-Identifier: GPL-3.0-or-later +# +# see https://www.system-rescue.org/Modules/ for details + +# bash-checks right at the top due to many bashisms in the rest of the script +if [ -n "$POSIXLY_CORRECT" ] || [ -z "$BASH_VERSION" ]; then + echo "ERROR: bash >= 4.0 is required for this script." + exit 1 +fi + +if (( BASH_VERSINFO[0]*100 + BASH_VERSINFO[1] < 400 )); then + echo "ERROR: bash >= 4.0 is required for this script." + exit 1 +fi + +# abort on failures +set -o errexit -o pipefail -o noclobber -o nounset + +MOUNTPOINT="/run/archiso/load-srm" + +print_help() +{ + echo "load-srm - late-load a SystemRescueModule (SRM)" + echo " by copying it's content onto the Copy-on-Write (CoW) space" + echo "" + echo "Usage:" + echo "load-srm [-v|--verbose] [-i|--insecure] " + echo "" + echo " Either a path to the SRM or a URL to download it from." + echo " Supports http:// and https:// URLs." + echo "" + echo "--insecure Ignore TLS errors like wrong certificate when using HTTPS." + echo " Not recommended to use unless you know what you are doing." + echo "--verbose Output progress and details about each step." + echo "" + echo "See https://www.system-rescue.org/Modules/ for details." + + return +} + +# error while parsing commandline parameters +argument_error() +{ + echo "$1" + echo + echo "---------------------------------" + echo + print_help + exit 2 +} + +do_cleanup() +{ + # cleanups necessary for ending + + if findmnt --mountpoint "$MOUNTPOINT" >/dev/null 2>&1; then + umount "$MOUNTPOINT" || true + [[ $VERBOSE -eq 1 ]] && echo "squashfs unmounted" + fi + + if [[ -n "${TMPDIR:-}" ]]; then + rm -rf "${TMPDIR}" || true + [[ $VERBOSE -eq 1 ]] && echo "tmpdir removed" + fi + + return 0 +} + +# an error occured after argument parsing +error_exit() +{ + do_cleanup + + echo "ERROR: $1" + exit $2 +} + +parse_args() +{ + # adapted from https://stackoverflow.com/a/29754866 by Robert Siemer + # version edited Mar 4 '21 at 0:11, licensed under CC BY-SA 4.0 due to Stackoverflow Terms of Service + # https://creativecommons.org/licenses/by-sa/4.0/ + + # show help when no arguments given + [[ $# -eq 0 ]] && { print_help ; exit 0 ; } + + # -allow a command to fail with !’s side effect on errexit + # -use return value from ${PIPESTATUS[0]}, because ! hosed $? + ! getopt --test > /dev/null + if [[ ${PIPESTATUS[0]} -ne 4 ]]; then + echo 'ERROR: `getopt --test` failed in this environment' + exit 1 + fi + + local OPTIONS="ivh" + local LONGOPTS="insecure,verbose,help" + + # option variables as globals, set to default values + declare -g INSECURE=0 + declare -g VERBOSE=0 + declare -g URL="" + declare -g URL_PROTO="" + + # -regarding ! and PIPESTATUS see above + # -temporarily store output to be able to check for errors + # -activate quoting/enhanced mode (e.g. by writing out “--options”) + # -pass arguments only via -- "$@" to separate them correctly + ! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") + if [[ ${PIPESTATUS[0]} -ne 0 ]]; then + # e.g. return value is 1 + # then getopt has complained about wrong arguments to stdout + echo + print_help + exit 2 + fi + # read getopt’s output this way to handle the quoting right: + eval set -- "$PARSED" + + while true; do + case "$1" in + -i|--insecure) + INSECURE=1 + shift + ;; + -v|--verbose) + VERBOSE=1 + shift + ;; + -h|--help) + print_help + exit 0 + ;; + --) + shift + break + ;; + *) + echo "ERROR: Argument parsing logic bug" + exit 2 + ;; + esac + done + + # one positional argument required: the URL + [[ $# -ne 1 ]] && argument_error "ERROR: URL missing" + URL=$1 + + # basic check for the URL parameter + if [[ $URL =~ ^[a-z0-9]+://.+ ]]; then + # we have a URI style parameter + + if [[ $URL =~ ^http://.+ ]]; then + URL_PROTO="http" + return 0 + elif [[ $URL =~ ^https://.+ ]]; then + URL_PROTO="https" + return 0 + fi + + argument_error "ERROR: invalid URL or unsupported protocol" + + elif [[ -f "$URL" ]]; then + URL_PROTO="file" + return 0 + fi + + argument_error "ERROR: can't find file" + + return 0 +} + +mount_srm() +{ + local srm_path=$1 + + # first test if we really have a valid squashfs file + if ! unsquashfs -l "$srm_path" >/dev/null 2>&1; then + error_exit "file not a valid squashfs file" 100 + fi + [[ $VERBOSE -eq 1 ]] && echo "squashfs file verified $srm_path" + + # prepare mount + if ! [[ -d "$MOUNTPOINT" ]]; then + mkdir "$MOUNTPOINT" + elif findmnt --mountpoint "$MOUNTPOINT" >/dev/null 2>&1; then + error_exit "$MOUNTPOINT already mounted" 101 + fi + + if ! mount -t squashfs "$srm_path" "$MOUNTPOINT"; then + error_exit "can't mount squashfs file" 102 + fi + + [[ $VERBOSE -eq 1 ]] && echo "squashfs successfully mounted to $MOUNTPOINT" + + return 0 +} + +rsync_to_cow() +{ + # dry-run first, we want to find any problems before beginning the actual sync + if ! rsync -a --sparse --checksum --quiet --dry-run "$MOUNTPOINT/" "/"; then + error_exit "problem while testing to copy the SRM content" 103 + fi + + local param="--quiet" + [[ $VERBOSE -eq 1 ]] && param="--progress" + + if ! rsync -a --sparse --checksum $param "$MOUNTPOINT/" "/"; then + error_exit "problem copying the SRM content" 104 + fi + + [[ $VERBOSE -eq 1 ]] && echo "files copied successfully" + + return 0 +} + +curl_download() +{ + # first create a tmpdir we use to download the srm to + # use tmpfs (and not the CoW space) because we want to fully remove it afterwards + declare -g TMPDIR + if ! TMPDIR=$(mktemp --directory --tmpdir="/tmp" "load-srm.XXXXXXXXXX"); then + error_exit "can't create tmpdir" 3 + fi + + local curl_param + [[ $VERBOSE -eq 0 ]] && curl_param="--show-error --silent" + [[ $VERBOSE -eq 1 ]] && curl_param="--progress-meter" + [[ $INSECURE -eq 1 ]] && curl_param="$curl_param --insecure" + + if ! curl --output "$TMPDIR/srm" --fail --location --max-redirs 10 \ + --retry-connrefused --retry 2 --retry-delay 3 $curl_param "$URL"; then + error_exit "error downloading SRM" 4 + fi + + [[ $VERBOSE -eq 1 ]] && echo "file downloaded successfully" + + return 0 +} + +################################# +# execution begins here + +parse_args "$@" + +[[ $VERBOSE -eq 1 ]] && echo "URL/path: $URL" + +if [[ $URL_PROTO == "http" ]] || [[ $URL_PROTO == "https" ]]; then + curl_download + # replace the URL parameter with the location we downloaded the file to + URL="$TMPDIR/srm" +fi + +mount_srm "$URL" +rsync_to_cow +do_cleanup + +exit 0