#!/bin/sh # # dbginfo.sh - Tool to collect runtime, configuration, and trace information # # Copyright IBM Corp. 2002, 2018 # # s390-tools is free software; you can redistribute it and/or modify # it under the terms of the MIT license. See LICENSE for details. # # Switching to neutral locale LC_ALL=C export LC_ALL # The general name of this script readonly SCRIPTNAME="${0##*/}" ######################################## # print version info print_version() { cat </dev/null)" -ne 0; then echo "${SCRIPTNAME}: Error: You must be user root to run \"${SCRIPTNAME}\"!" exit 1 fi ####################################### # Parsing the command line # paramWORKDIR_BASE="/tmp/" while [ ${#} -gt 0 ]; do case ${1} in --help|-h) print_usage exit 0 ;; --version|-v) print_version exit 0 ;; --directory|-d) paramWORKDIR_BASE=${2} shift ;; -*|--*|*) echo echo "${SCRIPTNAME}: invalid option \"${1}\"" echo "Try '${SCRIPTNAME} --help' for more information" echo exit 1 ;; esac shift done if test -z "${paramWORKDIR_BASE}"; then echo "${SCRIPTNAME}: Error: No directory specified for data collection!" echo exit 1 fi if test ! -d "${paramWORKDIR_BASE}"; then echo "${SCRIPTNAME}: Error: The specified directory \"${paramWORKDIR_BASE}\" does not exist!" echo exit 1 fi ######################################## # Global used variables # # The base working directory readonly WORKDIR_BASE="$(echo "${paramWORKDIR_BASE}" | sed -e 's#/$##')/" # The terminal readonly TERMINAL="$(tty 2>/dev/null)" # The hostname of the system readonly SYSTEMHOSTNAME="$(hostname -s 2>/dev/null)" # The kernel release version as delivered from uname -r readonly KERNEL_RELEASE_VERSION="$(uname -r 2>/dev/null)" # The processor ID for the first processor readonly PROCESSORID="$(grep -E ".*processor 0:.*" /proc/cpuinfo | \ sed 's/.*identification[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')" # The processor version for the first processor readonly PROCESSORVERSION="$(grep -E ".*processor 0:.*" /proc/cpuinfo | \ sed 's/.*version[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')" # The current date readonly DATETIME="$(date +%Y-%m-%d-%H-%M-%S 2>/dev/null)" # The current working directory for the actual script execution if test -z "${PROCESSORID}"; then readonly WORKDIR_CURRENT="DBGINFO-${DATETIME}-${SYSTEMHOSTNAME:-localhost}" else readonly WORKDIR_CURRENT="DBGINFO-${DATETIME}-${SYSTEMHOSTNAME:-localhost}-${PROCESSORID}" fi # The current path where the collected information is put together readonly WORKPATH="${WORKDIR_BASE}${WORKDIR_CURRENT}/" # The current TAR archive that finally includes all collected information readonly WORKARCHIVE="${WORKDIR_BASE}${WORKDIR_CURRENT}.tgz" # The log file of activities from this script execution readonly LOGFILE="${WORKPATH}dbginfo.log" # The file to indicate that another instance of the script is already running readonly LOCKFILE="/tmp/${SCRIPTNAME}.lock" # File that includes output of Linux commands readonly OUTPUT_FILE_CMD="${WORKPATH}runtime.out" # File that includes output of z/VM commands (if running in z/VM) readonly OUTPUT_FILE_VMCMD="${WORKPATH}zvm_runtime.out" # File that includes content of files from sysfs readonly OUTPUT_FILE_SYSFS="${WORKPATH}sysfsfiles.out" # File that includes content of OSA OAT readonly OUTPUT_FILE_OSAOAT="${WORKPATH}osa_oat" # File that includes the output of journalctl readonly OUTPUT_FILE_JOURNALCTL="${WORKPATH}journalctl.out" # File that includes the output of OpenVSwitch readonly OUTPUT_FILE_OVS="${WORKPATH}openvswitch" # File that includes the KVM domain xml file readonly OUTPUT_FILE_XML="${WORKPATH}domain_xml" # File that includes the docker inspect output readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_inspect.out" # File that includes nvme related information readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out" # Mount point of the debug file system readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug" # The amount of steps running the whole collections readonly COLLECTION_COUNT=12 # The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1) readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1) # The kernel major revision number (e.g. '6' from 2.6.32 or '2' from 3.2.1) readonly KERNEL_MAJOR_REVISION=$(uname -r 2>/dev/null | cut -d'.' -f2) # The kernel mainor revision number (e.g. '32' from 2.6.32 or '1' from 3.2.1) readonly KERNEL_MINOR_REVISION=$(uname -r 2>/dev/null | cut -d'.' -f3 | sed 's/[^0-9].*//g') # Is this kernel supporting sysfs - since 2.4 (0=yes, 1=no) if test "${KERNEL_VERSION}" -lt 2 || ( test "${KERNEL_VERSION}" -eq 2 && test "${KERNEL_MAJOR_REVISION}" -le 4 ); then readonly LINUX_SUPPORT_SYSFS=1 else readonly LINUX_SUPPORT_SYSFS=0 fi # Is this kernel potentially using the /sys/kernel/debug feature - since 2.6.13 (0=yes, 1=no) if test "${KERNEL_VERSION}" -lt 2 || ( test "${KERNEL_VERSION}" -eq 2 && ( test "${KERNEL_MAJOR_REVISION}" -lt 6 || ( test "${KERNEL_MAJOR_REVISION}" -eq 6 && test "${KERNEL_MINOR_REVISION}" -lt 13 ))); then readonly LINUX_SUPPORT_SYSFSDBF=1 else readonly LINUX_SUPPORT_SYSFSDBF=0 fi if test "x${PROCESSORVERSION}" = "xFF" || test "x${PROCESSORVERSION}" = "xff"; then readonly RUNTIME_ENVIRONMENT=$(grep -E "VM00.*Control Program.*" /proc/sysinfo| sed 's/.*:[[:space:]]*\([[:graph:]]*\).*/\1/g') else readonly RUNTIME_ENVIRONMENT="LPAR" fi ######################################## # Collection of proc fs entries PROCFILES="\ /proc/buddyinfo\ /proc/cio_ignore\ /proc/cmdline\ /proc/cpuinfo\ /proc/crypto\ /proc/dasd/devices\ /proc/dasd/statistics\ /proc/devices\ /proc/diskstats\ /proc/driver/z90crypt\ /proc/interrupts\ /proc/iomem\ /proc/mdstat\ /proc/meminfo\ /proc/misc\ /proc/modules\ /proc/mounts\ /proc/net/vlan\ /proc/net/bonding\ /proc/partitions\ /proc/qeth\ /proc/qeth_perf\ /proc/qeth_ipa_takeover\ /proc/sched_debug\ /proc/schedstat\ /proc/service_levels\ /proc/slabinfo\ /proc/stat\ /proc/swaps\ /proc/sys/kernel\ /proc/sys/vm\ /proc/sysinfo\ /proc/version\ /proc/zoneinfo\ " # Adding files to PROCFILES in case scsi devices are available if test -e /proc/scsi; then PROCFILES="${PROCFILES}\ $(find /proc/scsi -type f -perm /444 2>/dev/null)\ " fi # Adding files to PROCFILES in case we run on Kernel 2.4 or older if test "${LINUX_SUPPORT_SYSFS}" -eq 1; then PROCFILES="${PROCFILES}\ /proc/chpids\ /proc/chandev\ /proc/ksyms\ /proc/lvm/global\ /proc/subchannels\ " fi # Adding s390dbf files to PROCFILE in case we run on Kernel lower than 2.6.13 if test "${LINUX_SUPPORT_SYSFSDBF}" -eq 1; then if test -e /proc/s390dbf; then PROCFILES="${PROCFILES}\ $(find /proc/s390dbf -type f -not -path "*/raw" -not -path "*/flush" 2>/dev/null)\ " fi fi ######################################## LOGFILES="\ /var/log/anaconda.*\ /var/log/audit\ /var/log/boot*\ /var/log/cron*\ /var/log/dmesg*\ /var/log/dracut.log*\ /var/log/IBMtape.trace\ /var/log/IBMtape.errorlog\ /var/log/libvirt\ /var/log/lin_tape.trace\ /var/log/lin_tape.errorlog\ /var/log/messages*\ /var/log/syslog*\ /var/log/sa\ /var/log/yum.log\ /var/log/openvswitch/ovs-vswitchd.log\ /var/log/openvswitch/ovsdb-server.log\ /run/docker/libcontainerd/containerd/events.log\ /run/containerd/events.log\ " ######################################## CONFIGFILES="\ /boot/grub2/grub.cfg\ /boot/zipl/active_devices.txt\ /boot/zipl/config\ /etc/*.conf\ /etc/anacrontab\ /etc/auto.*\ /etc/cron.*\ /etc/crontab\ /etc/crypttab\ /etc/default\ /etc/depmod.d\ /etc/dracut.conf.d\ /etc/exports\ /etc/fstab\ /etc/groups\ /etc/grub.d\ /etc/hosts*\ /etc/iscsi\ /etc/inittab\ /etc/libvirt\ /etc/logrotate.d\ /etc/lvm\ /etc/modprobe.conf*\ /etc/modprobe.d\ /etc/mtab\ /etc/multipath\ /etc/network\ /etc/networks\ /etc/pam.d\ /etc/profile\ /etc/profile.d\ /etc/pki/tls/openssl.cnf\ /etc/rc.d\ /etc/rc.local\ /etc/resolv.*\ /etc/rsyslog.d\ /etc/ssl/openssl.conf\ /etc/ssl/openssl.cnf\ /etc/sysconfig\ /etc/sysctl.d\ /etc/syslog*\ /etc/systemd\ /etc/udev*\ /etc/xinet.d\ /etc/*release\ $(find /lib/modules -name modules.dep 2>/dev/null)\ /etc/docker\ /lib/systemd/system/docker.service\ /usr/lib/systemd/system/docker.service\ /etc/apparmor.d\ " ######################################## CMDS="uname -a\ :uptime\ :runlevel\ :iptables -L\ :ulimit -a\ :ps -emo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\ :ps -eHo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\ :ps axX\ :dmesg -s 1048576\ :last\ :lsshut\ :ifconfig -a\ :nm-tool\ :route -n\ :ip route list\ :ip route list table all\ :ip rule list\ :ip neigh list\ :ip link show\ :ip ntable\ :ip a sh\ :firewall-cmd --list-all\ :ipcs -a\ :netstat -pantu\ :netstat -s\ :dmsetup ls\ :dmsetup ls --tree\ :dmsetup table\ :dmsetup table --target multipath\ :dmsetup status\ :multipathd -k'show config'\ :multipathd -k'show maps'\ :multipathd -k'show topo'\ :multipathd -k'show paths'\ :multipathd -k'show maps stats'\ :multipathd -k'show maps status'\ :multipathd -k'show status'\ :multipathd -k'show daemon'\ :multipathd -k'show blacklist'\ :multipathd -k'show devices'\ :multipath -v6 -ll\ :multipath -d\ :multipath -t\ :lsqeth\ :lschp\ :lscss\ :lscpu -ae\ :lsmem\ :lsdasd\ :lsdasd -u\ :ziorep_config -ADM\ :lsmod\ :lsdev\ :lsscsi\ :lstape\ :lszfcp\ :lszfcp -D\ :lszfcp -V\ :icainfo\ :icastats\ :lszcrypt -VV\ :ivp.e\ :pkcsconf -mlist\ :cat /var/lib/opencryptoki/pk_config_data\ :ls -al /usr/lib64/opencryptoki/stdll\ :SPident\ :rpm -qa | sort\ :sysctl -a\ :lsof\ :mount\ :df -h\ :df -i\ :pvpath -qa\ :find /boot -print0 | sort -z | xargs -0 -n 10 ls -ld\ :find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\ :java -version\ :cat /root/.bash_history\ :env\ :journalctl --all --no-pager --since=$(date -d '5 day ago' +%Y-%m-%d) --until=now --lines=50000 \ > '${OUTPUT_FILE_JOURNALCTL}'\ :openssl engine\ :systemd-delta\ :systemctl --all --no-pager show\ :systemctl --all --no-pager list-units\ :systemctl --all --no-pager list-unit-files\ :docker info\ :docker images\ :docker network ls\ :docker ps -a\ :docker version\ :docker stats --no-stream\ :systemctl status docker.service\ " ######################################## VM_CMDS="q userid\ :q users\ :q privclass\ :q cplevel\ :q cpservice\ :q cpprot user\ :q specex\ :q ssi\ :q cpus\ :q srm\ :q vtod\ :q time full\ :q timezone\ :q loaddev\ :q v osa\ :q v dasd\ :q v crypto\ :q v fcp\ :q v pav\ :q v sw\ :q v st\ :q v nic\ :q st\ :q xstore\ :q xstore user system\ :q sxspages\ :q vmlan\ :q vswitch\ :q vswitch details\ :q vswitch access\ :q vswitch active\ :q vswitch accesslist\ :q vswitch promiscuous\ :q vswitch controller\ :q port group all active details\ :q set\ :q comm\ :q controller all\ :q fcp\ :q frames\ :q lan\ :q lan all details\ :q lan all access\ :q cache\ :q nic\ :q pav\ :q proc\ :q proc topology\ :q mt\ :q qioass\ :q spaces\ :q swch all\ :q trace\ :q mdcache\ :q alloc page\ :q alloc spool\ :q dump\ :q dumpdev\ :q reorder VMUSERID\ :q quickdsp VMUSERID\ :ind load\ :ind sp\ :ind user\ " ############################################################################### ######################################## collect_cmdsout() { local cmd local ifs_orig ifs_orig="${IFS}" pr_syslog_stdout "1 of ${COLLECTION_COUNT}: Collecting command output" IFS=: for cmd in ${CMDS}; do IFS=${ifs_orig} call_run_command "${cmd}" "${OUTPUT_FILE_CMD}" done IFS="${ifs_orig}" pr_log_stdout " " } ######################################## collect_vmcmdsout() { local vm_command local cp_command local vm_cmds local vm_userid local module_loaded local ifs_orig local cp_buffer_size local rc_buffer_size module_loaded=1 ifs_orig="${IFS}" if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output" if which vmcp >/dev/null 2>&1; then cp_command="vmcp" if ! lsmod 2>/dev/null | grep -q vmcp && modinfo vmcp >/dev/null 2>&1; then modprobe vmcp && module_loaded=0 && sleep 2 fi elif which hcp >/dev/null 2>&1; then cp_command="hcp" if ! lsmod 2>/dev/null | grep -q cpint; then modprobe cpint && module_loaded=0 && sleep 2 fi else pr_log_stdout " " pr_log_stdout "${SCRIPTNAME}: Warning: No program found to communicate to z/VM CP" pr_log_stdout " Skipping collection of z/VM command output" pr_log_stdout " " return 1 fi vm_userid=$(${cp_command} q userid 2>/dev/null | sed -ne 's/^\([^[:space:]]*\).*$/\1/p') vm_cmds=$(echo "${VM_CMDS}" | sed "s/VMUSERID/${vm_userid}/g") IFS=: for vm_command in ${vm_cmds}; do IFS="${ifs_orig}" cp_buffer_size=2 rc_buffer_size=2 while test ${rc_buffer_size} -eq 2 && test ${cp_buffer_size} -lt 1024; do cp_buffer_size=$(( cp_buffer_size * 2 )) eval ${cp_command} -b ${cp_buffer_size}k "${vm_command}" >/dev/null 2>&1 rc_buffer_size=$? done call_run_command "${cp_command} -b ${cp_buffer_size}k ${vm_command}" "${OUTPUT_FILE_VMCMD}" IFS=: done IFS=${ifs_orig} if test ${module_loaded} -eq 0 && test "x${cp_command}" = "xhcp"; then rmmod cpint elif test ${module_loaded} -eq 0 && test "x${cp_command}" = "xvmcp"; then rmmod vmcp fi else pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output skipped - no z/VM environment" fi pr_log_stdout " " } ######################################## collect_procfs() { local file_name pr_syslog_stdout "3 of ${COLLECTION_COUNT}: Collecting procfs" for file_name in ${PROCFILES}; do call_collect_file "${file_name}" done pr_log_stdout " " } ######################################## collect_sysfs() { local debugfs_mounted local dir_name local file_name debugfs_mounted=0 # Requires kernel version newer then 2.4 if test "${LINUX_SUPPORT_SYSFS}" -eq 0; then pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs" # Requires kernel version of 2.6.13 or newer if test "${LINUX_SUPPORT_SYSFSDBF}" -eq 0; then if ! grep -qE "${MOUNT_POINT_DEBUGFS}.*debugfs" /proc/mounts 2>/dev/null; then if mount -t debugfs debugfs "${MOUNT_POINT_DEBUGFS}" >/dev/null 2>&1; then sleep 2 debugfs_mounted=1 else pr_log_stdout "${SCRIPTNAME}: Warning: Unable to mount debugfs at \"${MOUNT_POINT_DEBUGFS}\"" fi fi fi # Collect sysfs files using multiple threads (-J 1) while excluding # files known to block on read (-x). Stop reading a file that takes # more than 5 seconds (-T 5) such as an active ftrace buffer. dump2tar /sys -z -o "${WORKPATH}/sysfs.tgz" -x '*/tracing/trace_pipe*' \ -x '*/tracing/per_cpu/*' --ignore-failed-read -J 1 -T 5 if [ $? -ne 0 ] ; then echo "${SCRIPTNAME}: Warning: dump2tar failed or is unavailable - falling back to slow path" call_run_command "find /sys -print0 | sort -z | xargs -0 -n 10 ls -ld" "${OUTPUT_FILE_SYSFS}" find /sys -noleaf -type d 2>/dev/null | while IFS= read -r dir_name; do mkdir -p "${WORKPATH}${dir_name}" done find /sys -noleaf -type f -perm /444\ -a -not -name "*trace_pipe*"\ 2>/dev/null | while IFS= read -r file_name; do echo " ${file_name}" if ! dd if="${file_name}" status=noxfer iflag=nonblock of="${WORKPATH}${file_name}" >/dev/null 2>&1; then echo "${SCRIPTNAME}: Warning: failed to copy \"${file_name}\"" fi done fi if test ${debugfs_mounted} -eq 1; then umount "${MOUNT_POINT_DEBUGFS}" fi else pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs skipped. Kernel $(uname -r) must be newer than 2.4" fi pr_log_stdout " " } ######################################## collect_logfiles() { local file_name pr_syslog_stdout "5 of ${COLLECTION_COUNT}: Collecting log files" for file_name in ${LOGFILES}; do call_collect_file "${file_name}" done pr_log_stdout " " } ######################################## collect_configfiles() { local file_name pr_syslog_stdout "6 of ${COLLECTION_COUNT}: Collecting config files" for file_name in ${CONFIGFILES}; do call_collect_file "${file_name}" done pr_log_stdout " " } ######################################## collect_osaoat() { local network_devices local network_device network_devices=$(lsqeth 2>/dev/null | grep "Device name" \ | sed 's/.*:[[:space:]]\+\([^[:space:]]*\)[[:space:]]\+/\1/g') if which qethqoat >/dev/null 2>&1; then if test -n "${network_devices}"; then pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output" for network_device in ${network_devices}; do call_run_command "qethqoat ${network_device}" "${OUTPUT_FILE_OSAOAT}.out" && call_run_command "qethqoat -r ${network_device}" "${OUTPUT_FILE_OSAOAT}_${network_device}.raw" done else pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - no devices" fi else pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - not available" fi pr_log_stdout " " } ######################################## # OpenVSwitch collect_ovs() { local br_list local ovscmd local bridge local ovsbrcmd local ovscmds local ovsbrcmds br_list=$(ovs-vsctl list-br) ovscmds="ovs-dpctl -s show\ :ovs-vsctl -t 5 show\ :ovsdb-client dump\ " if test -n "${br_list}"; then pr_syslog_stdout "8 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output" IFS=: for ovscmd in ${ovscmds}; do IFS=${ifs_orig} call_run_command "${ovscmd}" "${OUTPUT_FILE_OVS}.out" done IFS="${ifs_orig}" for bridge in ${br_list}; do ovsbrcmds="ovs-ofctl show ${bridge}\ :ovs-ofctl dump-flows ${bridge}\ :ovs-appctl fdb/show ${bridge}\ " IFS=: for ovsbrcmd in ${ovsbrcmds}; do IFS=${ifs_orig} call_run_command "${ovsbrcmd}" "${OUTPUT_FILE_OVS}.out" done IFS="${ifs_orig}" done else pr_syslog_stdout "8 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output skipped" fi pr_log_stdout " " } ######################################## collect_domain_xml() { local domain_list local domain domain_list=$(virsh list --all --name) if test -n "${domain_list}"; then pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting domain xml files" for domain in ${domain_list}; do call_run_command "virsh dumpxml ${domain}" "${OUTPUT_FILE_XML}_${domain}.xml" done else pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting domain xml files skipped" fi pr_log_stdout " " } ######################################## collect_docker() { local item_list local item # call docker inspect for all containers item_list=$(docker ps -qa) if test -n "${item_list}"; then pr_syslog_stdout "10a of ${COLLECTION_COUNT}: Collecting docker container output" for item in ${item_list}; do call_run_command "docker inspect ${item}" "${OUTPUT_FILE_DOCKER}" done else pr_syslog_stdout "10a of ${COLLECTION_COUNT}: Collecting docker container output skipped" fi # call docker inspect for all networks item_list=$(docker network ls -q) if test -n "${item_list}"; then pr_syslog_stdout "10b of ${COLLECTION_COUNT}: Collecting docker network output" for item in ${item_list}; do call_run_command "docker network inspect ${item}" "${OUTPUT_FILE_DOCKER}" done else pr_syslog_stdout "10b of ${COLLECTION_COUNT}: Collecting docker network output skipped" fi pr_log_stdout " " } ######################################## collect_nvme() { local NVME pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting nvme output" call_run_command "nvme list" "${OUTPUT_FILE_NVME}" for NVME in /dev/nvme[0-9]*; do if [ -c $NVME ]; then call_run_command "smartctl -x $NVME" "${OUTPUT_FILE_NVME}" call_run_command "nvme fw-log $NVME" "${OUTPUT_FILE_NVME}" call_run_command "nvme smart-log $NVME" "${OUTPUT_FILE_NVME}" call_run_command "nvme error-log $NVME" "${OUTPUT_FILE_NVME}" fi done pr_log_stdout " " } ######################################## post_processing() { local file_mtime local file_mtime_epoche local tmp_file local file_name pr_syslog_stdout "${COLLECTION_COUNT} of ${COLLECTION_COUNT}: Postprocessing" find "${WORKPATH}etc/libvirt/qemu/" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do file_mtime_epoche=$(stat --format=%Y "${file_name}") file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}") tmp_file=${file_name}.$$ echo " ${file_name}" if ! sed "s/\( \+passwd='\).*\('\)/\1********\2/g" "${file_name}" > "${tmp_file}"; then echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}" echo fi mv "${tmp_file}" "${file_name}" touch --time=mtime -t "${file_mtime}" "${file_name}" done find "${WORKPATH}etc/libvirt/" -name "auth.conf" 2>/dev/null | while IFS= read -r file_name; do file_mtime_epoche=$(stat --format=%Y "${file_name}") file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}") tmp_file=${file_name}.$$ echo " ${file_name}" if ! sed "s/\(password=\).*/\1********/g" "${file_name}" > "${tmp_file}"; then echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}" echo fi mv "${tmp_file}" "${file_name}" touch --time=mtime -t "${file_mtime}" "${file_name}" done find "${WORKPATH}" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do file_mtime_epoche=$(stat --format=%Y "${file_name}") file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}") tmp_file=${file_name}.$$ echo " ${file_name}" if ! sed "s/\( \+passwd='\).*\('\)/\1********\2/g" "${file_name}" > "${tmp_file}"; then echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}" echo fi mv "${tmp_file}" "${file_name}" touch --time=mtime -t "${file_mtime}" "${file_name}" done pr_log_stdout " " } ######################################## # Be aware that this output must be # redirected into a separate logfile call_run_command() { local cmd local logfile local raw_cmd cmd="${1}" logfile="${2}" raw_cmd=$(echo "${cmd}" | sed -ne 's/^\([^[:space:]]*\).*$/\1/p') echo "#######################################################" >> "${logfile}" echo "${USER}@${SYSTEMHOSTNAME:-localhost}> ${cmd}" >> "${logfile}" # check if command exists if ! which "${raw_cmd}" >/dev/null 2>&1; then # check if command is a builtin if ! command -v "${raw_cmd}" >/dev/null 2>&1; then echo "${SCRIPTNAME}: Warning: Command \"${raw_cmd}\" not available" >> "${logfile}" echo >> "${logfile}" return 1 fi fi if ! eval "${cmd}" >> "${logfile}" 2>&1; then echo "${SCRIPTNAME}: Warning: Command \"${cmd}\" failed" >> "${logfile}" echo >> "${logfile}" return 1 else echo >> "${logfile}" return 0 fi } ######################################## call_collect_file() { local directory_name local file_name file_name="${1}" echo " ${file_name}" directory_name=$(dirname "${file_name}" 2>/dev/null) if test ! -e "${WORKPATH}${directory_name}"; then mkdir -p "${WORKPATH}${directory_name}" 2>&1 fi if ! cp -r --preserve=mode,timestamps -d -L --parents "${file_name}" "${WORKPATH}" 2>&1; then return 1 else return 0 fi } ############################################################################### ######################################## # print that an instance is already running print_alreadyrunning() { print_version cat < "${LOCKFILE}" fi if ! mkdir "${WORKPATH}" 2>/dev/null; then echo "${SCRIPTNAME}: Error: Target directory \"${WORKPATH}\" already exists or" echo " \"${WORKDIR_BASE}\" does not exist!" exit 1 fi chmod 0700 "${WORKPATH}" } ######################################## # create gzip-ped tar file create_package() { local rc_tar pr_stdout "Finalizing: Creating archive with collected data" cd "${WORKDIR_BASE}" tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}" rc_tar=$? if [ $rc_tar -eq 0 ]; then chmod 0600 "${WORKARCHIVE}" pr_stdout " " pr_stdout "Collected data was saved to:" pr_stdout " >> ${WORKARCHIVE} <<" pr_stdout " " pr_stdout "Review the collected data before sending to your service organization. " pr_stdout " " elif [ $rc_tar -eq 127 ]; then pr_stdout " " pr_stdout "${SCRIPTNAME}: Error: tar command is not available!" pr_stdout " Please install the corresponding package!" else pr_stdout " " pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!" pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful." pr_stdout " Please check the directory \"${WORKDIR_BASE}\"" pr_stdout " to provide enough free available space." fi } ######################################## # Cleaning up the prepared/collected information environment_cleanup() { if ! rm -rf "${WORKPATH}" 2>/dev/null; then pr_stdout " " pr_stdout "${SCRIPTNAME}: Warning: Deletion of \"${WORKPATH}\" failed" pr_stdout " Please remove the directory manually" pr_stdout " " fi if ! rm -f "${LOCKFILE}" 2>/dev/null; then pr_stdout " " pr_stdout "${SCRIPTNAME}: Warning: Deletion of \"${WORKDIR_BASE}${SCRIPTNAME}\" failed" pr_stdout " Please remove the file manually" pr_stdout " " fi } ######################################## # Function to perform a cleanup in case of a received signal emergency_exit() { pr_stdout " " pr_stdout "${SCRIPTNAME}: Info: Data collection has been interrupted" pr_stdout " Cleanup of temporary collected data" environment_cleanup pr_stdout "${SCRIPTNAME}: Info: Emergency exit processed" pr_stdout " " logger -t "${SCRIPTNAME}" "Data collection interrupted" exit } ######################################## # Function to print to stdout when rediretion is active pr_stdout() { echo "${@}" >&8 } ######################################## # Function to print to stdout and into log file when rediretion is active pr_log_stdout() { echo "$@" echo "$@" >&8 } ######################################## # Function to print to stdout and into log file when rediretion is active pr_syslog_stdout() { echo "$@" echo "$@" >&8 logger -t "${SCRIPTNAME}" "$@" } ############################################################################### # Running the script environment_setup print_version # saving stdout/stderr and redirecting stdout/stderr into log file exec 8>&1 9>&2 >"${LOGFILE}" 2>&1 # trap on SIGHUP=1 SIGINT=2 SIGTERM=15 trap emergency_exit SIGHUP SIGINT SIGTERM pr_log_stdout "" pr_log_stdout "Hardware platform = $(uname -i)" pr_log_stdout "Kernel version = ${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION} ($(uname -r 2>/dev/null))" pr_log_stdout "Runtime environment = ${RUNTIME_ENVIRONMENT}" pr_log_stdout "" logger -t "${SCRIPTNAME}" "Starting data collection" collect_cmdsout collect_vmcmdsout # Collecting the proc file system (content is specific based on kernel version) collect_procfs # Collecting sysfs in case we run on Kernel 2.4 or newer collect_sysfs collect_logfiles collect_configfiles collect_osaoat collect_ovs collect_domain_xml collect_docker collect_nvme post_processing create_package environment_cleanup logger -t "${SCRIPTNAME}" "Data collection completed" exec 1>&8 2>&9 8>&- 9>&- #EOF