#!/usr/bin/bash
# Collect core dump from local node.

. /usr/share/shaman/functions

verify_caller

# sleep period to let other services write their log contents
SLEEP_DURATION=3

MIN_FREE_MB_DIR=128
MIN_FREE_MB_GCORE=10240


# Make kernel dump and coredump of vstorage-mount.
# Give some limited time to complete: 300sec

# Sync all relevant log files' contents onto disk

tmo=60

{
	sync -f /var/spool/abrt
} < /dev/null >& /dev/null &

wpid=$!
wait_timed "$wpid"


# Dump kernel core

tmo=300
kgcore="$WORK_DIR/kgcore"
touch "$kgcore"
truncate -s 0 "$kgcore"

{
	/usr/sbin/makedumpfile -f -l --num-threads 4 -d 31 /proc/kcore "$kgcore"
	sync -d "$kgcore"
} < /dev/null >& /dev/null &

wpid=$!
wait_timed "$wpid"

function is_dumping_core ()
{
	local this_pid="$1"
	local status_file="/proc/$this_pid/status"

	[ -r "$status_file" ] || return 1
	[ "$(awk '/^CoreDumping:/ {print $2}' "$status_file")" = "1" ]
}

# Use this simple pidof instead of system pidof which realiably deadlock
# when we have problems with mm

function mypidof ()
{
	local comm="$1"
	local p

	[ -n "$comm" ] || return 1
	for p in /proc/*/comm ; do
		if [ -r "$p" ]; then
			if [ "$(<"$p")" = "$comm" ]; then
				p=${p%/comm}
				echo "${p#/proc/}"
				return 0
			fi
		fi
	done
	return 1
}


# Dump vstorage-mount core
if [ -n "$CLUSTER_NAME" ]; then

	corepfx="$WORK_DIR/vstorage-mount"
	vmountpid="$(mypidof vstorage-mount)"
	tmo=1200

	{
		if [ -n "$vmountpid" ]; then
			# If vstorage-mount is dumping core right now wait till it is complete
			if is_dumping_core "$vmountpid"; then
				while is_dumping_core "$vmountpid"; do
					sleep 1
				done
			fi
		fi

		coredone=0
		if coredumpctl info -1 /usr/bin/vstorage-mount > "${corepfx}.coreinfo"; then
			coref="$(awk '/^Storage:/ {print $2}' "${corepfx}.coreinfo")"
			if [ -n "$coref" ] && [ -f "$coref" ]; then
				mtime="$(stat -c '%Y' "$coref")"
				curtime="$(date +%s)"
				if [ $((mtime + 300)) -ge "$curtime" ]; then
					if ! ln "$coref" "${corepfx}.corez"; then
						cp -a "$coref" "${corepfx}.corez"
					fi
					sync -f "${corepfx}.corez"
					coredone=1
				fi
			fi
		fi

		if [ -n "$vmountpid" ] && [ "$coredone" -eq 0 ] && [ -r "/proc/$vmountpid/stat" ]; then
			vup="$(awk '{printf "%u\n", $22/100}' "/proc/$vmountpid/stat")"
			uptime="$(awk '{printf "%u\n", $1}' /proc/uptime)"
			if [ -n "$vup" ] && [ -n "$uptime" ] && [ "$uptime" -ge $((vup + 600)) ]; then
				# Check space
				core_prefix="${corepfx}.core"
				core_out="${core_prefix}.${vmountpid}"
				space="$(get_avail_mb "$WORK_DIR")"
				if [ -n "$space" ] && [ "$space" -ge "$MIN_FREE_MB_GCORE" ]; then
					# This can hang if process is in D state or R in the kernel
					touch "$core_out"
					if gcore -a -o "$core_prefix" "$vmountpid"; then
						sync -d "$core_out"
						if [ "$(get_avail_mb "$WORK_DIR")" -le "$MIN_FREE_MB_DIR" ]; then
							rm -f "$core_out"
							sync -f "$WORK_DIR"
						fi
					fi
				fi
			fi
		fi
	} < /dev/null >& /dev/null &

	wpid=$!
	wait_timed "$wpid" "${corepfx}.core.$vmountpid"

fi

sync -f "$WORK_DIR"

# Sleep for a while to let other services write their log contents
sleep "$SLEEP_DURATION"

exit 0
