239 lines
9.7 KiB
Bash
239 lines
9.7 KiB
Bash
#!/bin/bash
|
||
# SPDX-Version: 3.0
|
||
# SPDX-CreationInfo: 2025-05-05; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||
# 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.; <msw@coresecret.dev>
|
||
# SPDX-FileType: SOURCE
|
||
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||
# 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.02.512.2025.05.30"
|
||
|
||
### 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
|