diff --git a/tools/hb_report.in b/tools/hb_report.in index eab91f92ed..c0bfb8ea35 100755 --- a/tools/hb_report.in +++ b/tools/hb_report.in @@ -1,672 +1,733 @@ #!/bin/sh # Copyright (C) 2007 Dejan Muhamedagic <dmuhamedagic@suse.de> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # . @sysconfdir@/ha.d/shellfuncs . $HA_NOARCHBIN/utillib.sh PROG=`basename $0` # FIXME: once this is part of the package! PROGDIR=`dirname $0` echo "$PROGDIR" | grep -qs '^/' || { test -f @sbindir@/$PROG && PROGDIR=@sbindir@ test -f $HA_NOARCHBIN/$PROG && PROGDIR=$HA_NOARCHBIN } LOGD_CF=`findlogdcf @sysconfdir@ $HA_DIR` export LOGD_CF : ${SSH_OPTS="-T"} LOG_PATTERNS="CRIT: ERROR:" PEINPUTS_PATT="peng.*PEngine Input stored" # # the instance where user runs hb_report is the master # the others are slaves # if [ x"$1" = x__slave ]; then SLAVE=1 fi # # if this is the master, allow ha.cf and logd.cf in the current dir # (because often the master is the log host) # if [ "$SLAVE" = "" ]; then [ -f ha.cf ] && HA_CF=ha.cf [ -f logd.cf ] && LOGD_CF=logd.cf fi usage() { cat<<EOF usage: hb_report -f time [-t time] [-u user] [-l file] [-p patt] [-L patt] [-e prog] [-SDC] dest -f time: time to start from -t time: time to finish at (dflt: now) -u user: ssh user to access other nodes (dflt: empty, hacluster, root) -l file: log file -p patt: regular expression to match variables to be removed; this option is additive (dflt: "passw.*") -L patt: regular expression to match in log files for analysis; this option is additive (dflt: $LOG_PATTERNS) -e prog: your favourite editor -D : don't invoke editor to write description -C : remove the destination directory -S : single node operation; don't try to start report collectors on other nodes dest : destination directory EOF [ "$1" != short ] && cat<<EOF . the multifile output is first stored in a directory {dest} of which a tarball {dest}.tar.gz is created . the time specification is as in either Date::Parse or Date::Manip, whatever you have installed; Date::Parse is preferred . we try to figure where is the logfile; if we can't, please clue us in Examples hb_report -f 2pm /tmp/report_1 hb_report -f "2007/9/5 12:30" -t "2007/9/5 14:00" /tmp/report_2 hb_report -f 1:00 -t 3:00 -l /var/log/cluster/ha-debug /tmp/report_3 hb_report -f "09sep07 2:00" -u hbadmin /tmp/report_4 hb_report -f 18:00 -p "usern.*" -p "admin.*" /tmp/report_5 . WARNING . WARNING . WARNING . WARNING . WARNING . WARNING . We try to sanitize the CIB and the peinputs files. If you have more sensitive information, please supply additional patterns yourself. The logs and the crm_mon, ccm_tool, and crm_verify output are *not* sanitized. IT IS YOUR RESPONSIBILITY TO PROTECT THE DATA FROM EXPOSURE! EOF exit } # # these are "global" variables # setvarsanddefaults() { now=`perl -e 'print time()'` # used by all DESTDIR="" FROM_TIME="" + CTS="" TO_TIME=0 HA_LOG="" UNIQUE_MSG="Mark:HB_REPORT:$now" SANITIZE="passw.*" REMOVE_DEST="" # used only by the master NO_SSH="" SSH_USER="" TRY_SSH="hacluster root" SLAVEPIDS="" NO_DESCRIPTION="" } chkdirname() { [ "$1" ] || usage short [ $# -ne 1 ] && fatal "bad directory name: $1" echo $1 | grep -qs '^/' || fatal "destination directory must be an absolute path" [ "$1" = / ] && fatal "no root here, thank you" } chktime() { [ "$1" ] || fatal "bad time specification: $2" } msgcleanup() { fatal "destination directory $DESTDIR exists, please cleanup" } nodistdirectory() { fatal "could not create the destination directory $DESTDIR" } time2str() { perl -e "use POSIX; print strftime('%x %X',localtime($1));" } # # find log files # logmarks() { sev=$1 msg=$2 c="logger -p $HA_LOGFACILITY.$sev $msg" for n in `getnodes`; do if [ "$n" = "`uname -n`" ]; then $c else [ "$ssh_good" ] && echo $c | ssh $ssh_opts $n fi done } findlog() { if [ "$HA_LOGFACILITY" ]; then findmsg $UNIQUE_MSG | awk '{print $1}' else echo ${HA_DEBUGFILE:-$HA_LOGFILE} fi } +# +# find log slices +# +findlogseg() { + logf=$1 + from_time=$2 + to_time=$3 + + FROM_LINE=`findln_by_time $logf $from_time` + if [ -z "$FROM_LINE" ]; then + warning "couldn't find line for time $from_time; corrupt log file?" + return + fi + + TO_LINE="" + if [ "$to_time" != 0 ]; then + TO_LINE=`findln_by_time $logf $to_time` + if [ -z "$TO_LINE" ]; then + warning "couldn't find line for time $to_time; corrupt log file?" + return + fi + fi +} + +cts_findlogseg() { + logf=$1 + testnum=$2 + + FROM_LINE=`grep -n "Running test.*\[$testnum\]" $logf | sed 's/:.*//'` + if [ -z "$FROM_LINE" ]; then + warning "couldn't find line for CTS test $testnum; corrupt log file?" + return + else + FROM_TIME=`linetime $logf $FROM_LINE` + fi + TO_LINE=`grep -n "Running test.*\[$((testnum+1))\]" $logf | sed 's/:.*//'` + [ "$TO_LINE" ] || + TO_LINE=`wc -l < $logf` + TO_TIME=`linetime $logf $TO_LINE` +} + # # this is how we pass environment to other hosts # dumpenv() { cat<<EOF FROM_TIME=$FROM_TIME +CTS=$CTS TO_TIME=$TO_TIME HA_LOG=$HA_LOG +MASTER_IS_HOSTLOG=$MASTER_IS_HOSTLOG DESTDIR=$DESTDIR UNIQUE_MSG=$UNIQUE_MSG SANITIZE="$SANITIZE" REMOVE_DEST="$REMOVE_DEST" EOF } send_config() { for node in `getnodes`; do [ "$node" = "$WE" ] && continue dumpenv | ssh $ssh_opts $node "mkdir -p $DESTDIR; cat > $DESTDIR/.env" done } start_remote_collectors() { for node in `getnodes`; do [ "$node" = "$WE" ] && continue ssh $ssh_opts $node "$PROGDIR/hb_report __slave $DESTDIR" | (cd $DESTDIR && tar xf -) & SLAVEPIDS="$SLAVEPIDS $!" done } # # does ssh work? # testsshuser() { if [ "$2" ]; then ssh -T -o Batchmode=yes $2@$1 true 2>/dev/null else ssh -T -o Batchmode=yes $1 true 2>/dev/null fi } findsshuser() { for u in "" $TRY_SSH; do rc=0 for n in `getnodes`; do [ "$node" = "$WE" ] && continue testsshuser $n $u || { rc=1 break } done if [ $rc -eq 0 ]; then echo $u return 0 fi done return 1 } # # the usual stuff # getbacktraces() { flist=`find_files $HA_VARLIB/cores $1 $2` [ "$flist" ] && getbt $flist > $3 } getpeinputs() { if [ "$HA_LOGFACILITY" ]; then n=`basename $3` patt=" $n $PEINPUTS_PATT" else patt="$PEINPUTS_PATT" fi flist=$( if [ -f $3/ha-log ]; then grep "$patt" $3/ha-log | awk '{print $NF}' elif [ -f $3/../ha-log ]; then # central log grep "$patt" $3/../ha-log | awk '{print $NF}' else find_files $HA_VARLIB/pengine $1 $2 fi | sed "s,$HA_VARLIB/,,g" ) [ "$flist" ] && (cd $HA_VARLIB && tar cf - $flist) | (cd $3 && tar xf -) } touch_DC_if_dc() { dc=`crmadmin -D 2>/dev/null | awk '{print $NF}'` if [ "$WE" = "$dc" ]; then touch $1/DC fi } # # some basic system info and stats # sys_info() { echo "Heartbeat version: `hb_ver`" crm_info echo "Platform: `uname`" echo "Kernel release: `uname -r`" echo "Architecture: `arch`" [ `uname` = Linux ] && echo "Distribution: `distro`" } sys_stats() { set -x uptime ps axf ps auxw top -b -n 1 netstat -i arp -an set +x } # # replace sensitive info with '****' # sanitize() { for f in $1/ha.cf $1/cib.xml $1/pengine/*; do [ -f "$f" ] && sanitize_one $f done } # # remove duplicates if files are same, make links instead # consolidate() { for n in `getnodes`; do if [ -f $1/$2 ]; then rm $1/$n/$2 else mv $1/$n/$2 $1 fi ln -s ../$2 $1/$n done } # # some basic analysis of the report # checkcrmvfy() { for n in `getnodes`; do if [ -s $1/$n/crm_verify.txt ]; then echo "WARN: crm_verify reported warnings at $n:" cat $1/$n/crm_verify.txt fi done } checkbacktraces() { for n in `getnodes`; do [ -s $1/$n/backtraces.txt ] && { echo "WARN: coredumps found at $n:" egrep 'Core was generated|Program terminated' \ $1/$n/backtraces.txt | sed 's/^/ /' } done } checklogs() { logs=`find $1 -name ha-log` [ "$logs" ] || return pattfile=`maketempfile` || fatal "cannot create temporary files" for p in $LOG_PATTERNS; do echo "$p" done > $pattfile echo "" echo "Log patterns:" for n in `getnodes`; do cat $logs | grep -f $pattfile done rm -f $pattfile } # # check if files have same content in the cluster # cibdiff() { d1=`dirname $1` d2=`dirname $2` if [ -f $d1/RUNNING -a -f $d2/RUNNING ] || [ -f $d1/STOPPED -a -f $d2/STOPPED ]; then crm_diff -c -n $1 -o $2 else echo "can't compare cibs from running and stopped systems" fi } txtdiff() { diff $1 $2 } diffcheck() { [ -f "$1" ] || { echo "$1 does not exist" return 1 } [ -f "$2" ] || { echo "$2 does not exist" return 1 } case `basename $1` in ccm_tool.txt) txtdiff $1 $2;; # worddiff? cib.xml) cibdiff $1 $2;; ha.cf) txtdiff $1 $2;; # confdiff? crm_mon.txt|sysinfo.txt) txtdiff $1 $2;; esac } analyze_one() { rc=0 node0="" for n in `getnodes`; do if [ "$node0" ]; then diffcheck $1/$node0/$2 $1/$n/$2 rc=$((rc+$?)) else node0=$n fi done return $rc } analyze() { # flist="ccm_tool.txt cib.xml crm_mon.txt ha.cf logd.cf sysinfo.txt" flist="ccm_tool.txt crm_mon.txt ha.cf logd.cf sysinfo.txt" for f in $flist; do perl -e "printf \"Diff $f... \"" ls $1/*/$f >/dev/null 2>&1 || continue if analyze_one $1 $f; then echo "OK" consolidate $1 $f else echo "varies" fi done checkcrmvfy $1 checkbacktraces $1 checklogs $1 } # # description template, editing, and other notes # mktemplate() { cat<<EOF Please edit this template and describe the issue/problem you encountered. Then, post to Linux-HA@lists.linux-ha.org or file a bug at http://old.linux-foundation.org/developer_bugzilla/ See http://linux-ha.org/ReportingProblems for detailed description on how to report problems. Thank you. Date: `date` By: $PROG $userargs Subject: [short problem description] Severity: [choose one] enhancement minor normal major critical blocking Component: [choose one] CRM LRM CCM RA fencing heartbeat comm GUI tools other Detailed description: --- [...] --- EOF if [ -f $DESTDIR/sysinfo.txt ]; then echo "Common system info found:" cat $DESTDIR/sysinfo.txt else for n in `getnodes`; do if [ -f $DESTDIR/$n/sysinfo.txt ]; then echo "System info $n:" sed 's/^/ /' $DESTDIR/$n/sysinfo.txt fi done fi } edittemplate() { if ec=`pickfirst $EDITOR vim vi emacs nano`; then $ec $1 else warning "could not find a text editor" fi } finalword() { cat<<EOF The report is saved in $DESTDIR.tar.gz. Thank you for taking time to create this report. EOF } checksize() { ls -s $DESTDIR.tar.gz | awk '$1>=100{exit 1}' || cat <<EOF NB: size of the tarball exceeds 100kb and if posted to the mailing list will have to be first approved by the moderator. Try reducing the period (use the -f and -t options). EOF } [ $# -eq 0 ] && usage # check for the major prereq for a) parameter parsing and b) # parsing logs # NO_str2time="" t=`str2time "12:00"` if [ "$t" = "" ]; then NO_str2time=1 [ "$SLAVE" ] || fatal "please install the perl Date::Parse module" fi WE=`uname -n` # who am i? THIS_IS_NODE="" getnodes | grep -wqs $WE && # are we a node? THIS_IS_NODE=1 getlogvars # # part 1: get and check options; and the destination # if [ "$SLAVE" = "" ]; then setvarsanddefaults userargs="$@" args=`getopt -o f:t:l:u:p:L:e:SDCh -- "$@"` [ $? -ne 0 ] && usage eval set -- "$args" while [ x"$1" != x ]; do case "$1" in -h) usage;; - -f) FROM_TIME=`str2time "$2"` - chktime "$FROM_TIME" "$2" - shift 2;; + -f) + if echo "$2" | grep -qs '^cts:'; then + FROM_TIME=0 # to be calculated later + CTS=`echo "$2" | sed 's/cts://'` + else + FROM_TIME=`str2time "$2"` + chktime "$FROM_TIME" "$2" + fi + shift 2 + ;; -t) TO_TIME=`str2time "$2"` chktime "$TO_TIME" "$2" - shift 2;; + shift 2 + ;; -u) SSH_USER="$2"; shift 2;; -l) HA_LOG="$2"; shift 2;; -e) EDITOR="$2"; shift 2;; -p) SANITIZE="$SANITIZE $2"; shift 2;; -L) LOG_PATTERNS="$LOG_PATTERNS $2"; shift 2;; -S) NO_SSH=1; shift 1;; -D) NO_DESCRIPTION=1; shift 1;; -C) REMOVE_DEST=1; shift 1;; --) shift 1; break;; *) usage short;; esac done [ $# -ne 1 ] && usage short DESTDIR=$1 chkdirname $DESTDIR [ "$FROM_TIME" ] || usage short fi # this only on master if [ "$SLAVE" = "" ]; then # # part 2: ssh business # # find out if ssh works ssh_good="" if [ -z "$NO_SSH" ]; then [ "$SSH_USER" ] || SSH_USER=`findsshuser` if [ $? -eq 0 ]; then ssh_good=1 if [ "$SSH_USER" ]; then ssh_opts="-l $SSH_USER $SSH_OPTS" else ssh_opts="$SSH_OPTS" fi fi fi # final check: don't run if the destination directory exists [ -d $DESTDIR ] && msgcleanup [ "$ssh_good" ] && for node in `getnodes`; do [ "$node" = "$WE" ] && continue ssh $ssh_opts $node "test -d $DESTDIR" && msgcleanup done fi if [ "$SLAVE" ]; then DESTDIR=$2 [ -d $DESTDIR ] || nodistdirectory . $DESTDIR/.env else mkdir -p $DESTDIR [ -d $DESTDIR ] || nodistdirectory fi if [ "$SLAVE" = "" ]; then # # part 3: log marks to be searched for later # important to do this now on _all_ nodes # if [ "$HA_LOGFACILITY" ]; then sev="info" cfdebug=`getcfvar debug` # prefer debuglog if set [ "$cfdebug" -a "$cfdebug" -gt 0 ] && sev="debug" logmarks $sev $UNIQUE_MSG fi -# -# part 4: start this program on other nodes -# - if [ "$ssh_good" ]; then - send_config - start_remote_collectors - else - [ `getnodes | wc -w` -gt 1 ] && - warning "ssh does not work to all nodes" - fi fi # only cluster nodes need their own directories [ "$THIS_IS_NODE" ] && mkdir -p $DESTDIR/$WE # -# part 5: find the logs and cut out the segment for the period +# part 4: find the logs and cut out the segment for the period # if [ "$HA_LOG" ]; then # log provided by the user? [ -f "$HA_LOG" ] || { # not present [ "$SLAVE" ] || # warning if not on slave warning "$HA_LOG not found; we will try to find log ourselves" HA_LOG="" } fi if [ "$HA_LOG" = "" ]; then HA_LOG=`findlog` [ "$HA_LOG" ] && cnt=`fgrep -c $UNIQUE_MSG < $HA_LOG` fi nodecnt=`getnodes | wc -w` if [ "$cnt" ] && [ $cnt -eq $nodecnt ]; then + MASTER_IS_HOSTLOG=1 info "found the central log!" - info "you can ignore warnings about missing logs" fi if [ -f "$HA_LOG" ]; then if [ "$NO_str2time" ]; then warning "a log found; but we cannot slice it" warning "please install the perl Date::Parse module" else - dumplog $HA_LOG $FROM_TIME $TO_TIME | + if [ "$CTS" ]; then + cts_findlogseg $HA_LOG $CTS + else + findlogseg $HA_LOG $FROM_TIME $TO_TIME + fi + dumplog $HA_LOG $FROM_LINE $TO_LINE | if [ "$THIS_IS_NODE" ]; then cat > $DESTDIR/$WE/ha-log else cat > $DESTDIR/ha-log # we are log server, probably fi fi else - warning "could not find the log file on $WE" + [ "$MASTER_IS_HOSTLOG" ] || + warning "could not find the log file on $WE" +fi + +# +# part 5: start this program on other nodes +# +if [ ! "$SLAVE" ]; then + if [ "$ssh_good" ]; then + send_config + start_remote_collectors + else + [ `getnodes | wc -w` -gt 1 ] && + warning "ssh does not work to all nodes" + fi fi # # part 6: get all other info (config, stats, etc) # if [ "$THIS_IS_NODE" ]; then getconfig $DESTDIR/$WE getpeinputs $FROM_TIME $TO_TIME $DESTDIR/$WE getbacktraces $FROM_TIME $TO_TIME $DESTDIR/$WE/backtraces.txt touch_DC_if_dc $DESTDIR/$WE sanitize $DESTDIR/$WE sys_info > $DESTDIR/$WE/sysinfo.txt sys_stats > $DESTDIR/$WE/sysstats.txt 2>&1 fi # # part 7: endgame: # slaves tar their results to stdout, the master waits # for them, analyses results, asks the user to edit the # problem description template, and prints final notes # if [ "$SLAVE" ]; then (cd $DESTDIR && tar cf - $WE) else wait $SLAVEPIDS analyze $DESTDIR > $DESTDIR/analysis.txt mktemplate > $DESTDIR/description.txt [ "$NO_DESCRIPTION" ] || { echo press enter to edit the problem description... read junk edittemplate $DESTDIR/description.txt } cd $DESTDIR/.. tar czf $DESTDIR.tar.gz `basename $DESTDIR` finalword checksize fi [ "$REMOVE_DEST" ] && rm -r $DESTDIR diff --git a/tools/utillib.sh b/tools/utillib.sh index 2187624d9d..0c08aa9fab 100644 --- a/tools/utillib.sh +++ b/tools/utillib.sh @@ -1,354 +1,354 @@ # Copyright (C) 2007 Dejan Muhamedagic <dmuhamedagic@suse.de> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # ha.cf/logd.cf parsing # getcfvar() { [ -f $HA_CF ] || return sed 's/#.*//' < $HA_CF | grep -w "^$1" | sed 's/^[^[:space:]]*[[:space:]]*//' } iscfvarset() { test "`getcfvar \"$1\"`" } iscfvartrue() { getcfvar "$1" | egrep -qsi "^(true|y|yes|on|1)" } getnodes() { getcfvar node } # # logging # syslogmsg() { severity=$1 shift 1 logtag="" [ "$HA_LOGTAG" ] && logtag="-t $HA_LOGTAG" logger -p ${HA_LOGFACILITY:-"daemon"}.$severity $logtag $* } # # find log destination # uselogd() { iscfvartrue use_logd && return 0 # if use_logd true iscfvarset logfacility || iscfvarset logfile || iscfvarset debugfile || return 0 # or none of the log options set false } findlogdcf() { for f in \ `which strings > /dev/null 2>&1 && strings $HA_BIN/ha_logd | grep 'logd\.cf'` \ `for d; do echo $d/logd.cf $d/ha_logd.cf; done` do if [ -f "$f" ]; then echo $f return 0 fi done return 1 } getlogvars() { savecf=$HA_CF if uselogd; then [ -f "$LOGD_CF" ] || fatal "could not find logd.cf or ha_logd.cf" HA_CF=$LOGD_CF fi HA_LOGFACILITY=`getcfvar logfacility` HA_LOGFILE=`getcfvar logfile` HA_DEBUGFILE=`getcfvar debugfile` HA_SYSLOGMSGFMT="" iscfvartrue syslogmsgfmt && HA_SYSLOGMSGFMT=1 HA_CF=$savecf } findmsg() { # this is tricky, we try a few directories syslogdir="/var/log /var/logs /var/syslog /var/adm /var/log/ha /var/log/cluster" favourites="ha-*" mark=$1 log="" for d in $syslogdir; do [ -d $d ] || continue log=`fgrep -l "$mark" $d/$favourites` && break log=`fgrep -l "$mark" $d/*` && break done 2>/dev/null echo $log } # # print a segment of a log file # str2time() { perl -e "\$time='$*';" -e ' eval "use Date::Parse"; if (!$@) { print str2time($time); } else { eval "use Date::Manip"; if (!$@) { print UnixDate(ParseDateString($time), "%s"); } } ' } getstamp() { if [ "$HA_SYSLOGMSGFMT" -o "$HA_LOGFACILITY" ]; then awk '{print $1,$2,$3}' else awk '{print $2}' | sed 's/_/ /' fi } linetime() { l=`tail -n +$2 $1 | head -1 | getstamp` str2time "$l" } findln_by_time() { logf=$1 tm=$2 first=1 last=`wc -l < $logf` while [ $first -le $last ]; do mid=$(((last+first)/2)) tmid=`linetime $logf $mid` if [ -z "$tmid" ]; then warning "cannot extract time: $logf:$mid" return fi if [ $tmid -gt $tm ]; then last=$((mid-1)) elif [ $tmid -lt $tm ]; then first=$((mid+1)) else break fi done echo $mid } + dumplog() { logf=$1 - from_time=$2 - to_time=$3 - from_line=`findln_by_time $logf $from_time` - if [ -z "$from_line" ]; then - warning "couldn't find line for time $from_time; corrupt log file?" + from_line=$2 + to_line=$3 + [ "$from_line" ] || return - fi tail -n +$from_line $logf | - if [ "$to_time" != 0 ]; then - to_line=`findln_by_time $logf $to_time` - if [ -z "$to_line" ]; then - warning "couldn't find line for time $to_time; corrupt log file?" - return - fi + if [ "$to_line" ]; then head -$((to_line-from_line+1)) else cat fi } # # find files newer than a and older than b # +isnumber() { + echo "$1" | grep -qs '^[0-9][0-9]*$' +} touchfile() { t=`maketempfile` && perl -e "\$file=\"$t\"; \$tm=$1;" -e 'utime $tm, $tm, $file;' && echo $t } find_files() { dir=$1 from_time=$2 to_time=$3 + isnumber "$from_time" && [ "$from_time" -gt 0 ] || { + warning "sorry, can't find files based on time if you don't supply time" + return + } from_stamp=`touchfile $from_time` findexp="-newer $from_stamp" - if [ "$to_time" -a "$to_time" -gt 0 ]; then + if isnumber "$to_time" && [ "$to_time" -gt 0 ]; then to_stamp=`touchfile $to_time` findexp="$findexp ! -newer $to_stamp" fi find $dir -type f $findexp rm -f $from_stamp $to_stamp } # # coredumps # findbinary() { random_binary=`which cat 2>/dev/null` # suppose we are lucky binary=`gdb $random_binary $1 < /dev/null 2>/dev/null | grep 'Core was generated' | awk '{print $5}' | sed "s/^.//;s/[.']*$//"` [ x = x"$binary" ] && return fullpath=`which $binary 2>/dev/null` if [ x = x"$fullpath" ]; then [ -x $HA_BIN/$binary ] && echo $HA_BIN/$binary else echo $fullpath fi } getbt() { which gdb > /dev/null 2>&1 || { warning "please install gdb to get backtraces" return } for corefile; do absbinpath=`findbinary $corefile` [ x = x"$absbinpath" ] && return 1 echo "====================== start backtrace ======================" ls -l $corefile gdb -batch -n -quiet -ex ${BT_OPTS:-"thread apply all bt full"} -ex quit \ $absbinpath $corefile 2>/dev/null echo "======================= end backtrace =======================" done } # # heartbeat configuration/status # iscrmrunning() { crmadmin -D >/dev/null 2>&1 } dumpstate() { crm_mon -1 | grep -v '^Last upd' > $1/crm_mon.txt cibadmin -Ql > $1/cib.xml ccm_tool -p > $1/ccm_tool.txt 2>&1 } getconfig() { [ -f $HA_CF ] && cp -p $HA_CF $1/ [ -f $LOGD_CF ] && cp -p $LOGD_CF $1/ if iscrmrunning; then dumpstate $1 touch $1/RUNNING else cp -p $HA_VARLIB/crm/cib.xml $1/ 2>/dev/null touch $1/STOPPED fi [ -f "$1/cib.xml" ] && crm_verify -V -x $1/cib.xml >$1/crm_verify.txt 2>&1 } # # remove values of sensitive attributes # # this is not proper xml parsing, but it will work under the # circumstances sanitize_xml_attrs() { sed $( for patt in $SANITIZE; do echo "-e /name=\"$patt\"/s/value=\"[^\"]*\"/value=\"****\"/" done ) } sanitize_hacf() { awk ' $1=="stonith_host"{ for( i=5; i<=NF; i++ ) $i="****"; } {print} ' } sanitize_one() { file=$1 compress="" echo $file | grep -qs 'gz$' && compress=gzip echo $file | grep -qs 'bz2$' && compress=bzip2 if [ "$compress" ]; then decompress="$compress -dc" else compress=cat decompress=cat fi tmp=`maketempfile` && ref=`maketempfile` || fatal "cannot create temporary files" touch -r $file $ref # save the mtime if [ "`basename $file`" = ha.cf ]; then sanitize_hacf else $decompress | sanitize_xml_attrs | $compress fi < $file > $tmp mv $tmp $file touch -r $ref $file rm -f $ref } # # keep the user posted # fatal() { echo "`uname -n`: ERROR: $*" >&2 exit 1 } warning() { echo "`uname -n`: WARN: $*" >&2 } info() { echo "`uname -n`: INFO: $*" >&2 } pickfirst() { for x; do which $x >/dev/null 2>&1 && { echo $x return 0 } done return 1 } # # get some system info # distro() { which lsb_release >/dev/null 2>&1 && { lsb_release -d return } relf=`ls /etc/debian_version 2>/dev/null` || relf=`ls /etc/slackware-version 2>/dev/null` || relf=`ls -d /etc/*-release 2>/dev/null` && { for f in $relf; do test -f $f && { echo "`ls $f` `cat $f`" return } done } warning "no lsb_release no /etc/*-release no /etc/debian_version" } hb_ver() { which dpkg > /dev/null 2>&1 && { dpkg-query -f '${Version}' -W heartbeat 2>/dev/null || dpkg-query -f '${Version}' -W heartbeat-2 return } which rpm > /dev/null 2>&1 && { rpm -q --qf '%{version}' heartbeat return } # more packagers? } crm_info() { $HA_BIN/crmd version 2>&1 }