#!/bin/bash

# Purpose {{{
# This script will build a new initrd with some extra firmwares.
#   1. Download Debian initrd (Bullseye, Buster, Stretch and Sid)
#   2. Download firmwares
#     * bnx2
#     * all non-free (for tigon)
#     * Myricom for IBM
#     * qlogic
#     * iwlwifi (Intel WiFi for user's laptop)
#   3. Extract everything
#   4. Build a new initrd with everything and compress with XZ
# }}}
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG

# Default value for TFTP's directory
if command -v in.tftpd > /dev/null; then
	source /etc/default/tftpd-hpa
else
	TFTP_DIRECTORY="/srv/tftp"
fi

FIRM_BNX2_DEB_URL_DEFAULT="http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-bnx2_0.43_all.deb"
FIRM_NONFREE_DEB_URL_DEFAULT="http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-linux-nonfree_0.43_all.deb"
FIRM_MYRICOM_DEB_URL_DEFAULT="http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-myricom_0.43_all.deb"
FIRM_QLOGIC_DEB_URL_DEFAULT="http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-qlogic_0.43_all.deb"
FIRM_IWLWIFI_DEB_URL_DEFAULT="http://ftp.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-iwlwifi_20210818-1~bpo11+1_all.deb"

## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() {                                                       # {{{

	cat <<- EOF
usage: $PROGNAME [-d|-h]

This script will build a new Debian initrd with extra firmwares for
"all" Debian's releases.

EXAMPLES :
    - Build Debian's initrd to default place (${TFTP_DIRECTORY})
        ${PROGNAME}

OPTIONS :
    -d,--debug
        Enable debug messages.

    -h,--help
        Print this help message.

