#!/bin/bash set -e -x -u main () { parse_args "$@" if [ "$CRASHHOSTNAME" = "$(hostname f)" ] then setup_collector else setup_crash_kernel fi } parse_args () { CRASHHOSTNAME=${1:?FQDN of crash capture host} craship=$(dig +short +search "$CRASHHOSTNAME") dev=$(ip route get "$craship" | sed -rne 's,.* dev (\w+) +src .*,\1,p') driver=$(basename "$(readlink /sys/class/net/eth0/device/driver)") } setup_collector () { # Create user and service for collecting data from the network: adduser --system crash --home /var/lib/crash create_file /var/lib/crash/collector.sh <<'__SH__' #!/bin/sh umask 0177 exec cat >/var/lib/crash/core-$(date +%%s).gz __SH__ update-inetd --add '666\tstream\ttcp\tnowait\tcrash\t/var/lib/crash/collector.sh' # Make sure the port is allowed by the firewall: ucr set security/packetfilter/tcp/666/all=ACCEPT service univention-firewall restart } setup_crash_kernel () { install_kexec create_initramfs_hook create_initramfs_modules create_initramfs_script create_initramfs setup_grub setup_kernel setup_boot finish } install_kexec () { which kexec >/dev/null 2>/dev/null && return ucr set repository/online/unmaintained=yes apt-get -qq update apt-get -qq install kexec-tools } create_initramfs_hook () { create_file /etc/initramfs-tools/hooks/crash <<'__SH__' #!/bin/sh PREREQ= prereqs () { echo "$PREREQ" } case "$1" in prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /bin/ip copy_exec /bin/nc __SH__ } create_initramfs_modules () { grep -qFe "$driver" /etc/initramfs-tools/modules && return echo "$driver" >>/etc/initramfs-tools/modules update_initramfs=true } create_initramfs_script () { create_file /etc/initramfs-tools/scripts/crash <<__SH__ #!/bin/sh trap 'sh /dev/console 2>/dev/console' EXIT echo "Loading network driver '$driver'..." modprobe "$driver" echo "Configuring network interface '$dev'..." ip addr add "$(ip addr show dev "$dev" | sed -rne 's,^.*inet ([0-9./]+) brd.*,\1,p')" dev "$dev" ip link set "$dev" up ip route add default via "$(ip route list | sed -rne 's,^default via ([0-9./]+) dev .*,\1,p')" echo "Dumping crash to '$craship'..." gzip -c /proc/sysrq-trigger __SH__ } create_initramfs () { "$update_initramfs" || return ucr set initramfs/modules=dep update-initramfs -u } setup_grub () { grub=$(ucr get grub/append) case "$grub" in *crashkernel=*) ;; *) ucr set grub/append="$grub crashkernel=128M" ;; # 384M-2G:64M,2G-:128M esac } setup_kernel () { create_file /etc/sysctl.d/crash.conf 0644 <<__CONF__ kernel.hung_task_panic=0 # panic when hung task is detected kernel.panic_on_io_nmi=0 # panic on NMIs from I/O kernel.panic_on_oops=1 # panic on oops or kernel bug detection kernel.panic_on_unrecovered_nmi=1 # panic on NMIs from memory or unknown kernel.softlockup_panic=0 # panic when soft lockups are detected vm.panic_on_oom=0 # panic when out-of-memory happens __CONF__ } setup_boot () { create_file /etc/rc.local '' FORCE <<'__SH__' #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. load_crash () { [ "$(cat /sys/kernel/kexec_crash_loaded)" = 0 ] || return console=--reset-vga args='1 irqpoll maxcpus=1 reset_devices boot=crash debug break=init nosplash' set -- $(cat /proc/cmdline) while [ $# -ge 1 ] do case "$1" in blacklist=*) args="${args} $1" ;; boot=*) ;; BOOTIF=*) args="${args} $1" ;; BOOT_IMAGE=*) ;; break|break=*) ;; console=ttyS*) args="${args} $1" console=--console-serial ;; console=*) args="${args} $1" ;; crashkernel=*) ;; drop_capabilities=*) ;; fastboot|forcefsck|fsckfix) ;; loglevel=*) args="${args} $1" ;; netconsole=*) args="${args} $1" ;; nfsroot=*|ip=*) ;; panic=*) ;; quiet|verbose|debug|debug=*) ;; resume=*|resume_offset=*|noresume) ;; root=*|rootflags=*|rootfstype=*|rootdelay=*) ;; ro|rw) ;; splash|nosplash) ;; *) echo "Unknown arg '$1'" ;; esac shift done kexec -p /boot/vmlinuz-`uname -r` --initrd /boot/initrd.img-`uname -r` --append="$args" $console cat /sys/kernel/kexec_crash_loaded } load_crash : __SH__ } finish () { if [ "$(cat /sys/kernel/kexec_crash_size)" = 0 ] then echo "Now 'reboot'; after that test with 'echo c >/proc/sysrq-trigger'" else if [ "$(cat /sys/kernel/kexec_crash_loaded)" != 0 ] then kexec -p -u fi /etc/rc.local echo "Test with 'echo c >/proc/sysrq-trigger'" fi } update_initramfs=false create_file () { [ -z "${3:-}" ] && [ -f "$1" ] && return 0 cat >"$1" chmod "${2:-0755}" "$1" case "$1" in */initramfs-tools/*) update_initramfs=true ;; esac } main "$@"