Files
CISS.debian.live.builder/lib/lib_arg_parser.sh
2025-06-02 22:11:13 +02:00

437 lines
16 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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: 20242025; 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
#######################################
# Argument Parser
# Globals:
# BUILD_LOG
# DEBUG
# EARLY_DEBUG
# ERR_CONTROL_CT
# ERR_MISS_PWD_F
# ERR_MISS_PWD_P
# ERR_OWNS_PWD_F
# ERR_PASS_LENGH
# ERR_PASS_PLICY
# ERR_REIONICE_P
# ERR_REIO_C_VAL
# ERR_REIO_P_VAL
# ERR_RENICE_PRI
# ERR_RGHT_PWD_F
# ERR_SPLASH_PNG
# ERR_UNCRITICAL
# ERR__SSH__PORT
# handler_architecture
# HANDLER_BUILD_DIR
# HANDLER_CDI
# HANDLER_DHCP
# VAR_HANDLER_ISO_COUNTER
# HANDLER_PRIORITY
# HANDLER_SPLASH
# HANDLER_SSHPORT
# HANDLER_SSHPUBKEY
# HANDLER_STA
# HASHED_PWD
# ISO8601
# REIONICE_CLASS
# REIONICE_PRIORITY
# VAR_VERSION
# handler_jumphost
# Arguments:
# None
#######################################
#######################################
# description
# Globals:
# ARY_HANDLER_JUMPHOST
# ARY_HANDLER_NETCUP_IPV6
# ERR_ARG_MSMTCH
# ERR_CONTROL_CT
# ERR_MISS_PWD_F
# ERR_MISS_PWD_P
# ERR_OWNS_PWD_F
# ERR_PASS_LENGH
# ERR_PASS_PLICY
# ERR_REIONICE_P
# ERR_REIO_C_VAL
# ERR_REIO_P_VAL
# ERR_RENICE_PRI
# ERR_RGHT_PWD_F
# ERR_SPLASH_PNG
# ERR_UNCRITICAL
# ERR__SSH__PORT
# VAR_ARCHITECTURE
# VAR_BUILD_LOG
# VAR_EARLY_DEBUG
# VAR_HANDLER_BUILD_DIR
# VAR_HANDLER_CDI
# VAR_HANDLER_DHCP
# VAR_HANDLER_ISO_COUNTER
# VAR_HANDLER_NETCUP_IPV6
# VAR_HANDLER_PRIORITY
# VAR_HANDLER_SPLASH
# VAR_HANDLER_STA
# VAR_HASHED_PWD
# VAR_ISO8601
# VAR_REIONICE_CLASS
# VAR_REIONICE_PRIORITY
# VAR_SSHPORT
# VAR_SSHPUBKEY
# Arguments:
# None
#######################################
arg_parser() {
while [[ $# -gt 0 ]]; do
declare argument="${1}"
case "${argument,,}" in
-a=* | --autobuild=*)
shift 1
;;
-c | --contact)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --contact MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
shift 1
;;
-h | --help)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --help MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
shift 1
;;
-v | --version)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --version MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
shift 1
;;
--architecture)
if [[ "${2}" == "amd64" || "${2}" == "arm64" ]]; then
declare -gx VAR_ARCHITECTURE="${2}"
shift 2
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --architecture MUST be 'amd64' or 'arm64'.\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_UNCRITICAL}"
fi
;;
--build-directory)
declare -gx VAR_HANDLER_BUILD_DIR="${2}"
if [[ ! "${VAR_HANDLER_BUILD_DIR}" =~ ^/ ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --build-directory MUST be an absolute path. Got: '%s'\n" "${VAR_HANDLER_BUILD_DIR}" >&2
exit "${ERR_NOTABSPATH}"
fi
declare -gx VAR_BUILD_LOG="${VAR_HANDLER_BUILD_DIR}/${VAR_ISO8601}_build.log"
shift 2
;;
--cdi)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --cdi MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
declare -g VAR_HANDLER_CDI=true
shift 1
;;
--change-splash )
if [[ "${2}" == "club" || "${2}" == "hexagon" ]]; then
declare -g VAR_HANDLER_SPLASH="${2}"
shift 2
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --change-splash MUST be 'club' or 'hexagon'.\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_SPLASH_PNG}"
fi
;;
--control)
if [[ -n "${2}" ]]; then
declare -g VAR_HANDLER_ISO_COUNTER="${2}"
shift 2
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --control MUST be provided with a Parameter.\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_CONTROL_CT}"
fi
;;
--debug)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --debug MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
shift 1
;;
--dhcp-centurion)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --dhcp-centurion MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
declare -gi VAR_HANDLER_DHCP=1
shift 1
;;
--jump-host)
if [[ -n "${2}" && "${2}" != -* ]]; then
declare -i count=0
shift
while [[ "${#}" -gt 0 && "${1}" != -* && count -lt 10 ]]; do
declare -g ARY_HANDLER_JUMPHOST+=("$1")
count=$((count + 1))
shift
done
while [[ "${#}" -gt 0 && "${1}" != -* ]]; do
shift
done
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --jump-host MUST contain one or up to ten IPs.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
;;
--log-statistics-only)
if [[ -n "${2}" && "${2}" != -* ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --log-statistics-only MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
declare -gi VAR_HANDLER_STA=1
shift 1
;;
--provider-netcup-ipv6)
if [[ -n "${2}" && "${2}" != -* ]]; then
declare -i count=0
declare -g VAR_HANDLER_NETCUP_IPV6=true
shift
while [[ "${#}" -gt 0 && "${1}" != -* && count -lt 1 ]]; do
declare cleaned="${1//[\[\]]/}"
declare -g ARY_HANDLER_NETCUP_IPV6+=("${cleaned}")
count=$((count + 1))
shift
done
while [[ "${#}" -gt 0 && "${1}" != -* ]]; do
shift
done
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --provider-netcup-ipv6 MUST provide one IPv6.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
;;
--renice-priority)
if [[ -n ${2} && ${2} =~ ^-?[0-9]+$ && ${2} -ge -19 && ${2} -le 19 ]]; then
declare -gi VAR_HANDLER_PRIORITY="$2"
shift 2
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --renice-priority MUST an integer between '-19' and '19'.\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_RENICE_PRI}"
fi
;;
--reionice-priority)
if [[ -z "${2}" ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --reionice-priority no values provided.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_REIONICE_P}"
else
if [[ "${2}" =~ ^[1-3]$ ]]; then
declare -gi VAR_REIONICE_CLASS="${2}"
if [[ -z "${3}" ]]; then
:
else
if [[ "${3}" =~ ^[0-7]$ ]]; then
declare -gi VAR_REIONICE_PRIORITY="${3}"
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --reionice-priority PRIORITY MUST be an integer between '0' and '7'.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_REIO_P_VAL}"
fi
fi
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --reionice-priority CLASS MUST be an integer between '1' and '3'.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_REIO_C_VAL}"
fi
fi
if [[ -n ${VAR_REIONICE_PRIORITY} ]]; then
shift 3
else
shift 2
fi
;;
--root-password-file)
declare pw_file="${2}"
if [[ -z "${pw_file}" ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file missing password file path argument.\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_MISS_PWD_P}"
fi
if [[ ! -f "${pw_file}" ]]; then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file password file '%s' does not exist.\e[0m\n" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_MISS_PWD_F}"
fi
declare owner
owner=$(stat -c '%U:%G' "${pw_file}")
if [[ "${owner}" != "root:root" ]]; then
chown root:root "${pw_file}" || {
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file failed to set owner root:root on '%s'.\e[0m\n" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_OWNS_PWD_F}"
}
fi
declare perms
perms=$(stat -c '%a' "${pw_file}")
if [[ "${perms}" -ne 400 ]]; then
chmod 400 "${pw_file}" || {
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file failed to set permissions 0400 on '%s'.\e[0m\n" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_RGHT_PWD_F}"
}
fi
declare plaintext_pw
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
if ! IFS= read -r plaintext_pw < "${pw_file}"; then
:
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare pw_length
pw_length=${#plaintext_pw}
if (( pw_length < 20 || pw_length > 64 )); then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file password MUST be between 20 and 64 characters (got %d).\e[0m\n" "${pw_length}" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_PASS_LENGH}"
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
if [[ "${plaintext_pw}" == *\"* ]]; then
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file password MUST NOT contain double quotes (\").\e[0m\n" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_PASS_PLICY}"
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare salt
set +o pipefail
while :; do
salt=$(tr -dc 'A-Za-z0-9' </dev/random | head -c 16)
[[ ${#salt} -eq 16 ]] && break
done
set -o pipefail
declare hash_temp
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
hash_temp=$(mkpasswd --method=sha-512 --salt="${salt}" --rounds=8388608 "${plaintext_pw}")
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare -g VAR_HASHED_PWD="${hash_temp}"
unset hash_temp plaintext_pw
sync
if shred -vfzu -n 5 "${pw_file}" > /dev/null 2>&1; then
printf "\e[92m✅ Password file '%s': shred -vfzu -n 5 >> done. \e[0m\n" "${pw_file}" > /dev/null 2>&1
else
printf "\e[91m❌ Password file '%s': shred -vfzu -n 5 >> NOT successful. \e[0m\n" "${pw_file}" > /dev/null 2>&1
fi
sync
shift 2
;;
--ssh-port)
if [[ -n "${2}" && "${2}" =~ ^-?[0-9]+$ && "${2}" -ge 1 && "${2}" -le 65535 ]]; then
declare -gi VAR_SSHPORT="${2}"
shift 2
else
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --ssh-port MUST be an integer between '1' and '65535'.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR__SSH__PORT}"
fi
;;
--ssh-pubkey)
declare -g VAR_SSHPUBKEY="${2}"
shift 2
;;
*)
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
usage
;;
esac
done
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh