#!/bin/bash APP_SVNID='$HeadURL$ $LastChangedRevision$' . $(ade-config ade_share_prefix)/include/ade.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load ade.sh" >&2; exit 3; } FSEB_DEFINED_ERRORS=( "KEY=FSEB_ERR_MISC; FMT=\"%s\"" ) fseb() { local ERRSTACK_REF="$1"; shift local -a NEW_DOLLAR_AT local RC LABEL STDOUT_FLAG PROGNAME # Register application-specific errors ade_register_error_types FSEB_DEFINED_ERRORS # Defaults for options STDOUT_FLAG=false # Register fseb options ade_register_options "$ERRSTACK_REF" --longoptions=stdout --callback-template="fseb_opt_handler_%s" || return $? ade_set_callbacks "$ERRSTACK_REF" fseb_usage_help fseb_version fseb_paths || return $? # Process options ade_process_options "$ERRSTACK_REF" NEW_DOLLAR_AT "$@" || return $? set -- "${NEW_DOLLAR_AT[@]}" # Argument processing [ $# -eq 0 ] || ade_show_bad_usage "$ERRSTACK_REF" # Sanity checks and derivations if [ $EUID != 0 ]; then ade_error "$ERRSTACK_REF" FSEB_ERR_MISC "you must be root to run this program" return $ADE_FAIL fi REPORT_DIR=$(fseb-config fseb_state_prefix) REPORT_FILE=$REPORT_DIR/$(date +%Y%m%d%H%M%S).log # Generate report mkdir -p $REPORT_DIR if ! $STDOUT_FLAG; then report "$ERRSTACK_REF" > $REPORT_FILE || return $? # Remove old reports ade_debug "$ERRSTACK_REF" 10 "main: deleting old reports ..." find $REPORT_DIR/ -mindepth 1 -maxdepth 1 -type f -ctime +7 \! -name newest -delete # Hardlink to newest report rm -f $REPORT_DIR/newest.log ade_debug "$ERRSTACK_REF" 10 "main: linking newest report ($REPORT_DIR/newest.log --> $REPORT_FILE) ..." ln $REPORT_FILE $REPORT_DIR/newest.log else report "$ERRSTACK_REF" || return $? fi return $ADE_OK } fseb_usage_help() { local ERRSTACK_REF="$1"; shift local USAGE_TEXT_SHORT_REF="$1"; shift local USAGE_TEXT_LONG_REF="$1"; shift eval "$USAGE_TEXT_SHORT_REF=" eval "$USAGE_TEXT_LONG_REF=" return $ADE_OK } fseb_paths() { local ERRSTACK_REF="$1"; shift local PATHLIST_REF=$1; shift eval "$PATHLIST_REF=\"\"" return $ADE_OK } fseb_version() { local ERRSTACK_REF="$1"; shift local VERSION_REF=$1; shift ade_extract_version "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF" return $ADE_OK } fseb_opt_handler_stdout() { local ERRSTACK_REF="$1"; shift STDOUT_FLAG=true return $ADE_OK } report() { local ERRSTACK_REF="$1"; shift local HASHES PROGNAME HASHES="===============================================================" # Cron doesn't put /sbin and /usr/sbin in $PATH. I don't want to use explicit # paths to everything 'cos it looks ugly. I don't want to contaminate $PATH. # So save now and restore later. OLD_PATH="$PATH" PATH=$PATH:/sbin:/usr/sbin ade_get_progname "$ERRSTACK_REF" PROGNAME # The disks are referred to again and again. Cache them. ade_debug "$ERRSTACK_REF" 10 "report: determining disk names ..." # See https://unix.stackexchange.com/questions/414305/lsblk-capture-only-the-disks # but note that KVM virtual disks are seen as major number 253 from within the VM. # Also note that, as per the link, 'lsblk -I 8' works, but relies on a version # of lsblk that is not present yet in other distros (e.g. SLES12SP3). # On halusky the lsblk command outputs /dev/sdb, which I think is an empty SD card # reader. If it remains in the list it triggers other problems in the script so # filter out. lsblk -dnp | sed -nr -e "/ 0B /d" -e "s/ +(8|253|259):.*//p" | sort > /tmp/$PROGNAME.$$.disks SECTION="Disks" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" while read DEV; do ade_debug "$ERRSTACK_REF" 10 "report: DEV=$DEV" if [ -f /sys/block/${DEV#/dev/}/device/model ]; then MODEL="$(cat /sys/block/${DEV#/dev/}/device/model)" else MODEL="virtual disk?" fi SIZE=$(blockdev --getsize64 $DEV) printf "%s %s (%d bytes)\n" $DEV "$MODEL" $SIZE done < /tmp/$PROGNAME.$$.disks echo SECTION="Partition table types" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" touch /tmp/$PROGNAME.$$.disks-with-partition-tables while read DEV; do TYPE=$(parted $DEV print 2>/dev/null | sed -n 's/^Partition Table: //p') printf "%s %s\n" "$DEV" "$TYPE" if [ $TYPE != unknown ]; then echo $DEV >> /tmp/$PROGNAME.$$.disks-with-partition-tables fi done < /tmp/$PROGNAME.$$.disks echo SECTION="MBR (gzipped & hex encoded)" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" while read DEV; do MBR=$(dd if=$BOOTDEV bs=512 count=1 2>/dev/null | gzip | perl -wlne 'print unpack( "H*", $_ );') printf "%s %s\n" "$DEV" "$MBR" done < /tmp/$PROGNAME.$$.disks-with-partition-tables echo SECTION="Partitions" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" while read DEV; do parted $DEV unit B print 2>&1 | sed -e '1,/^Number/d' -e '$d' | sed "s@^@$DEV @" done < /tmp/$PROGNAME.$$.disks-with-partition-tables echo SECTION="LVM physical volumes" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" # Discard stderr to avoid reporting on empty SD card readers. pvs 2>/dev/null | sed -e 1d -e 's/^ *//g' echo SECTION="LVM volume groups" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" vgs 2>&1 | sed -e '/VG.*#PV/d' -e 's/^ *//g' echo SECTION="LVM logical volumes" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" lvs 2>&1 | sed -e '/LV.*VG/d' -e 's/^ *//g' echo SECTION="Block device attributes" ade_debug "$ERRSTACK_REF" 10 "report: SECTION=$SECTION" printf "%s\n%.${#SECTION}s\n\n" "$SECTION" "$HASHES" # Set COLUMNS to prevent wrapping COLUMNS=400 blkid -o list | sed -e '1,2d' -e 's/ */ /g' echo rm -f /tmp/$PROGNAME.$$.disks /tmp/$PROGNAME.$$.disks-with-partition-tables PATH=$OLD_PATH return $ADE_OK } ade_main fseb "$@"