#!/bin/sh PROGNAME="dump-server-state" REPOSITORY="https://gitea.evolix.org/evolix/dump-server-state" VERSION="24.01" readonly VERSION dump_dir= rc=0 # base functions show_version() { cat <, Jérémy Lecour , Éric Morino , Brice Waegeneire , Jérémy Dubois and others. ${REPOSITORY} ${PROGNAME} comes with ABSOLUTELY NO WARRANTY.This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License v3.0 for details. END } show_help() { cat < "${dump_dir}/packages.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* pkg_info OK" else debug "* pkg_info ERROR :" debug "${last_result}" rc=10 fi last_result=$(pkg_info -m > "${dump_dir}/packages_manual.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* pkg_info -m OK" else debug "* pkg_info -m ERROR :" debug "${last_result}" rc=10 fi } task_uname() { debug "Task: uname" last_result=$(uname -a > "${dump_dir}/uname.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* uname OK" else debug "* uname ERROR" debug "${last_result}" rc=10 fi } task_uptime() { debug "Task: uptime" last_result=$(uptime > "${dump_dir}/uptime.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* uptime OK" else debug "* uptime ERROR" debug "${last_result}" rc=10 fi } task_processes() { debug "Task: Process list" last_result=$(ps auwwx > "${dump_dir}/ps.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* ps OK" else debug "* ps ERROR" debug "${last_result}" rc=10 fi pstree_bin=$(command -v pstree) if [ -n "${pstree_bin}" ]; then last_result=$(${pstree_bin} -w > "${dump_dir}/pstree.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* pstree OK" else debug "* pstree ERROR" debug "${last_result}" rc=10 fi fi } task_fstat() { debug "Task: Network status" last_result=$({ fstat | head -1 ; fstat | grep internet ; } > "${dump_dir}/fstat.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* fstat OK" else debug "* fstat ERROR" debug "${last_result}" rc=10 fi } task_netcfg() { debug "Task: Network configuration" last_result=$(ifconfig -A > "${dump_dir}/ifconfig.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* ifconfig OK" else debug "* ifconfig ERROR" debug "${last_result}" rc=10 fi last_result=$(netstat -nr > "${dump_dir}/routes.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* netstat OK" else debug "* netstat ERROR" debug "${last_result}" rc=10 fi } task_pfctl() { debug "Task : PacketFilter" last_result=$(pfctl -sa > "${dump_dir}/pfctl.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* pfctl OK" else debug "* pfctl ERROR" debug "${last_result}" rc=10 fi } task_sysctl() { debug "Task: sysctl values" sysctl_bin=$(command -v sysctl) if [ -n "${sysctl_bin}" ]; then last_result=$(${sysctl_bin} -a 2>/dev/null | sort -h > "${dump_dir}/sysctl.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* sysctl OK" else debug "* sysctl ERROR" debug "${last_result}" rc=10 fi else debug "* sysctl not found" fi } task_disks() { debug "Task: Disks" sysctl_bin=$(command -v sysctl) if [ -n "${sysctl_bin}" ]; then disks=$(${sysctl_bin} hw.disknames | grep -Eo "(wd|sd)[0-9]*") for disk in ${disks}; do disklabel_bin=$(command -v disklabel) if [ -n "${disklabel_bin}" ]; then last_result=$(${disklabel_bin} "${disk}" 2>&1 > "${dump_dir}/partitions-${disk}") last_rc=$? if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "disklabel: DIOCGDINFO: Input/output error" ]; }; then debug "* disklabel ${disk} OK" else debug "* disklabel ${disk} ERROR" debug "${last_result}" rc=10 fi else debug "* disklabel not found" fi bioctl_bin=$(command -v bioctl) if [ -n "${bioctl_bin}" ]; then last_result=$(${bioctl_bin} "${disk}" 2>&1 > "${dump_dir}/bioctl-${disk}") last_rc=$? if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "bioctl: DIOCINQ: Inappropriate ioctl for device" ]; } || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "bioctl: BIOCINQ: Input/output error" ]; }; then debug "* bioctl ${disk} OK" else debug "* bioctl ${disk} ERROR" debug "${last_result}" rc=10 fi else debug "* bioctl not found" fi atactl_bin=$(command -v atactl) if [ -n "${atactl_bin}" ]; then last_result=$(${atactl_bin} "${disk}" 2>&1 > "${dump_dir}/atactl-${disk}") last_rc=$? if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "atactl: ATA device returned error register 0" ]; } || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "atactl: ATAIOCCOMMAND failed: Input/output error" ]; }; then debug "* atactl ${disk} OK" else debug "* atactl ${disk} ERROR" debug "${last_result}" rc=10 fi else debug "* atactl not found" fi done cat "${dump_dir}"/partitions-* > "${dump_dir}/partitions" cat "${dump_dir}"/bioctl-* > "${dump_dir}/bioctl" cat "${dump_dir}"/atactl-* > "${dump_dir}/atactl" else debug "* sysctl not found" fi } task_mount() { debug "Task: Mount points" mount_bin=$(command -v mount) if [ -n "${mount_bin}" ]; then last_result=$(${mount_bin} > "${dump_dir}/mount.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* mount points OK" else debug "* mount points ERROR" debug "${last_result}" rc=10 fi else debug "* mount not found" fi } task_df() { debug "Task: df" df_bin=$(command -v df) if [ -n "${df_bin}" ]; then last_result=$(${df_bin} > "${dump_dir}/df.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* df OK" else debug "* df ERROR" debug "${last_result}" rc=10 fi else debug "* df not found" fi } task_dmesg() { debug "Task: dmesg" dmesg_bin=$(command -v dmesg) if [ -n "${dmesg_bin}" ]; then last_result=$(${dmesg_bin} > "${dump_dir}/dmesg.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* dmesg OK" else debug "* dmesg ERROR" debug "${last_result}" rc=10 fi last_result=$(${dmesg_bin} -s > "${dump_dir}/dmesg-console.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* dmesg console buffer OK" else debug "* dmesg console buffer ERROR" debug "${last_result}" rc=10 fi else debug "* dmesg not found" fi } task_rcctl() { debug "Task: Services" rcctl_bin=$(command -v rcctl) if [ -n "${rcctl_bin}" ]; then last_result=$(${rcctl_bin} ls failed > "${dump_dir}/rcctl-failed-services.txt") last_rc=$? if [ ${last_rc} -eq 0 ] || [ ${last_rc} -eq 1 ]; then debug "* failed services OK" else debug "* failed services ERROR" debug "${last_result}" rc=10 fi last_result=$(${rcctl_bin} ls on > "${dump_dir}/rcctl-on-services.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* on services OK" else debug "* on services ERROR" debug "${last_result}" rc=10 fi last_result=$(${rcctl_bin} ls started > "${dump_dir}/rcctl-started-services.txt") last_rc=$? if [ ${last_rc} -eq 0 ]; then debug "* started services OK" else debug "* started services ERROR" debug "${last_result}" rc=10 fi else debug "* rcctl not found" fi } main() { if [ -z "${dump_dir}" ]; then echo "ERROR: You must provide the --dump-dir argument" >&2 exit 1 fi if [ -d "${dump_dir}" ]; then if [ "${FORCE}" != "1" ]; then echo "ERROR: The dump directory ${dump_dir} already exists. Delete it first." >&2 exit 2 fi else create_dump_dir fi if [ "${TASK_ETC}" -eq 1 ]; then task_etc fi if [ "${TASK_PACKAGES}" -eq 1 ]; then task_packages fi if [ "${TASK_UNAME}" -eq 1 ]; then task_uname fi if [ "${TASK_UPTIME}" -eq 1 ]; then task_uptime fi if [ "${TASK_PROCESSES}" -eq 1 ]; then task_processes fi if [ "${TASK_FSTAT}" -eq 1 ]; then task_fstat fi if [ "${TASK_NETCFG}" -eq 1 ]; then task_netcfg fi if [ "${TASK_PFCTL}" -eq 1 ]; then task_pfctl fi if [ "${TASK_SYSCTL}" -eq 1 ]; then task_sysctl fi if [ "${TASK_DISKS}" -eq 1 ]; then task_disks fi if [ "${TASK_MOUNT}" -eq 1 ]; then task_mount fi if [ "${TASK_DF}" -eq 1 ]; then task_df fi if [ "${TASK_DMESG}" -eq 1 ]; then task_dmesg fi if [ "${TASK_RCCTL}" -eq 1 ]; then task_rcctl fi debug "=> Your dump is available at ${dump_dir}" exit ${rc} } # parse options # based on https://gist.github.com/deshion/10d3cb5f88a21671e17a while :; do case $1 in -h|-\?|--help) show_help exit 0 ;; -V|--version) show_version exit 0 ;; -v|--verbose) VERBOSE=1 ;; -f|--force) FORCE=1 ;; -d|--dump-dir) # with value separated by space if [ -n "$2" ]; then dump_dir=$2 shift else printf 'ERROR: "-d|--dump-dir" requires a non-empty option argument.\n' >&2 exit 1 fi ;; --dump-dir=?*) # with value speparated by = dump_dir=${1#*=} ;; --dump-dir=) # without value printf 'ERROR: "--dump-dir" requires a non-empty option argument.\n' >&2 exit 1 ;; --all) for option in \ TASK_ETC \ TASK_PACKAGES \ TASK_UNAME \ TASK_UPTIME \ TASK_PROCESSES \ TASK_FSTAT \ TASK_NETCFG \ TASK_PFCTL \ TASK_SYSCTL \ TASK_DISKS \ TASK_MOUNT \ TASK_DF \ TASK_DMESG \ TASK_RCCTL do eval "${option}=1" done ;; --none) for option in \ TASK_ETC \ TASK_PACKAGES \ TASK_UNAME \ TASK_UPTIME \ TASK_PROCESSES \ TASK_FSTAT \ TASK_NETCFG \ TASK_PFCTL \ TASK_SYSCTL \ TASK_DISKS \ TASK_MOUNT \ TASK_DF \ TASK_DMESG \ TASK_RCCTL do eval "${option}=0" done ;; --etc) TASK_ETC=1 ;; --no-etc) TASK_ETC=0 ;; --packages) TASK_PACKAGES=1 ;; --no-packages) TASK_PACKAGES=0 ;; --uname) TASK_UNAME=1 ;; --no-uname) TASK_UNAME=0 ;; --uptime) TASK_UPTIME=1 ;; --no-uptime) TASK_UPTIME=0 ;; --processes) TASK_PROCESSES=1 ;; --no-processes) TASK_PROCESSES=0 ;; --fstat) TASK_FSTAT=1 ;; --no-fstat) TASK_FSTAT=0 ;; --netcfg) TASK_NETCFG=1 ;; --no-netcfg) TASK_NETCFG=0 ;; --pfctl) TASK_PFCTL=1 ;; --no-pfctl) TASK_PFCTL=0 ;; --sysctl) TASK_SYSCTL=1 ;; --no-sysctl) TASK_SYSCTL=0 ;; --disks) TASK_DISKS=1 ;; --no-disks) TASK_DISKS=0 ;; --mount) TASK_MOUNT=1 ;; --no-mount) TASK_MOUNT=0 ;; --df) TASK_DF=1 ;; --no-df) TASK_DF=0 ;; --dmesg) TASK_DMESG=1 ;; --no-dmesg) TASK_DMESG=0 ;; --rcctl) TASK_RCCTL=1 ;; --no-rcctl) TASK_RCCTL=0 ;; --) # End of all options. shift break ;; -?*) # ignore unknown options printf 'WARN: Unknown option : %s\n' "$1" >&2 exit 1 ;; *) # Default case: If no more options then break out of the loop. break ;; esac shift done # Default values : "${VERBOSE:=0}" : "${FORCE:=0}" : "${TASK_ETC:=0}" : "${TASK_PACKAGES:=1}" : "${TASK_UNAME:=1}" : "${TASK_UPTIME:=1}" : "${TASK_PROCESSES:=1}" : "${TASK_FSTAT:=1}" : "${TASK_NETCFG:=1}" : "${TASK_PFCTL:=1}" : "${TASK_SYSCTL:=1}" : "${TASK_DISKS:=1}" : "${TASK_MOUNT:=1}" : "${TASK_DF:=1}" : "${TASK_DMESG:=1}" : "${TASK_RCCTL:=1}" export LC_ALL=C set -u main