#!/usr/bin/env bash # -*- coding: utf-8 -*- # region header # Copyright Torben Sickert (info["~at~"]torben.website) 29.10.2015 # Janosch Dobler (info["~at~"]jandob.com) 29.10.2015 # Jonathan Bauer (jonathan.bauer@rz.uni-freiburg.de) 19.09.2019 # License # ------- # This library written by Torben Sickert and Janosch Dobler stand under a # creative commons naming 3.0 unported license. # see http://creativecommons.org/licenses/by/3.0/deed.de ## endregion declare -rg _root_dir="$(readlink -f $(dirname ${BASH_SOURCE[0]}))" declare -rg _repo_dir="${_root_dir}/systemd-init.git" declare -rg _git_source="git://git.openslx.org/openslx-ng/systemd-init.git" declare -rg _git_branch="centos8" ## region ensure presence of needed dependencies set -o errexit if [ ! -e "$_repo_dir" ]; then echo "Missing dracut modules repository, loading them." if ! hash git; then echo "Needed dependency \"git\" isn't available." echo "Please install \"git\" or provide the main repository in \"${_repo_dir}\"." exit 1 fi git clone --branch "$_git_branch" --single-branch --depth 1 \ "$_git_source" "${_repo_dir}" pushd "${_repo_dir}" git submodule init # try to clone submodules as shallowy as possible, since we cannot just # use '--depth 1' on submodules residing on non-master branches... for mod in $(grep -Po '(?<=^\[submodule ")([^"]+)' .gitmodules); do url="$(git config -f .gitmodules --get submodule.${mod}.url)" path="$(git config -f .gitmodules --get submodule.${mod}.path)" branch="$(git config -f .gitmodules --get submodule.${mod}.branch)" commit="$(git submodule status $path | grep -oE '[0-9a-f]{40}')" depth_arg=("--shallow-since") [ "$mod" = "dnbd3" ] && depth_arg+=("2019-02-12") && url="git://git.openslx.org/dnbd3-ng.git" && commit="b57dadc2dd577fb8ce21975722cdfa2f010cd718" [ "$mod" = "rebash" ] && depth_arg+=("2016-11-30") [ "$mod" = "qemu-xmount" ] && depth_arg+=("2016-01-01") [ "$mod" = "xmount" ] && depth_arg+=("2015-11-05") [ "$mod" = "kernel-qcow2-linux" ] && depth_arg+=("2019-08-25") [ "$mod" = "kernel-qcow2-util-linux" ] && depth_arg+=("2019-08-15") git clone -n --no-tags "${depth_arg[@]}" --branch "$branch" "$url" "$path" pushd "$path" git checkout "$commit" popd done # apply patches for submodules git submodule foreach ' for p in $(find ${toplevel}/builder/patches/${path##*/} -type f -name "*.patch" | sort -n); do patch -p1 < $p || echo "Failed to patch $path with $p - expect errors." done 2>/dev/null ' popd fi set +o errexit ## endregion file_path='/boot/initramfs.img' dracut_parameter=(--force --no-hostonly) verbose='no' debug='no' target='' cleanup='no' full_cleanup='no' use_systemd_in_initramfs='no' print_help_message() { echo "help" } parse_command_line() { while true; do case "$1" in -h|--help) shift print_help_message "$0" exit 0 ;; -v|--verbose) shift verbose='yes' ;; -d|--debug) shift debug='yes' ;; -p|--file-path) local given_argument="$1" shift file_path="$1" if [[ "$file_path" == '' ]]; then echo \ "Error with given option \"$given_argument\": This option needs a path to save initramfs image to." return 1 fi shift ;; -c|--cleanup) shift cleanup='yes' ;; -f|--full-cleanup) shift full_cleanup='yes' ;; -s|--use-systemd-in-initramfs) shift use_systemd_in_initramfs='yes' ;; -t|--target) local given_argument="$1" shift target="$1" if [[ "$target" == '' ]]; then echo \ "Error with given option \"$given_argument\": This option needs a path create initramfs from." return 1 fi shift ;; -i|--init) shift initialize='yes' ;; -k|--kernel-version) local given_argument="$1" shift kernel_version="$1" if [ -z "$kernel_version" ]; then echo \ "Error with given option \"$given_argument\": This option needs a kernel version to build the initramfs for." return 1 fi shift ;; -H|--kernel-headers) local given_argument="$1" shift kernel_headers="$1" if [ -z "$kernel_headers" ]; then echo \ "Error with given option \"$given_argument\": This option needs the path to the kernel headers." return 1 fi shift ;; -q|--qcow-handler) local given_argument="$1" shift qcow_handler="$1" if [ -z "$qcow_handler" ]; then echo \ "Error with given option \"$given_argument\": This options needs to be either 'xmount' or 'kernel'." return 1 fi shift ;; -u|--update) shift update='yes' ;; -) shift while [[ "$1" =~ ^.+$ ]]; do dracut_parameter+=("$1") shift done ;; '') break ;; *) echo \ "Error with given option \"$1\": This argument is not available." return 1 esac done return 0 } ## endregion ## region helper initialize_dracut() { # First check what version to get # Autodetect the kmod version present on the system to decide which dracut version to get # * v47 requires kmod >= 23 (Available in Ubuntu 18.04) # * v46 works with kmod == 20 (CentOS 7.5 only provides kmod v20) if [ "$(pkg-config --modversion libkmod)" -ge 23 ]; then dracut_version="047" else dracut_version="046" fi dracut_resource_url="https://www.kernel.org/pub/linux/utils/boot/dracut/dracut-$dracut_version.tar.gz" if [[ ! -f "${_root_dir}/dracut/install/dracut-install" ]]; then mkdir --parents "${_root_dir}/dracut" echo "Download and extract dracut version $dracut_version" curl --location "$dracut_resource_url" | tar --extract --gzip \ --directory "${_root_dir}/dracut" --strip-components 1 pushd "${_root_dir}/dracut" # NOTE: On virtualbox shared folder symlinks are not allowed. # NOTE: make the dracut-install binary (dracut-install resolves # dependencies etc.) echo 'Compiling dracut.' ./configure make install/dracut-install # NOTE: We have to copy the binary to current instead of symlinking # them since this feature isn't supported in shared virtual box machine # folders. # If symlinks would be available we could simply use: # >>> make dracut-install popd fi cp "${_root_dir}/dracut/install/dracut-install" \ "${_root_dir}/dracut/dracut-install" return $? } # The idea here was to source each module-setup.sh from our # custom dracut modules and call their clean() function. # TODO: Does this still work? cleanup() { local plugin_path plugin_path="${_root_dir}/modules.d/dnbd3-rootfs" source "${plugin_path}/module-setup.sh" moddir="$(cd "$plugin_path" &>/dev/null && pwd)" clean return $? } main() { if ! parse_command_line "$@"; then print_help_message "$0" exit 1 fi # if no kernel was specified as dracut argument, use the running kernel's version echo "Building for:" if [ -z "$kernel_version" ]; then kernel_version="$(uname -r)" fi echo " * kernel version: $kernel_version" # similar for kernel headers needed to compile dnbd3 against. if [ -z "$kernel_headers" ]; then kernel_headers="/lib/modules/${kernel_version}/build" fi if [ ! -f "${kernel_headers}/Makefile" ]; then echo 'Missing core dependency "linux-headers" for version to compile against given or current kernel.' fi echo " * kernel headers: $kernel_headers" [ -n "$qcow_handler" ] && echo " * qcow2 handler: $qcow_handler" export _QCOW_HANDLER="$qcow_handler" if [ "$update" == "yes" ]; then pushd "${_repo_dir}" git pull popd fi echo 'Checking dracut...' if [[ ! -f "${_root_dir}/dracut/dracut-install" ]]; then echo "Dracut isn't available yet loading it." initialize_dracut fi for _dracut_module_dir in "${_repo_dir}/builder/modules.d/"*; do [ -d "${_dracut_module_dir}" ] || continue _dracut_module="$(basename $_dracut_module_dir)" # TODO allow module-specific priority _dracut_module_target="${_root_dir}/dracut/modules.d/00${_dracut_module}" if [[ ! -L "$_dracut_module_target" || "$(readlink \ "$_dracut_module_target")" != "$_dracut_module_dir" ]]; then echo \ "Link ${_dracut_module} plugin into dracut modules folder ($_dracut_module_dir -> $_dracut_module_target)." if ! ln --symbolic --force "$_dracut_module_dir" "$_dracut_module_target"; then echo \ "Linking \"$_dracut_module_dir\" to \"$_dracut_module_target\" failed." \ " We will copy them. So we have to recopy it every time to ensure that recompiled things take effect." cp --recursive --force --no-target-directory \ "$_dracut_module_dir" \ "$_dracut_module_target" fi fi done _loglevel='' if [ "$verbose" == 'yes' ]; then _loglevel='--verbose' fi _modules=(dnbd3-rootfs conf-tgz) echo "Default modules: ${_modules[@]}" if [ "$debug" == 'yes' ]; then _loglevel="$_loglevel --stdlog 4" _modules+=(i18n terminfo) fi if [ "$use_systemd_in_initramfs" == 'yes' ]; then _modules+=(systemd systemd-initrd dracut-systemd) fi # Preprocess done - start build, cleanup or full cleanup if [[ "$full_cleanup" == 'yes' ]]; then echo 'Removing all modules.' rm "${_repo_dir}" "${_root_dir}/dracut" --recursive --force elif [[ "$cleanup" == 'yes' ]]; then echo 'Removing distribution specific files.' cleanup else . "${_repo_dir}/builder/modules.d/dnbd3-rootfs/helper/build.inc" build_initialize_components if [[ "$initialize" == 'yes' ]]; then echo "Initialized." exit 0 fi echo 'Build initramfs.' "${_root_dir}/dracut/dracut.sh" --local \ $_loglevel --modules "${_modules[*]}" --conf /etc/dracut.conf \ --confdir /etc/dracut.conf.d "${dracut_parameter[@]}" \ --kver "${kernel_version}" "$file_path" _return_code=$? if [ "$_return_code" != 0 ]; then echo 'Building initial ram file system failed.' exit 1 fi # NOTE: dracut generate the initramfs with 0600 permissions chmod 0644 "${file_path}" fi } main "$@"