#!/sbin/openrc-run

description="Load crash kernel or take dump+reboot"

: "${cmdline_append:="reset_devices nr_cpus=1"}"
: "${kexec_args:=}"
: "${makedumpfile_args:="-z -d 31"}"
: "${kdump_dir:=/var/crash}"

depend() {
	after localmount
	if [ -e /proc/vmcore ]; then
		# avoid starting unrelated services using up memory in crashkernel
		( cd /etc/init.d && before *; )
		keyword -timeout
	fi
}

start_load() {
	if [ -z "$kexec_args" ]; then
		eerror "Cannot load crash kernel without configuring kexec_args first"
		return 1
	fi
	if ! grep -q crashkernel /proc/cmdline; then
		einfo "Not loading crash kernel because crashkernel not set in cmdline"
		return
	fi

	# if already loaded unload first
	_stop

	ebegin "Loading crash kernel"

	local cmdline
	cmdline="$(cat /proc/cmdline) $cmdline_append"
	# shellcheck disable=SC2086 # allow spliting args
	kexec -p --command-line="$cmdline" $kexec_args
	eend "$?" "Could not load crash kernel"
}

start_dump() {
	local dest pgrp
	dest="$kdump_dir/$(date +%Y-%m-%d-%T)"
	ebegin "Dumping kernel $dest"
	mkdir -p "$dest"
	# shellcheck disable=SC2086 # allow spliting args
	makedumpfile $makedumpfile_args /proc/vmcore "$dest/dump"
	makedumpfile --dump-dmesg /proc/vmcore "$dest/dmesg"
	einfo "Dump done, rebooting"
	reboot
	# Interrupt parent openrc command by killing current session group
	# This avoids waiting for other services in same runlevel before
	# the reboot is actually processed
	pgrp=$(awk '{ print $6 }' /proc/self/stat)
	if [ -n "$pgrp" ]; then
		kill -SIGTERM -$pgrp
	fi
	eend 0
}

start() {
	if [ -e /proc/vmcore ]; then
		start_dump
	else
		start_load
	fi
}

_stop() {
	# we're not unloading the module on purpose to allow
	# crashes to work at poweroff
	# add `stop() { _stop; }` in conf.d/kdump to enable

	# not loaded
	kexec -S && return

	ebegin "Unloading crash kernel"
	kexec -p -u
	eend "$?" "Could not unload crash kernel"
}
