summaryrefslogblamecommitdiffstats
path: root/build-initramfs.sh
blob: f910e579c6d5ac3f02d2941664000586fccd4648 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                       
               
                                                                  


                                                                                     
 

         


                                                                         
            
 

                                                                          



                                      
                                                                   
 
                     
                               
                                        


            
            
                 
                             
 





















                                                                           
                                             










                                                                                    
                                            

                                               
                                             































                                                                                 



                                                           








































                                                                     
                      
                   
 
 
                      




















                                                                 

                                                                                                      





















                                                              

                                                                                                 













                                                                 

                                                                                                                









                                                                 

                                                                                                   









                                                               

                                                                                                       























                                                                                                         
 
                
 
            
                
                     















                                                                               
 
 


                                                           
           





                                                         
 
 
        



                                          

                                                        
                 













                                                                        









                                                                     

                                                          



                                                                        
 
                                      



                                    
 
                                 

                                                             
                                 
          
 







                                                                                    



                                                                                            

                                                                                                                 
                                                                                                                                             





                                                                              
 
                                

                                              




                                                   

                                         
                                                        

                                                                 

















                                                                               
          

                                                                   
 
 
         
#!/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
#			Thiago Abdo    (tjabdo@inf.ufpr.br) 06.11.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

# Afaik the idea here was to have the root dir where build-initramfs.sh
# is called from and the repo dir where the systemd-init.git is cloned to:
#	<root_dir>
#		 |- build-initramfs.sh
#		 |- dracut
#		 |- systemd-init
declare -rg _root_dir="$(readlink -f $(dirname ${BASH_SOURCE[0]}))"

# TODO clean these up
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'


declare -rg _bootstrap_modules="bootstrap.conf"

bootstrap() {
	if [ ! -f "$_bootstrap_modules" ]; then
		echo "Missing modules definition file: $_bootstrap_modules"
		print_help_message 1
		exit 1
	fi
	
	. "$_bootstrap_modules"
	
	if [[ ! -v core_dracut[@] ]] || [[ ! -v core_repo[@] ]]; then
		echo "Missing core modules for dracut & systemd-init"
		exit 1
	fi

	declare -rg _repo_dir="$(readlink -f ${core_repo[path]})"
	declare -rg _dracut_dir="$(readlink -f ${core_dracut[path]})"

	echo "Modules file: $_bootstrap_modules"
	echo "Core modules: ${!core_*}"
	echo "Modules:		${!module_*}"
	echo ""
	

	for module in "${!core_@}" "${!module_@}"; do
		declare -n _ref="$module"
		if [ -n "$(ls -A "${_ref[path]}" 2> /dev/null)" ]; then
			echo "'${_ref[path]}' not empty, skipping..."
			continue
		fi
		echo "#########################  $module  #########################"
		echo "Handler: ${_ref[handler]}"
		echo "	  URL: ${_ref[url]}"
		echo " Branch: ${_ref[branch]}"
		echo " Commit: ${_ref[commit]}"
		echo "	 Path: ${_ref[path]}"
		handler_${_ref[handler]} \
			"${_ref[path]}" \
			"${_ref[url]}" \
			"${_ref[branch]}" \
			"${_ref[commit]}"

		# apply patches if any are required
		shopt -s nullglob
		pushd "${_ref[path]}"
		for patch in "${_repo_dir}/patches/${_ref[path]##*/}/"*.patch; do
			patch -p1  < "$patch"
		done
		popd

	done
}

handler_git() {
	local path="$1"
	local url="$2"
	local branch="$3"
	local commit="$4"

	mkdir -p "$path"

	local gitargs=( \
		"--depth" "1" \
		"--single-branch" \
	)
	if [ -n "$branch" ]; then
		gitargs+=("--branch" "$branch")
	fi
	if ! git clone "${gitargs[@]}" "$url" "$path"; then
		echo "Error cloning '$url' to '$path'."
		exit 1
	fi

	[ -z "$commit" ] && return 0
	
	# make sure given commit in in the fetched history
	local revision="$branch"
	if [ -n "$commit" ]; then
		revision="$commit"
	fi

	# manual "shallow clone" since not all server allow it...
	pushd "$path"
	local i=50
	while ! git rev-parse --quiet --verify $revision^{commit}; do
		git fetch --depth=$(( i+=50 ))
	done
	git reset --hard "$revision"
	popd
}

handler_http() {
	local path="$1"
	local url="$2"

	mkdir --parents "$path"

	curl \
		--location \
		--max-redirs 5 \
		--max-time 7 \
		--connect-timeout 2 \
		--retry 3 \
		--retry-max-time 12 \
		"$url" \
		| tar \
			--extract \
			--gzip \
			--directory "$path" \
			--strip-components 1
}


print_help_message() {
	echo "TODO"
}

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() {
	pushd "${_dracut_dir}"
	# 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
	cp "${_dracut_dir}/install/dracut-install" \
		"${_dracut_dir}/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="${_repo_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

	# prepare remote modules and set core variables.
	bootstrap

	if [ "$full_cleanup" = "yes" ]; then
		echo 'Removing all modules.'
		rm "${_repo_dir}" "${_dracut_dir}" --recursive --force
		exit $?
	fi

	if [ "$cleanup" = "yes" ]; then
		echo 'Removing distribution specific files.'
		cleanup
		exit $?
	fi

	# Default to the running kernel's version if none were specified
	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 kernel headers for given kernel!'
		 exit 1
	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 "${_dracut_dir}/dracut-install" ]; then
		echo "Dracut isn't available yet loading it."
		initialize_dracut
	fi

	for _dracut_module_dir in "${_repo_dir}/modules.d/"*; do
		[ -d "${_dracut_module_dir}" ] || continue
		_dracut_module="$(basename $_dracut_module_dir)"
		# TODO allow module-specific priority
		_dracut_module_target="${_dracut_dir}/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

	# default dracut modules
	_modules=(dnbd3-rootfs conf-tgz)
	echo "Default modules: ${_modules[@]}"
	if [ "$verbose" = "yes" ]; then
		dracut_parameters+=("--verbose")
	fi
	if [ "$debug" = "yes" ]; then
		dracut_parameters+=("--stdlog" "4")
		_modules+=(i18n terminfo)
	fi
	if [ "$use_systemd_in_initramfs" = "yes" ]; then
		_modules+=(systemd systemd-initrd dracut-systemd)
	fi

	# Initialize and exit if we are only preparing the build environment
	. "${_repo_dir}/modules.d/dnbd3-rootfs/helper/build.inc"
	build_initialize_components
	if [ "$initialize" = "yes" ]; then
		echo "Initialization succeeded."
		exit 0
	fi

	echo 'Building initramfs...'
	"${_dracut_dir}/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 initramfs failed.'
		exit 1
	fi
	# NOTE: dracut generate the initramfs with 0600 permissions
	chmod 0644 "${file_path}"
}

main "$@"