summaryrefslogblamecommitdiffstats
path: root/build-initramfs.sh
blob: dbdeeba3c26b8691e504223701e801bdcb7437d6 (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
	git clone "${gitargs[@]}" "${url}" "${path}"

	[ -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
compile_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 submodules for the dnbd3-rootfs module
	bootstrap
	# 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 "${_dracut_dir}/dracut-install" ]; then
		echo "Dracut isn't available yet loading it."
		compile_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

	_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}" "${_dracut_dir}" --recursive --force
	elif [[ "$cleanup" == 'yes' ]]; then
		echo 'Removing distribution specific files.'
		cleanup
	else
		. "${_repo_dir}/modules.d/dnbd3-rootfs/helper/build.inc"
		build_initialize_components
		if [[ "$initialize" == 'yes' ]]; then
			echo "Initialized."
			exit 0
		fi
		echo 'Build 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 initial ram file system failed.'
			exit 1
		fi
		# NOTE: dracut generate the initramfs with 0600 permissions
		chmod 0644 "${file_path}"
	fi
}

main "$@"