#!/bin/sh

# Author: R Veera Kumar <vkor@vkten.in>
# Year: 2020
# License: GPLv3

# Adapted from script by Stefano Brivio <sbrivio@redhat.com>

BUILD_JOBS=2
SSH_CMD="$(which ssh)"
SSH_OPTS=""
SSH_REM_CMD="ssh"
RSYNC_CMD="$(which rsync)"
RSYNC_OPTS="-a"

ssh_chk() {
	[ -z "${SSH_CMD}" ] && echo "No ssh cmd present" && exit 1
}

rsync_chk() {
	[ -z "${RSYNC_CMD}" ] && echo "No rsync cmd present" && exit 1
}

wrong_option() {
	echo "Wrong option: $1"
	echo "See usage"
}

err_option_arg() {
	echo "Give argument for option: $1"
	echo "See usage"
}

build() {
	echo -e "Kernel Build Started\n"

	make -j ${BUILD_JOBS}
}

config() {
	echo -e "Kernel Configuration\n"

	if [ ! -z "${cfg_file}" -a -e "${cfg_file}" ]; then
		[ -f "./.config" ] && cp .config .config.1 
		cp "${cfg_file}" .config
	fi

	[ -e "./.config" ] && make olddefconfig
}

get_k_vers() {
	k_rel="./include/config/kernel.release"
	[ -f "${k_rel}" ] && head -n 1 "${k_rel}"
}

copy_kernel() {
	[ ! -d "$1" ] && mkdir "$1"
	[ ! -d "${1}/boot" ] && mkdir "${1}/boot"

	k_vers="$(get_k_vers)"
	[ -z "${k_vers}" ] && echo "Invalid Kernel Version" && exit 1

	cp "arch/x86/boot/bzImage" "${1}/boot/vmlinuz-${k_vers}"
	cp "System.map" "${1}/boot/System.map-${k_vers}"
	cp ".config" "${1}/boot/config-${k_vers}"
	cp "Module.symvers" "${1}/boot/Module.symvers-${k_vers}"
}

copy_modules() {
	make modules_install INSTALL_MOD_PATH="${1}"
}

copy() {
	echo -e "Copying kernel and modules\n"

	[ -z "${copy_path}" ] && echo "Set --copy-path option" && exit 1
	copy_kernel "${copy_path}"
	copy_modules "${copy_path}"
}

inst_tgt_kernel() {
	${RSYNC_CMD} ${RSYNC_OPTS} -e "${SSH_REM_CMD} -p ${port}" \
		"${1}/boot/vmlinuz-${2}" \
		"${1}/boot/System.map-${2}" \
		"${1}/boot/config-${2}" \
		"${1}/boot/Module.symvers-${2}" \
		root@${host}:/boot
 }

inst_tgt_mod() {
	${RSYNC_CMD} ${RSYNC_OPTS} --delete -e "${SSH_REM_CMD} -p ${port}" \
		"${1}/lib/modules/${2}" \
		root@${host}:/lib/modules
}

inst_tgt_setup() {
	${SSH_CMD} ${SSH_OPTS} -p ${port} root@${host} \
		"depmod -a ${1};
		mkinitramfs -o /boot/initrd.img-${1} ${1};
		update-grub2;"
}

inst_tgt() {
	echo -e "Installing kernel and modules to target and setting it up\n"

	[ -z "${copy_path}" ] && echo "Set --copy-path option" && exit 1

	if [ ! -z "${kernel_version}" ]; then
		k_vers="${kernel_version}"
	else
		k_vers="$(get_k_vers)"
		[ -z "${k_vers}" ] && echo "Invalid Kernel Version" && exit 1
	fi
     
	ssh_chk
	rsync_chk

	inst_tgt_kernel "${copy_path}" "${k_vers}"
	inst_tgt_mod "${copy_path}" "${k_vers}"
	inst_tgt_setup "${k_vers}"
}

prune() {
	echo -e "Removing kernel and modules from target\n"

	[ -z "${kernel_version}" ] && echo "Prune: Empty Kernel Version" && exit 1

	k_vers="${kernel_version}"

	${SSH_CMD} ${SSH_OPTS} -p ${port} root@${host} \
		"rm -f /boot/vmlinuz-${k_vers};
		rm -f /boot/System.map-${k_vers};
		rm -f /boot/config-${k_vers};
		rm -f /boot/Module.symvers-${k_vers};
		rm -fr /lib/modules/${k_vers};
		update-grub2;"
}

reboot() {
	echo -e "Reboot the target\n"

	${SSH_CMD} ${SSH_OPTS} -p ${port} root@${host} \
		"reboot;"
}

all() {
	echo -e "Configure, build, copy and install kernel to target\n"

	config && build && copy && inst_tgt
}

usage() {
	echo -e "Usage:\n"
	echo -e "PROG [CMD] [OPTIONS]\n"
	echo -e -n "CMD: "
	echo -e "build|cfg|copy|help|inst-tgt|prune|reboot|all\n"
	echo "PROG [CMD] help -- for cmd help"
}

build_help() {
	echo "  build: Builds the kernel and modules"
	echo "    --build-jobs num: Parallel build jobs"
}

config_help() {
	echo "  cfg: Setup config file for kernel building"
	echo "    --cfg-file file: specify a config file else existing one is used"
}

copy_help() {
	echo "  copy: Copies the built kernel image and modules"
	echo "    --copy-path dir: copy to dir"
}

inst_tgt_help() {
	echo "  inst_tgt: Install kernel image and modules to target and set it up"
	echo "    --copy-path dir: copy to dir"
	echo "    --host host: ssh host target"
	echo "    --port port: ssh port target"
	echo "    --version kernel_version: Install this version on target"
}

prune_help() {
	echo "  prune: Remove the installed kernel image and modules from target"
	echo "    --version kernel_version: Remove this version on target"
	echo "    --host host: ssh host target"
	echo "    --port port: ssh port target"
}

reboot_help() {
	echo "  reboot: Reboot the target"
	echo "    --host host: ssh host target"
	echo "    --port port: ssh port target"
}

all_help() {
	echo "  all: Configure, build, copy and install to target"
	echo "    --build-jobs num: Parallel build jobs"
	echo "    --cfg-file file: Specify a config file else existing one gets used"
	echo "    --copy-path dir: Copy to dir"
	echo "    --host host: ssh host target"
	echo "    --port port: ssh port target"
}

case "$1" in
	build)
		cmd=build
		;;
	cfg)
		cmd=config
		;;
	copy)
		cmd=copy
		;;
	help)
		usage
		exit
		;;
	inst-tgt)
		cmd=inst_tgt
		;;
	prune)
		cmd=prune
		;;
	reboot)
		cmd=reboot
		;;
	all)
		cmd=all
		;;
	*)
		usage
		exit 1
		;;
esac

shift

case "${cmd}" in
	build|config|copy|inst_tgt|prune|reboot|all)
		[ "$1" = "help" ] && ${cmd}_help && exit
		;;
esac

while [ $# -ne 0 ]; do
	case "$1" in
		--cfg-file)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			cfg_file="$2"
			shift; shift
			;;
		--build-jobs)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			BUILD_JOBS=$2
			shift; shift
			;;
		--copy-path)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			copy_path="$2"
			shift; shift
			;;
		--host)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			host="$2"
			shift; shift
			;;
		--port)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			port="$2"
			shift; shift
			;;
		--version)
			[ -z "$2" ] && err_option_arg $1 && exit 1
			kernel_version="$2"
			shift; shift
			;;
			*)
			wrong_option $1
			exit 1
			;;
	esac
done

${cmd} ${opts}