EOF

}
# }}}
debug_message() {                                               # {{{

	local_message="${1}"

	## Print message if DEBUG is enable (=0)
	[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG − ${PROGNAME} : ${local_message}"

	return 0
}
# }}}
error_message() {                                               # {{{

	local_error_message="${1}"
	local_error_code="${2}"

	## Print message
	printf '%b\n' "ERROR − ${PROGNAME} : ${RED}${local_error_message}${RESET}"

	exit "${local_error_code:=66}"
}
# }}}
define_vars() {                                                 # {{{

	# If firm_bnx2_deb_url wasn't defined (argument) {{{
	if [ -z "${firm_bnx2_deb_url}" ]; then
		## Use default value
		firm_bnx2_deb_url="${FIRM_BNX2_DEB_URL_DEFAULT}"
	fi
	# }}}
	# If firm_nonfree_deb_url wasn't defined (argument) {{{
	if [ -z "${firm_nonfree_deb_url}" ]; then
		## Use default value
		firm_nonfree_deb_url="${FIRM_NONFREE_DEB_URL_DEFAULT}"
	fi
	# }}}
	# If firm_myricom_deb_url wasn't defined (argument) {{{
	if [ -z "${firm_myricom_deb_url}" ]; then
		## Use default value
		firm_myricom_deb_url="${FIRM_MYRICOM_DEB_URL_DEFAULT}"
	fi
	# }}}
	# If firm_qlogic_deb_url wasn't defined (argument) {{{
	if [ -z "${firm_qlogic_deb_url}" ]; then
		## Use default value
		firm_qlogic_deb_url="${FIRM_QLOGIC_DEB_URL_DEFAULT}"
	fi
	# }}}
	# If firm_iwlwifi_deb_url wasn't defined (argument) {{{
	if [ -z "${firm_iwlwifi_deb_url}" ]; then
		## Use default value
		firm_iwlwifi_deb_url="${FIRM_IWLWIFI_DEB_URL_DEFAULT}"
	fi
	# }}}

}
# }}}

download_file() {                                               # {{{

	local_url="${1}"
	local_dest_file="${2}"


	## If the destination file is empty
	if [ -z "${local_dest_file}" ]; then
		debug_message "download_file − \
Download ${local_url} in the current directory."
		wget --quiet "${local_url}"
	else
		debug_message "download_file − \
Download ${local_url} to ${RED}${local_dest_file}${COLOR_DEBUG} ."
		wget --quiet "${local_url}" --output-document="${local_dest_file}"
	fi

	## Unset variables
	unset local_url
	unset local_dest_file
}
# }}}
is_file_empty() {                                               # {{{

	local_file="${1}"

	## File is empty by default
	return_is_file_empty="0"

	### Check if the file is empty
	if [ ! -s "${local_file}" ]; then
		return_is_file_empty="0"
		debug_message "is_file_empty − \
The file ${RED}${local_file}${COLOR_DEBUG} is empty or doesn't exists."
	else
		return_is_file_empty="1"
		debug_message "is_file_empty − \
The file ${RED}${local_file}${COLOR_DEBUG} exists and has a size greater than zero."
	fi

	## Unset variables
	unset local_file

	return "${return_is_file_empty}"
}
# }}}

main() {                                                        # {{{

	if ! [ $(id -u) = 0 ]; then
		# To allow creation of temp file (mknod,…)
		error_message "Please run this script as root" 1
	fi

	define_vars

	for DISTRO in bullseye buster stretch sid; do  # For ALL Debian's version

		debug_message "Main FOR loop − \
Manage initrd and firmwares for ${RED}${DISTRO}${COLOR_DEBUG} release."

		## Temp directory
		TEMP_DIR=$(mktemp -d)
		pushd "${TEMP_DIR}" > /dev/null \
			|| error_message "Can't move to ${TEMP_DIR}/ temp directory." 2
		initrd_file="${TEMP_DIR}/initrd.gz"

		## Download original initrd {{{
		download_file "http://deb.debian.org/debian/dists/${DISTRO}/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz" "${initrd_file}"
		is_file_empty "${initrd_file}" \
			&& error_message "${initrd_file} file for ${DISTRO} is empty !" 3
		## }}}
		## Uncompress initrd {{{
		mkdir -- "${TEMP_DIR}"/mkinitrd
		pushd "${TEMP_DIR}"/mkinitrd/ > /dev/null \
			|| error_message "Can't move to ${TEMP_DIR}/mkinitrd/ directory." 2
		zcat "${initrd_file}" | cpio --extract --quiet --preserve-modification-time 1>/dev/null 2>&1
		popd > /dev/null \
			|| error_message "Can't move back from ${TEMP_DIR}/mkinitrd/ directory." 2
		## }}}

		## Download bnx2's firmware and uncompress it {{{
		firm_bnx2_deb_file="${TEMP_DIR}/firmware-bnx2.deb"
		#wget http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-bnx2_0.43_all.deb
		download_file "${firm_bnx2_deb_url}" "${firm_bnx2_deb_file}"
		is_file_empty "${firm_bnx2_deb_file}" \
			&& error_message "${firm_bnx2_deb_file} file for ${DISTRO} is empty !" 3
		dpkg-deb --extract "${firm_bnx2_deb_file}" "${TEMP_DIR}"/mkinitrd \
			|| error_message "Can't extract ${firm_bnx2_deb_file} file for ${DISTRO}." 3
		## }}}

		## Download nonfree firmwares (for Tigon…) and uncompress it {{{
		firm_nonfree_deb_file="${TEMP_DIR}/firmware-nonfree.deb"
		download_file "${firm_nonfree_deb_url}" "${firm_nonfree_deb_file}"
		is_file_empty "${firm_nonfree_deb_file}" \
			&& error_message "${firm_nonfree_deb_file} file for ${DISTRO} is empty !" 3
		dpkg-deb --extract "${firm_nonfree_deb_file}" "${TEMP_DIR}"/mkinitrd \
			|| error_message "Can't extract ${firm_nonfree_deb_file} file for ${DISTRO}." 3
		## }}}

		## Download myricom's firmware (for IBM) and uncompress it {{{
		firm_myricom_deb_file="${TEMP_DIR}/firmware-myricom.deb"
		download_file "${firm_myricom_deb_url}" "${firm_myricom_deb_file}"
		is_file_empty "${firm_myricom_deb_file}" \
			&& error_message "${firm_myricom_deb_file} file for ${DISTRO} is empty !" 3
		dpkg-deb --extract "${firm_myricom_deb_file}" "${TEMP_DIR}"/mkinitrd \
			|| error_message "Can't extract ${firm_myricom_deb_file} file for ${DISTRO}." 3
		## }}}

		## Download qlogic's firmware and uncompress it {{{
		firm_qlogic_deb_file="${TEMP_DIR}/firmware-qlogic.deb"
		download_file "${firm_qlogic_deb_url}" "${firm_qlogic_deb_file}"
		is_file_empty "${firm_qlogic_deb_file}" \
			&& error_message "${firm_qlogic_deb_file} file for ${DISTRO} is empty !" 3
		dpkg-deb --extract "${firm_qlogic_deb_file}" "${TEMP_DIR}"/mkinitrd \
			|| error_message "Can't extract ${firm_qlogic_deb_file} file for ${DISTRO}." 3
		## }}}

		## Download iwlwifi's firmware (for user's laptop) and uncompress it {{{
		firm_iwlwifi_deb_file="${TEMP_DIR}/firmware-iwlwifi.deb"
		#wget http://deb.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-iwlwifi_0.43_all.deb
		download_file "${firm_iwlwifi_deb_url}" "${firm_iwlwifi_deb_file}"
		is_file_empty "${firm_iwlwifi_deb_file}" \
			&& error_message "${firm_iwlwifi_deb_file} file for ${DISTRO} is empty !" 3
		dpkg-deb --extract "${firm_iwlwifi_deb_file}" "${TEMP_DIR}"/mkinitrd \
			|| error_message "Can't extract ${firm_iwlwifi_deb_file} file for ${DISTRO}." 3
		## }}}

		## Make a new initrd {{{
		new_initrd_file="${TEMP_DIR}/initrd.xz"
		mv "${initrd_file}" initrd_orig.gz
		pushd "${TEMP_DIR}"/mkinitrd/ > /dev/null \
			|| error_message "Can't move to ${TEMP_DIR}/mkinitrd/ temp directory." 2
		### With a very good compression rate
		find . | cpio --quiet --create --format=newc | xz --stdout -9 --check=crc32 > "${new_initrd_file}"
		is_file_empty "${new_initrd_file}" \
			&& error_message "New initrd ${new_initrd_file} file for ${DISTRO} is empty !" 3
		popd > /dev/null \
			|| error_message "Can't move back from ${TEMP_DIR}/mkinitrd/ directory." 2
		## }}}

		## Move new initrd to TFTP tree {{{
		mkdir --parents -- "${TFTP_DIRECTORY}/installer/debian/${DISTRO}/amd64/"
		mv -- "${new_initrd_file}" "${TFTP_DIRECTORY}/installer/debian/${DISTRO}/amd64/initrd_firm.xz"
		## }}}

		## Leave temp directory and clean it {{{
		popd > /dev/null \
			|| error_message "Can't move back from ${TEMP_DIR}/ directory." 2
		rm --recursive --force -- "${TEMP_DIR}"
		## }}}

	done

}
# }}}

# Manage arguments                                                # {{{
# This code can't be in a function due to argument management

if [ ! "${NBARGS}" -eq "0" ]; then

	manage_arg="0"

	## If the first argument is not an option
	if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
	then
		## Print help message and exit
		printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
		printf '%b\n' "---"
		usage

		exit 1
	fi

	# Parse all options (start with a "-") one by one
	while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do

	case "${1}" in
		-d|--debug )                          ## debug
			DEBUG=0
			;;
		-h|--help )                           ## help
			usage
			## Exit after help informations
			exit 0
			;;
		* )                                   ## unknow option
			printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
			printf '%b\n' "---"
			usage
			exit 1
			;;
	esac

	debug_message "Arguments management − \
${RED}${1}${COLOR_DEBUG} option managed."

	## Move to the next argument
	shift
	manage_arg=$((manage_arg+1))

	done

	debug_message "Arguments management − \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
	debug_message "Arguments management − \
No arguments/options to manage."
fi

# }}}

main

exit 0
