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