#!/usr/bin/env bash # -*- coding: utf-8 -*- # region header # Copyright Torben Sickert (info["~at~"]torben.website) 29.10.2015 # Janosch Dobler (TODO) 29.10.2015 # 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 # This tool provides a generic way to install systemd based remote linux # initramfs. # Examples # -------- # Start install progress command (Assuming internet is available): # >>> ./build_initramfs.sh # Note that you only get very necessary output until you provide "--verbose" as # commandline options. # Dependencies # ------------ # - bash (or any bash like shell) # - cpio - Copies files into or out of a cpio or tar archive. The # archive can be another file on the disk, a magnetic tape, # or a pipe. # - git - The stupid content tracker. # - test - Check file types and compare values (part of the shell). # - shift - Shifts the command line arguments (part of the shell). # - echo - Display a line of text (part of coreutils). # - mktemp - Create a temporary file or directory (part of coreutils). # - cat - Concatenate files and print on the standard output (part of # coreutils). # - rm - Remove files or directories (part of coreutils). # - sed - Stream editor for filtering and transforming text. # - gzip - Compress or expand files. # - curl - Transfer a URL # - tar - The GNU version of the tar archiving utility. # - make - GNU make utility to maintain groups of programs. # - cmake - The "cmake" executable is the CMake command-line interface. # - linux-headers - GNU make utility to maintain groups of programs. # - grep - Searches the named input files (or standard input if no # files are named, or if a single hyphen-minus (-) is given # as file name) for lines containing a match to the given # PATTERN. By default, grep prints the matching lines. ## region ensure presence of needed dependencies set -o errexit build_initramfs__needed_location="$(dirname "${BASH_SOURCE[0]}")/dnbd3-rootfs" if ! [[ -d "$build_initramfs__needed_location" ]]; then echo "The dnbd3 dracut plugin isn't available, loading it." if ! hash git 2>/dev/null; then echo "Needed dependency \"git\" isn't available. Please install \"git\" or provide the repositories data structure in \"$(dirname "${BASH_SOURCE[0]}")\"." result=1 fi build_initramfs__temporary_repository_location="$(mktemp --directory)" git clone git://git.openslx.org/openslx-ng/systemd-init.git \ "$build_initramfs__temporary_repository_location" pushd "$build_initramfs__temporary_repository_location" git submodule init git submodule update popd cp --recursive "${build_initramfs__temporary_repository_location}/builder/dnbd3-rootfs" \ "$build_initramfs__needed_location" rm --recursive --force "$build_initramfs__temporary_repository_location" fi set +o errexit ## endregion source "$(dirname "${BASH_SOURCE[0]}")/dnbd3-rootfs/scripts/rebash/core.sh" core.import exceptions exceptions.activate core.import logging core.import utils # endregion logging.set_commands_log_level debug logging.set_log_level critical # region properties build_initramfs_dracut_parameter='--force --no-hostonly' build_initramfs_verbose='no' build_initramfs_debug='no' build_initramfs_target='' build_initramfs_create_system_image='' build_initramfs_cleanup='no' build_initramfs_dependencies=(cpio git test shift mktemp cat rm sed gzip curl \ tar grep make gcc cmake readlink dirname dmsetup fakeroot fakechroot \ chroot qemu-nbd) # endregion # region functions ## region command line interface function build_initramfs_print_usage_message() { # Prints a description about how to use this program. logging.cat << EOF This program provides a generic way to install systemd based remote linux initramfs. EOF } function build_initramfs_print_usage_examples() { # Prints a description about how to use this program by providing examples. logging.cat << EOF Start install progress: >>> ./build_initramfs.sh EOF } function build_initramfs_print_command_line_option_description() { # Prints descriptions about each available command line option. logging.cat << EOF -h --help Shows this help message. -v --verbose Tells you what is going on (default: "$build_initramfs_verbose"). -d --debug Gives you any output from all tools which are used (default: "$build_initramfs_debug"). -c --cleanup Removes all distribution specific compiled files. -i --create-system-image Creates an image under given path from current system. (default: "$build_initramfs_create_system_image"). -t --target Creates an image against given target template filesystem. If not explicitly speicifed current system will be used as template system (default). Additional dracut parameter and normal parameter can be deleimiter via a single dash (-) (default: "$build_initramfs_dracut_parameter"). EOF } function build_initramfs_print_help_message() { # Provides a help message for this module. logging.plain "\nUsage: $0 [options]\n" build_initramfs_print_usage_message "$@" logging.plain '\nExamples:\n' build_initramfs_print_usage_examples "$@" logging.plain -e '\nOption descriptions:\n' build_initramfs_print_command_line_option_description "$@" logging.plain } function build_initramfs_parse_command_line() { # Provides the command line interface and interactive questions. while true; do case "$1" in -h|--help) shift build_initramfs_print_help_message "$0" exit 0 ;; -v|--verbose) shift build_initramfs_verbose='yes' ;; -d|--debug) shift build_initramfs_debug='yes' ;; -c|--cleanup) shift build_initramfs_cleanup='yes' ;; -i|--create-system-image) shift build_initramfs_create_system_image="$1" if [[ "$build_initramfs_create_system_image" == '' ]]; then logging.critical "This options needs a path to save image to." return 1 fi shift ;; -t|--target) shift build_initramfs_target="$1" if [[ "$build_initramfs_target" == '' ]]; then logging.critical "This options needs a path create initramfs from." return 1 fi shift ;; -) shift while [[ "$1" =~ ^.+$ ]]; do build_initramfs_dracut_parameter+=" $1" shift done shift ;; '') break ;; *) logging.critical "Given argument: \"$1\" is not available." return 1 esac done if [ "$build_initramfs_verbose" == 'yes' ]; then logging.set_commands_log_level debug logging.set_log_level info fi if [ "$build_initramfs_debug" == 'yes' ]; then logging.set_commands_log_level debug logging.set_log_level debug fi if [[ "$UID" != '0' ]]; then logging.critical \ "You have to run this script as \"root\" not as \"${USER}\"." exit 2 fi return 0 } ## endregion ## region helper function build_initramfs_initialize_dracut() { # Downloads and compiles dracut. # # Examples: # # >>> build_initramfs_initialize_dracut # ... mkdir --parents "$(dirname "${BASH_SOURCE[0]}")/dracut" logging.info 'Download and extract dracut.' curl --location \ https://www.kernel.org/pub/linux/utils/boot/dracut/dracut-043.tar.gz | \ tar --extract --gzip --directory \ "$(dirname "${BASH_SOURCE[0]}")/dracut" --strip-components 1 pushd "$(dirname "${BASH_SOURCE[0]}")/dracut" # NOTE: On virtualbox shared folder symlinks are not allowed. # NOTE: make the dracut-install binary (dracut-install resolves # dependencies etc.) logging.info 'Compiling dracut.' 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 cp "$(dirname "${BASH_SOURCE[0]}")/dracut/install/dracut-install" \ "$(dirname "${BASH_SOURCE[0]}")/dracut/dracut-install" popd return $? } function build_initramfs_create_qcow2_system() { # Packs current distribution in a qcow2 container. # # Examples: # # >>> build_initramfs_create_qcow2_system echo TODO # dmsetup snapshot ... #qemu-img create -f qcow2 "${CONTAINER_PATH}" "${QCOW_SIZE}" return $? } function build_initramfs_cleanup() { # Removes distribution specific generated files. # # Examples: # # >>> build_initramfs_cleanup source "$(dirname "${BASH_SOURCE[0]}")/dnbd3-rootfs/module-setup.sh" moddir="$(dirname "${BASH_SOURCE[0]}")$(dirname "$(readlink \ --canonicalize "$(dirname \ "${BASH_SOURCE[0]}")dnbd3-rootfs/module-setup.sh")")" clean return $? } ## endregion # endregion # region controller ## region dependency checks utils.dependency_check "${build_initramfs_dependencies[*]}" # TODO check for existing kernel headers. # Find lib locations: $(gcc -print-prog-name=cc1plus) -v if ! ldconfig --print-cache | grep libz.so; then logging.critical "You have to install the compression library \"libz\". Otherwise we aren't able to compile dnbd3 for your kernel." exit 1 fi ## endregion if ! build_initramfs_parse_command_line "$@"; then build_initramfs_print_help_message "$0" exit 1 fi ## region handle delegated operations to specified target if [[ "$build_initramfs_target" != '' ]]; then build_initramfs__target="$build_initramfs_target" if [[ -f "$build_initramfs_target" ]]; then build_initramfs__target="$(mktemp --directory)" # TODO #qemu-nbd "$build_initramfs_target" "$build_initramfs__target" fi if [[ -d "$build_initramfs__target" ]]; then build_initramfs__temporary_working_directory="$(fakeroot \ fakechroot chroot "$build_initramfs__target" mktemp --directory)" mount --bind "$(pwd)" \ "${build_initramfs__target}${build_initramfs__temporary_working_directory}" build_initramfs__parameter_skip=false build_initramfs__parameter_to_forward=() for build_initramfs__parameter; do if $build_initramfs__parameter_skip; then build_initramfs__parameter_skip=false elif [[ "$build_initramfs__parameter" == '-t' ]] || \ [[ "$build_initramfs__parameter" == '--target' ]] then build_initramfs__parameter_skip=true else build_initramfs__parameter_to_forward+=("$build_initramfs__parameter") fi done # TODO check FAKECHROOT_CMD_SUBST FAKECHROOT_CMD_SUBST=/usr/bin/ldconfig=/usr/bin/ldconfig fakeroot \ fakechroot chroot "${build_initramfs__target}" \ "${build_initramfs__temporary_working_directory}/${BASH_SOURCE[0]}" \ ${build_initramfs__parameter_to_forward[*]} # TODO grap result from /boot/initramfs-test.img fi exit 0 fi ## endregion ## region handle dependencies which can be resolved automatically logging.info 'Checking dracut.' if ! [[ -f "$(dirname "${BASH_SOURCE[0]}")/dracut/dracut-install" ]]; then logging.info "Dracut isn't available yet loading it." build_initramfs_initialize_dracut fi build_initramfs__dracut_modules_source='../../dnbd3-rootfs' build_initramfs__dracut_modules_target="$(dirname "${BASH_SOURCE[0]}")/dracut/modules.d/90dnbd3-rootfs" if [[ ! -L "$build_initramfs__dracut_modules_target" || "$(readlink \ "$build_initramfs__dracut_modules_target")" != \ "$build_initramfs__dracut_modules_source" ]] then logging.info \ "Link dnbd3 plugin into dracut modules folder ($build_initramfs__dracut_modules_source -> $build_initramfs__dracut_modules_target)." if ! ln --symbolic "$build_initramfs__dracut_modules_source" \ "$build_initramfs__dracut_modules_target" 2>/dev/null; then logging.warn \ "Link \"$build_initramfs__dracut_modules_source\" to \"$build_initramfs__dracut_modules_target\" fails. We will copy them. So you have to recopy it if you recompile things in specified source." cp --recursive --force --no-target-directory \ "$(dirname "${BASH_SOURCE[0]}")/$(basename "$build_initramfs__dracut_modules_source")" \ "$build_initramfs__dracut_modules_target" fi fi ## endregion ## region prepare and perform final dracut call build_initramfs__loglevel='' if [ "$build_initramfs_verbose" == 'yes' ]; then build_initramfs__loglevel='--verbose' fi build_initramfs__modules='dnbd3-rootfs' if [ "$build_initramfs_debug" == 'yes' ]; then build_initramfs__loglevel="$build_initramfs__loglevel --stdlog 4" build_initramfs__modules="$build_initramfs__modules i18n terminfo" fi if [[ "$build_initramfs_create_system_image" != '' ]]; then logging.info 'Create system image.' build_initramfs_create_qcow2_system "$build_initramfs_create_system_image" elif [[ "$build_initramfs_cleanup" == 'yes' ]]; then logging.info 'Removing distribution specific files.' build_initramfs_cleanup else logging.info 'Build initramfs.' # NOTE: We deactivate our exception handle since dracut returns "1" if it # is launched with help parameter ("-h" or "--help"). exceptions.deactivate echo "$(dirname "${BASH_SOURCE[0]}")/dracut/dracut.sh" "$(dirname "${BASH_SOURCE[0]}")/dracut/dracut.sh" --local \ $build_initramfs__loglevel --modules "$build_initramfs__modules" \ ${build_initramfs_dracut_parameter[*]} /boot/initramfs-test.img exceptions.activate fi exceptions.deactivate ## endregion # endregion # region vim modline # vim: set tabstop=4 shiftwidth=4 expandtab: # vim: foldmethod=marker foldmarker=region,endregion: # endregion