#!/bin/bash # SPDX-Version: 3.0 # SPDX-CreationInfo: 2025-05-05; WEIDNER, Marc S.; # SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git # SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency # SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; # SPDX-FileType: SOURCE # SPDX-License-Identifier: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1 # SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework. # SPDX-PackageName: CISS.debian.live.builder # SPDX-Security-Contact: security@coresecret.eu declare -gr VERSION="Master V8.13.768.2025.12.06" ### VERY EARLY CHECK FOR DEBUGGING if [[ $* == *" --debug "* ]]; then declare -gr EARLY_DEBUG=true # Set a verbose PS4 prompt including timestamp, source, line, exit status and function name declare -gr PS4='\e[97m+\e[0m\e[96m$(date +%T.%4N)\e[0m\e[97m:\e[0m\e[92m[${BASH_SOURCE[0]}:${LINENO}]\e[0m\e[97m|\e[0m\e[93m$?\e[0m\e[97m>\e[0m\e[95m${FUNCNAME[0]:-main}()\e[0m \e[97m>>\e[0m ' # shellcheck disable=SC2155 declare -gr DEBUG_LOG="/tmp/ciss_live_builder_$$.log" # Generates empty DEBUG_LOG touch "${DEBUG_LOG}" && chmod 0600 "${DEBUG_LOG}" # Open file descriptor 42 for writing to the debug log exec 42>| "${DEBUG_LOG}" # Write Debug Log Header https://www.gnu.org/software/bash/manual/html_node/Bash-Variables { printf "\e[97m+\e[0m\e[92m%s: CISS.debian.live.builder Debug Log \e[0m\n" "$(date +%T.%4N)" printf "\e[97m+\e[0m\e[92m%s: Version : %s \e[0m\n" "$(date +%T.%4N)" "${VERSION}" printf "\e[97m+\e[0m\e[92m%s: Epoch : %s \e[0m\n" "$(date +%T.%4N)" "${EPOCHREALTIME}" printf "\e[97m+\e[0m\e[92m%s: Bash MAJ Release : %s \e[0m\n" "$(date +%T.%4N)" "${BASH_VERSINFO[0]}" printf "\e[97m+\e[0m\e[92m%s: Bash MIN Version : %s \e[0m\n" "$(date +%T.%4N)" "${BASH_VERSINFO[1]}" printf "\e[97m+\e[0m\e[92m%s: Bash Patch Level : %s \e[0m\n" "$(date +%T.%4N)" "${BASH_VERSINFO[2]}" printf "\e[97m+\e[0m\e[92m%s: Bash Build Version : %s \e[0m\n" "$(date +%T.%4N)" "${BASH_VERSINFO[3]}" printf "\e[97m+\e[0m\e[92m%s: Bash Release : %s \e[0m\n" "$(date +%T.%4N)" "${BASH_VERSINFO[4]}" printf "\e[97m+\e[0m\e[92m%s: UID : %s \e[0m\n" "$(date +%T.%4N)" "${UID}" printf "\e[97m+\e[0m\e[92m%s: EUID : %s \e[0m\n" "$(date +%T.%4N)" "${EUID}" printf "\e[97m+\e[0m\e[92m%s: Hostname : %s \e[0m\n" "$(date +%T.%4N)" "${HOSTNAME}" printf "\e[97m+\e[0m\e[92m%s: Script name : %s \e[0m\n" "$(date +%T.%4N)" "$0" printf "\e[97m+\e[0m\e[92m%s: Argument counter : %s \e[0m\n" "$(date +%T.%4N)" "$#" printf "\e[97m+\e[0m\e[92m%s: Argument string : %s \e[0m\n" "$(date +%T.%4N)" "$*" printf "\e[97m+\e[0m\e[92m%s: Script PID : %s \e[0m\n" "$(date +%T.%4N)" "$$" printf "\e[97m+\e[0m\e[92m%s: Script Parent PID : %s \e[0m\n" "$(date +%T.%4N)" "${PPID}" printf "\e[97m+\e[0m\e[92m%s: Script work DIR : %s \e[0m\n" "$(date +%T.%4N)" "${PWD}" printf "\e[97m+\e[0m\e[92m%s: Shell Options : %s \e[0m\n" "$(date +%T.%4N)" "$-" printf "\e[97m+\e[0m\e[92m%s: BASHOPTS : %s \e[0m\n" "$(date +%T.%4N)" "${BASHOPTS}" printf "\e[97m+\e[0m\e[92m%s: === Debug Log === : \e[0m\n" "$(date +%T.%4N)" } >&42 # Tell Bash to send xtrace output to FD 42 export BASH_XTRACEFD=42 # Enable inheritable shell options export SHELLOPTS # Turn on xtrace set -x else declare -gr EARLY_DEBUG=false fi ### Definition of error codes declare -gir ERR_NOT_USER_0=128 declare -gir ERR_UNSPPTBASH=255 ### Definition of error trap vars # declare -g errcode="" # = $? = $1 = ERRCODE # declare -g errscrt="" # = ${BASH_SOURCE[0]} = $2 = ERRSCRT # declare -g errline="" # = ${LINENO} = $3 = ERRLINE # declare -g errfunc="" # = ${FUNCNAME[0]:-main} = $4 = ERRFUNC # declare -g errcmmd="" # = ${$BASH_COMMAND} = $5 = ERRCMMD ### Preliminary vars declaration declare -gr argument_count="$#" declare -gr argument_string="$*" ### Preliminary checks [[ ${EUID} -ne 0 ]] \ && printf "\e[91m❌ Please make sure you are 'root'! Bye... \e[0m\n" >&2 && exit "${ERR_NOT_USER_0}" [[ -z ${BASH_VERSINFO[0]} ]] \ && printf "\e[91m❌ Please make sure you are using 'bash'! Bye... \e[0m\n" >&2 && exit "${ERR_UNSPPTBASH}" [[ $(kill -l | grep -c SIG) -eq 0 ]] \ && printf "\e[91m❌ Please make sure you are calling the script without leading 'sh'! Bye... \e[0m\n" >&2 && exit "${ERR_UNSPPTBASH}" [[ ${BASH_VERSINFO[0]} -lt 5 ]] \ && printf "\e[91m❌ Minimum requirement is bash 5.1. You are using '%s'! Bye... \e[0m\n" "${BASH_VERSION}" >&2 && exit "${ERR_UNSPPTBASH}" [[ ${BASH_VERSINFO[0]} -le 5 ]] && [[ ${BASH_VERSINFO[1]} -le 1 ]] \ && printf "\e[91m❌ Minimum requirement is bash 5.1. You are using '%s'! Bye... \e[0m\n" "${BASH_VERSION}" >&2 && exit "${ERR_UNSPPTBASH}" ### For all options see https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin set -o errexit # Exit script when a command exits with non-zero status, the same as "set -e". set -o nounset # Exit script on use of an undefined variable, the same as "set -u". set -o pipefail # Makes pipelines return the exit status of the last command in the pipe that failed. set -o noclobber # Prevent overwriting, the same as "set -C". ####################################### # Trap function to be called on 'ERR'. # Globals: # DEBUG_LOG # EARLY_DEBUG # VERSION # argument_count # argument_string # Arguments: # $1: $? # $2: ${BASH_SOURCE[0]} # $3: ${LINENO} # $4: ${FUNCNAME[0]:-main} # $5: ${BASH_COMMAND} ####################################### # shellcheck disable=SC2317 trap_on_err() { declare -r errcode="$1" declare -r errscrt="$2" declare -r errline="$3" declare -r errfunc="$4" declare -r errcmmd="$5" trap - ERR if [[ "${errcode}" -ne 127 ]]; then printf "\e[91m❌ Hash Generation Process failed.\e[0m\n" >&2 printf "\e[91m❌ Version : '%s' \e[0m\n" "${VERSION}" >&2 printf "\e[91m❌ Error : '%s' \e[0m\n" "${errcode}" >&2 printf "\e[91m❌ Line : '%s' \e[0m\n" "${errline}" >&2 printf "\e[91m❌ Script : '%s' \e[0m\n" "${errscrt}" >&2 printf "\e[91m❌ Function : '%s' \e[0m\n" "${errfunc}" >&2 printf "\e[91m❌ Command : '%s' \e[0m\n" "${errcmmd}" >&2 printf "\e[91m❌ Arguments # : '%s' \e[0m\n" "${argument_count}" >&2 printf "\e[91m❌ Arguments : '%s' \e[0m\n" "${argument_string}" >&2 if "${EARLY_DEBUG}"; then printf "\e[91m❌ Debug Log : '%s' \e[0m\n" "${DEBUG_LOG}" >&2 printf "\e[91m❌ cat %s \e[0m\n" "${DEBUG_LOG}" >&2 fi printf "\n" fi } trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR ### Initialization # shellcheck disable=SC2155 declare -gr SCRIPT_FULLPATH="$(readlink -f "${BASH_SOURCE[0]:-$0}")" # shellcheck disable=SC2155 declare -gr WORK_DIR="$(dirname "${SCRIPT_FULLPATH}")" declare -gr BASE_DIR="${WORK_DIR%/.iso}" declare -gr CFG_DIR="${BASE_DIR}/.cfg" declare -gr PRES_FILE="${BASE_DIR}/preseed.cfg" declare -gr HASH_FILE="${CFG_DIR}/md5sum.txt" declare -ga hashes=() # shellcheck disable=SC2188 >| "${HASH_FILE}" ####################################### # Generator for md5 Hashes # Globals: # CFG_DIR # HASH_FILE # hash # hashes # Arguments: # None ####################################### gen_hash() { # Enable nullglob so that non-matching patterns expand to nothing shopt -s nullglob declare file declare filename # Loop over all *.cfg files in CFG_DIR for file in "${CFG_DIR}"/*.cfg; do # Only process if it's a regular file if [[ -f "${file}" ]]; then # Calculate md5 hash (only the hash value) hash=$(md5sum "${file}" | awk '{ print $1 }') # Extract the filename without a path filename=${file##*/} # Append "hash filename" to HASH_FILE echo "${hash} ${filename}" >> "${HASH_FILE}" # Add hash to array hashes+=("${hash}") fi done } gen_hash { declare in_hash_block=false declare outer_line declare hash while IFS= read -r outer_line; do # Check if a line contains "#BOH" and start the hash insertion block if [[ ${outer_line} == "#BOH" ]]; then echo "${outer_line}" # shellcheck disable=SC1003 echo 'd-i preseed/include/checksum string \' # Add all new hashes from the array "hashes" except the last one for ((i = 0; i < ${#hashes[@]} - 1; i++)); do hash="${hashes[i]}" echo "${hash} \\" done # Output the last hash without the trailing backslash. echo "${hashes[@]: -1}" # Set the flag for the hash block to "true". in_hash_block=true continue fi # Check if the line "#EOH" has been reached to end the hash block. if [[ ${outer_line} == "#EOH" && ${in_hash_block} == true ]]; then echo "${outer_line}" in_hash_block=false continue fi # Skip lines within the hash block (old hashes and d-i line). if [[ ${in_hash_block} == true ]]; then # Skip the line "d-i preseed/include/checksum string". if [[ ${outer_line} =~ ^d-i\ preseed/include/checksum\ string ]]; then continue fi # Skip lines with old hashes. if [[ ${outer_line} =~ [a-f0-9]{32} ]]; then continue fi fi # Leave all other rows unchanged. echo "${outer_line}" done < "${PRES_FILE}" } >| "${PRES_FILE}.tmp" mv -f "${PRES_FILE}.tmp" "${PRES_FILE}" sed -i ':a;N;/\n#EOH/!ba;s/\(\n\)\+\(#EOH\)/\n#EOH/' "${PRES_FILE}" sed -i '$d' "$PRES_FILE" echo "# Written by: $0 Version: ${VERSION} at: $(date +%T.%4N)" >> "${PRES_FILE}" printf "\e[92m✅ '%s' Process successful.\e[0m\n" "${0}" exit 0 # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh