Hi,

I enhanced the dump-core script to collect meta-data information in
apport's crash file format to ease the crash file analysis. An updated
patch is attached.

-- 
Benjamin Drung
System Developer
Debian & Ubuntu Developer

ProfitBricks GmbH
Greifswalder Str. 207
D - 10405 Berlin

Email: [email protected]
URL:  http://www.profitbricks.com

Sitz der Gesellschaft: Berlin.
Registergericht: Amtsgericht Charlottenburg, HRB 125506B.
Geschäftsführer: Andreas Gauger, Achim Weiss.
From 085aecd10eae1ae2fae2d9af5d78bf27906cafb7 Mon Sep 17 00:00:00 2001
From: Benjamin Drung <[email protected]>
Date: Fri, 10 Mar 2017 14:13:49 +0100
Subject: [PATCH] Add dump-core script

Some users might want to store core dumps in the same place as kernel
dumps (especially when storing them on a remote machine). To avoid
having to configure two scripts, add a dump-core script to kdump-tools.
It will use the same configuration file as kdump-tools.

Set /proc/sys/kernel/core_pattern to pipe the core dumps to dump-core.
You can use following sysctl configuration file:

  $ cat /etc/sysctl.d/50-dump-core.conf
  kernel.core_pattern = |/usr/share/kdump-tools/dump-core %p %s %t %e
  # 2 = "suidsafe": Any binary which normally would not be dumped (see "0")
  # is dumped readable by root only.
  fs.suid_dumpable = 2
  $ sysctl -p /etc/sysctl.d/50-dump-core.conf

Closes: #857300
---
 debian/dump-core           | 330 +++++++++++++++++++++++++++++++++++++++++++++
 debian/kdump-tools.install |   1 +
 2 files changed, 331 insertions(+)
 create mode 100755 debian/dump-core

diff --git a/debian/dump-core b/debian/dump-core
new file mode 100755
index 0000000..203830a
--- /dev/null
+++ b/debian/dump-core
@@ -0,0 +1,330 @@
+#!/bin/bash
+set -u
+
+# Copyright (C) 2017, ProfitBricks GmbH
+# Authors: Benjamin Drung <[email protected]>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# This tool can be used to store core dumps the same way as kernel dumps.
+# Set /proc/sys/kernel/core_pattern to pipe the core dumps to this tool.
+# You can use following sysctl configuration file:
+#
+#   $ cat /etc/sysctl.d/50-dump-core.conf
+#   kernel.core_pattern = |/usr/share/kdump-tools/dump-core %p %s %t %e
+#   # 2 = "suidsafe": Any binary which normally would not be dumped (see "0")
+#   # is dumped readable by root only.
+#   fs.suid_dumpable = 2
+#   $ sysctl -p /etc/sysctl.d/50-dump-core.conf
+
+exec > >(logger -t "${0}" -p syslog.info) 2> >(logger -t "${0}" -p syslog.warn)
+
+if test "$#" -ne 4; then
+	echo "called with incorrect number of arguments: '$@'." >&2
+	echo "Expected 4 arguments: pid, signal, timestamp, executable (core_pattern arguments: %p %s %t %e)." >&2
+	exit 1
+fi
+
+PID="$1"
+SIGNAL="$2"
+TIMESTAMP="$3"
+PROGRAM="$4"
+echo "called for pid $PID, signal $SIGNAL, timestamp $TIMESTAMP, executable $PROGRAM"
+
+# Global Setup
+KDUMP_DEFAULTS=/etc/default/kdump-tools
+[ -r $KDUMP_DEFAULTS ] && . $KDUMP_DEFAULTS
+
+# Set up defaults
+KDUMP_COREDIR=${KDUMP_COREDIR:=/var/crash}
+NFS_TIMEO=${NFS_TIMEO:=600}
+NFS_RETRANS=${NFS_RETRANS:=3}
+KDUMP_STAMP="${PROGRAM}-sig${SIGNAL}-$(date -u -d @$TIMESTAMP +%Y%m%d%H%M%S)"
+
+
+#
+# Return the name of the subdirectory to store core file.
+#	Will add hostname/IP according to the value of
+#	HOSTTAG if networked dump is selected
+
+define_stampdir()
+{
+	STAMP=$1
+	HOSTTAG="${HOSTTAG:=ip}"
+
+	if [ -z "${SSH-}" ] && [ -z "${NFS-}" ] && [ -z "${FTP-}" ]; then
+		echo "$KDUMP_COREDIR/$STAMP"
+	elif [ "$HOSTTAG" = "hostname" ];then
+		echo "$KDUMP_COREDIR/$(hostname)-$STAMP"
+	else
+		# Looping to give time to network to settle
+		local counter=0
+		while [ $counter -lt 5 ];do
+			THIS_HOST="$(ip addr show up | grep -w inet | tail -n1 | awk '{print $2}' | cut -f1  -d'/')"
+			set -- $THIS_HOST
+			THIS_HOST=$1
+			if [ -z "$THIS_HOST" ]; then
+				sleep 1
+				counter=$(($counter + 1))
+			else
+				break
+			fi
+		done
+		if [ -z "$THIS_HOST" ]; then
+			# Send log msg to stderr to avoid polluting
+			# the result of the function
+			echo "Unable to get IP from network" >&2
+			echo "Reverting to HOSTTAG=hostname" >&2
+			THIS_HOST="$(hostname)"
+		fi
+		echo "$KDUMP_COREDIR/$THIS_HOST-$STAMP"
+	fi
+}
+
+compress() {
+	if [ "$KDUMP_COMPRESSION" = "bzip2" ]; then
+		bzip2 -c
+	elif [ "$KDUMP_COMPRESSION" = "gzip" ]; then
+		gzip -c
+	elif [ "$KDUMP_COMPRESSION" = "lz4" ]; then
+		lz4 -c
+	elif [ "$KDUMP_COMPRESSION" = "xz" ]; then
+		/usr/bin/xz -c
+	else
+		cat
+	fi
+}
+
+compression_extension() {
+	if [ "$KDUMP_COMPRESSION" = "bzip2" ]; then
+		echo ".bz2"
+	elif [ "$KDUMP_COMPRESSION" = "gzip" ]; then
+		echo ".gz"
+	elif [ "$KDUMP_COMPRESSION" = "lz4" ]; then
+		echo ".lz4"
+	elif [ "$KDUMP_COMPRESSION" = "xz" ]; then
+		echo ".xz"
+	fi
+}
+
+collect_metadata() {
+	# Collect metadata information using apport's crash file format.
+	# See http://bazaar.launchpad.net/~apport-hackers/apport/trunk/view/head:/doc/data-format.tex
+	local coredump_file="$1"
+	. /etc/os-release
+	local executable_path=$(readlink /proc/$PID/exe)
+	local package=$(dpkg -S $executable_path | sed -s 's/:.*$//')
+	local package_version=$(dpkg -s $package | sed -n 's/Version: //p')
+	if dpkg -s $package | grep -q '^Source:'; then
+		local source_package=$(dpkg -s $package | sed -n 's/Source: //p')
+	else
+		local source_package=$package
+	fi
+	local dependencies=$(apt-cache --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --recurse --installed depends ${package}=${package_version} | sed -n 's/.*: //p' | sort | uniq)
+	cat <<EOF
+ProblemType: Crash
+Architecture: $(dpkg --print-architecture)
+CoreDumpFile: ${coredump_file##*/}
+Date: $(date -d @$TIMESTAMP -R)
+DistroRelease: ${NAME} ${VERSION_ID}
+ExecutablePath: ${executable_path}
+Host: $(uname -n)
+Package: ${package} ${package_version}
+ProcCmdline: $(sed 's/ /\\ /g' /proc/$PID/cmdline | tr '\0' ' ' | sed 's/ *$//')
+Signal: ${SIGNAL}
+SourcePackage: ${source_package}
+Uname: $(uname -srm)
+Dependencies:
+$(dpkg-query -f=' ${Package} ${Version}\n' -W $dependencies)
+ProcStatus:
+$(sed 's/^/ /' /proc/$PID/status)
+ProcMaps:
+$(sed 's/^/ /' /proc/$PID/maps)
+EOF
+}
+
+dump_local()
+{
+	KDUMP_STAMPDIR=$(define_stampdir $KDUMP_STAMP)
+	KDUMP_CORETEMP="$KDUMP_STAMPDIR/coredump-incomplete$(compression_extension)"
+	KDUMP_COREFILE="$KDUMP_STAMPDIR/coredump.$KDUMP_STAMP$(compression_extension)"
+	CRASH_FILE="$KDUMP_STAMPDIR/${KDUMP_STAMP}.crash"
+
+	# If we use NFS, verify that we can mount the FS
+	#
+	if [ -n "${NFS-}" ];then
+		echo "Mounting NFS mountpoint $NFS ..."
+		mount -t nfs -o nolock -o tcp -o soft -o timeo=${NFS_TIMEO} -o retrans=${NFS_RETRANS} $NFS $KDUMP_COREDIR
+		ERROR=$?
+		if [ $ERROR -ne 0 ];then
+			echo "Unable to mount remote NFS directory $NFS. Cannot save core dump" >&2
+			return 1;
+		fi
+
+		# FS is mounted, see if we can write to it
+		#
+		mkdir -p $KDUMP_STAMPDIR
+		ERROR=$?
+
+		if [ $ERROR -ne 0 ];then
+			echo "Unable to write to the remote NFS directory $NFS. Cannot save core dump" >&2
+			umount $KDUMP_COREDIR
+			UMNT_ERROR=$?
+			if [ $UMNT_ERROR -ne 0 ];then
+				echo "Unable to cleanly unmount the NFS file system" >&2
+			fi
+		else
+			echo "Dumping to NFS mountpoint $NFS/$KDUMP_STAMP"
+		fi
+	else
+		mkdir -p $KDUMP_STAMPDIR
+	fi
+
+	collect_metadata "$KDUMP_COREFILE" > $CRASH_FILE
+	compress > $KDUMP_CORETEMP
+	ERROR=$?
+
+	# did we succeed?
+	if [ $ERROR -eq 0 ]; then
+		mv $KDUMP_CORETEMP $KDUMP_COREFILE
+		echo "saved core dump in $KDUMP_STAMPDIR"
+		sync
+	else
+		echo "failed to save core dump in $KDUMP_STAMPDIR" >&2
+	fi
+
+	# If we use NFS, umount the remote FS
+	#
+	if [ -n "$NFS" ];then
+		umount $KDUMP_COREDIR
+		UMNT_ERROR=$?
+		if [ $UMNT_ERROR -ne 0 ] ; then
+			echo "Unable to cleanly unmount the NFS file system" >&2
+		fi
+	fi
+
+	return $ERROR
+}
+
+dump_to_ftp()
+{
+	KDUMP_REMOTE_HOST="${FTP%%:*}"
+	local fqdn=$(host "${KDUMP_REMOTE_HOST}" | grep -v "not found" | tail -n 1 | cut -d " " -f 1 || echo "${KDUMP_REMOTE_HOST}")
+	KDUMP_COREDIR="${FTP#*:}"
+	if [ "$KDUMP_COREDIR" = "$FTP" ]; then
+		# No colon in FTP specified. Assuming / as path
+		KDUMP_COREDIR="/"
+	fi
+
+	KDUMP_STAMPDIR=$(define_stampdir "")
+
+	KDUMP_COREFILE="${KDUMP_STAMPDIR}$KDUMP_STAMP$(compression_extension)"
+	CRASH_FILE="${KDUMP_STAMPDIR}${KDUMP_STAMP}.crash"
+	ERROR=0
+
+	FTPPUT_ARGS=""
+	if [ -n "${FTP_USER-}" ]; then
+		FTPPUT_ARGS="$FTPPUT_ARGS -u $FTP_USER"
+	fi
+	if [ -n "${FTP_PASSWORD-}" ]; then
+		FTPPUT_ARGS="$FTPPUT_ARGS -p $FTP_PASSWORD"
+	fi
+	if [ -n "${FTP_PORT-}" ]; then
+		FTPPUT_ARGS="$FTPPUT_ARGS -P $FTP_PORT"
+	fi
+
+	# save meta-data
+	collect_metadata "$KDUMP_COREFILE" | busybox ftpput $FTPPUT_ARGS $KDUMP_REMOTE_HOST $CRASH_FILE -
+	ERROR=$?
+	# did we succeed?
+	if [ $ERROR == 0 ]; then
+		echo "saved crash meta-data via FTP in $fqdn:$CRASH_FILE"
+	else
+		echo "failed to save crash meta-data via FTP in $fqdn:$CRASH_FILE" >&2
+	fi
+
+	compress | busybox ftpput $FTPPUT_ARGS $KDUMP_REMOTE_HOST $KDUMP_COREFILE -
+	ERROR=$?
+	# did we succeed?
+	if [ $ERROR -ne 0 ]; then
+		echo "failed to save vmcore via FTP in $fqdn:$KDUMP_COREFILE" >&2
+	else
+		echo "saved core dump via FTP in $fqdn:$KDUMP_COREFILE"
+	fi
+
+	return $ERROR
+}
+
+dump_to_ssh()
+{
+	KDUMP_SSH_KEY="${SSH_KEY:=/root/.ssh/kdump_id_rsa}"
+	KDUMP_REMOTE_HOST="$SSH"
+
+	KDUMP_STAMPDIR=$(define_stampdir $KDUMP_STAMP)
+
+	KDUMP_CORETEMP="$KDUMP_STAMPDIR/coredump-incomplete$(compression_extension)"
+	KDUMP_COREFILE="$KDUMP_STAMPDIR/coredump.$KDUMP_STAMP$(compression_extension)"
+	CRASH_FILE="${KDUMP_STAMPDIR}/${KDUMP_STAMP}.crash"
+	ERROR=0
+
+	ssh -i $KDUMP_SSH_KEY $KDUMP_REMOTE_HOST mkdir -p $KDUMP_STAMPDIR
+	ERROR=$?
+	# If remote connections fails, no need to continue
+	if [ $ERROR -ne 0 ] ; then
+		echo "Unable to reach remote server $KDUMP_REMOTE_HOST. No reason to continue" >&2
+		return 1
+	fi
+
+	# save meta-data
+	collect_metadata "$KDUMP_COREFILE" | ssh -i $KDUMP_SSH_KEY $KDUMP_REMOTE_HOST dd of=$CRASH_FILE
+	ERROR=$?
+	# did we succeed?
+	if [ $ERROR == 0 ]; then
+		echo "saved crash meta-data via SSH in $KDUMP_REMOTE_HOST:$CRASH_FILE"
+	else
+		echo "failed to save crash meta-data via SSH in $KDUMP_REMOTE_HOST:$CRASH_FILE" >&2
+	fi
+
+	echo "sending makedumpfile $MAKEDUMP_ARGS $vmcore_file to $KDUMP_REMOTE_HOST : $KDUMP_CORETEMP"
+	compress | ssh -i $KDUMP_SSH_KEY $KDUMP_REMOTE_HOST dd of=$KDUMP_CORETEMP
+	ERROR=$?
+	if [ $ERROR -ne 0 ] ; then
+		echo "makedumpfile scp failed. The core dump file will not be available" >&2
+	else
+		ERROR=0
+	fi
+
+	# did we succeed?
+	if [ $ERROR -ne 0 ]; then
+		echo "failed to save core dump in $KDUMP_REMOTE_HOST:$KDUMP_STAMPDIR" >&2
+		sync
+	else
+		ssh -i $KDUMP_SSH_KEY $KDUMP_REMOTE_HOST mv $KDUMP_CORETEMP $KDUMP_COREFILE
+		echo "saved vmcore in $KDUMP_REMOTE_HOST:$KDUMP_STAMPDIR"
+	fi
+
+	return $ERROR
+}
+
+if test -n "${KDUMP_TASKSET_CORES-}"; then
+	taskset -p -c "${KDUMP_TASKSET_CORES}" $$ || true
+fi
+
+if [ -n "${FTP-}" ]; then
+	dump_to_ftp
+elif [ -n "${SSH-}" ]; then
+	dump_to_ssh
+else
+	dump_local
+fi
+exit $?
diff --git a/debian/kdump-tools.install b/debian/kdump-tools.install
index 86ef7e4..fb54352 100644
--- a/debian/kdump-tools.install
+++ b/debian/kdump-tools.install
@@ -1 +1,2 @@
 debian/kdump-config	/usr/sbin
+debian/dump-core	/usr/share/kdump-tools
-- 
2.9.3

Reply via email to