#!/bin/bash # This script starts LyX, and restarts LyX if it is closed # it logs all output, including backtraces to development/keystest/out/GDB #Setting the following may give better screen shots #gconftool-2 /apps/metacity/general/compositing_manager -s -t bool true DIRNAME0=`dirname "$0"` OUTDIR="$DIRNAME0/out" ROOT_OUTDIR="$DIRNAME0/out" THIS_PID=$$ EXE_TO_TEST=src/lyx if [ ! -e "$EXE_TO_TEST" ] then echo "$EXE_TO_TEST" does not exist echo Cannot proceed exit fi #BORED_AFTER_SECS=7200 #If we have spend more than 3600 secs (an hour) replaying a file, without learning anything new, go and start looking for more bugs instead BORED_AFTER_SECS=3600 #If we have spend more than 3600 secs (an hour) replaying a file, without learning anything new, go and start looking for more bugs instead LAST_CORE="" ############################# # This section of code is LyX Specific ############################# if [ ! -e $DIRNAME0/.lyx ] then echo WARNING $DIRNAME0/.lyx does not exist echo will need to regenerate .lyx every test fi #if [ ! -e lib/doc.orig ] #then # mv lib/doc lib/doc.orig #fi kill_all_children() { kill `list_all_children.sh $1` sleep 0.1 kill -9 `list_all_children.sh $1` } ensure_cannot_print () { if [ ! -z "$REPLAYFILE" ] then return fi if lpq then echo We can print, this is bad! echo use lpadmin to stop keytest from destroying a forest. full_exit sleep 999999 ; read else echo "Phew, lpq reckons we aren't ready to print. This is a *good* thing!" fi } extras_save () { return for f in `ls lib/doc` do if [ lib/doc/$f -nt lib/doc.orig/$f -o ! -e lib/doc.orig/$f ] then #echo making doc dir $OUTDIR/$SEC.doc mkdir -p $OUTDIR/$SEC.doc cp -a lib/doc/$f $OUTDIR/$SEC.doc/ fi done } extras_prepare () { return mkdir -p lib/doc/ rm lib/doc/*.lyx cp -p lib/doc.orig/*.lyx lib/doc/ } get_crash_id () { name=`(cat $GDB | grep -o ' in lyx::[[:alnum:]:]*' ; cat $GDB | grep -o ' [ai][nt] [[:alnum:]:]*' ) | head -n3 | sed s/in// | sed 's/ //g'` echo $name | sed 's/ /__/g' } calc_confirm_file() { id=`get_crash_id` echo "$ROOT_OUTDIR/$id.reproduced" } get_pid () { sleep 3 echo getting pidof "$1" 1>&2 #PID=`ps "-u$USER" "$2" | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` PID=`ps x | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` echo "$PID" | ( grep " " > /dev/null && ( echo too many PIDs 1>&2 ; full_exit ) ) nPIDs=`echo PID "$PID" | wc -l` echo nPIDs $nPIDs 1>&2 sleep 1 echo -- if [ "$nPIDs" != "1" ] 1>&2 if test "$nPIDs" != "1" #2> /tmp/testerr then echo autolyx: Wrong number of PIDs "$nPIDs" "($1)" "($2)" 1>&2 fi echo "$PID" echo got pidof "$1" 1>&2 } clean_up () { KT_PID=`get_pid keytest.py x` kill $KT_PID sleep 0.1 kill -9 $KT_PID } full_exit() { clean_up echo attempting to exit this entire script... normal exit may just exit one function kill $THIS_PID sleep 1 echo We should not get this far sleep 1 kill -9 $THIS_PID echo We really should not get this far exit } run_gdb () { echo Starting GDB (echo " shell svn info src/ run bt shell kill $CHILD_PID shell wmctrl -l shell sleep 1 shell kill -9 $CHILD_PID " ; yes q) | HOME="$NEWHOME" gdb src/lyx 2>&1 | strings| tee $GDB echo "end run_gdb" #### gcore $GDB.core #shell wmctrl -r __renamed__ -b add,shaded #shell wmctrl -r term -b add,shaded #shell wmctrl -r term -b add,shaded #shell wmctrl -R lyx' # #shell import -window root '$GDB.png' #shell import -window root '$GDB..png' #exit } ########################### try_replay () { id=`get_crash_id` echo CRASH_ID export CONFIRM_FILE=`calc_confirm_file` if [ ! -e "$CONFIRM_FILE" ] then echo $CONFIRM_FILE does not exist echo This bug appears not to have been reproduced before echo Will try to reproduce now echo do_replay echo echo Finished attempt at replay else echo $CONFIRM_FILE exists echo This bugs has already been reproduced echo Will not attempt to reproduce again fi } do_replay() { (REPLAYFILE="$KEYCODEpure" TAIL_LINES=25 MAX_TAIL_LINES=10000 bash "$0")& TEST_PID="$!" echo Backgrounded $TEST_PID echo waiting for $TEST_PID to finish wait "$TEST_PID" } test_replayed () { test -e "$f.replay/last_crash_sec" -o -e "$f.replay/Irreproducible" } move_to_replayed () { mkdir -p $REPLAY_DIR/replayed mv $f* $REPLAY_DIR/replayed } do_queued_replays() { REPLAY_DIR=development/keytest/out/toreplay for f in `ls $REPLAY_DIR/*KEYCODEpure` do if test_replayed then move_to_replayed else #./development/keytest/killtest killall lyx sleep 1 killall -9 lyx KEYCODEpure="$f" do_replay #if test_replayed #then move_to_replayed #fi fi done } #get_pid() { # ps a | grep $1 | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//' #} do_one_test() { GDB=$OUTDIR/$SEC.GDB KEYCODE=$OUTDIR/$SEC.KEYCODE KEYCODEpure=$OUTDIR/$SEC.KEYCODEpure NEWHOME=~/kt.dir/$SEC.dir mkdir -p $NEWHOME NEWHOME=`cd $NEWHOME; pwd` echo NEWHOME $NEWHOME mkdir -p "$NEWHOME" cp -rv $DIRNAME0/.lyx "$NEWHOME"/ killall -9 lyx latex pdflatex ( sleep 9 && ps a | grep lyx echo -- 1 || full_exit LYX_PID="" i=0 echo -- while [ -z "$LYX_PID" -a 200 -gt $i ] while [ -z "$LYX_PID" -a 200 -gt $i ] do #export LYX_PID=`ps a | grep /src/lyx | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` export LYX_PID=`get_pid "/src/lyx$" ` echo LYXPID "$LYX_PID" || full_exit sleep 0.1 i=$(($i+1)) done echo `ps a | grep /src/lyx` echo -- 2 echo `ps a | grep /src/lyx | grep -v grep` echo -- 3 echo `ps a | grep /src/lyx | grep -v grep | sed 's/ [a-z].*$//'` echo -- 4 echo LYX_PID=$LYX_PID echo XA_PRIMARY | xclip -selection XA_PRIMARY echo XA_SECONDARY | xclip -selection XA_SECONDARY echo XA_CLIPBOARD | xclip -selection XA_CLIPBOARD echo -- if [ ! -z "$LYX_PID" ] if [ ! -z "$LYX_PID" ] then kill `ps a | grep keytest.py | grep -v grep | cut -c 1-5` sleep 0.2 kill -9 `ps a | grep keytest.py | grep -v grep | cut -c 1-5` while ! wmctrl -r lyx -b add,maximized_vert,maximized_horz do echo trying to maximize lyx sleep 1 done KEYTEST_OUTFILE="$KEYCODEpure" nice -19 python $DIRNAME0/keytest.py | tee $KEYCODE #echo "$!" > $NEWHOME/keytest_py.pid fi killall lyx) & CHILD_PID="$!" ls src/lyx ; sleep 1 pwd #You may want to use the following to simulate SIGFPE #(sleep 90 && killall -8 lyx) & echo TTL $TAIL_LINES extras_prepare ensure_cannot_print run_gdb # (run_gdb) & # GDBTASK_PID="$!" # (sleep 600 ; kill "$!") # echo WAITING FOR: wait $GDBTASK_PID # wait $GDBTASK_PID # echo NOLONGER waiting for: wait $GDBTASK_PID echo END gdb kill $CHILD_PID KT_PID=`get_pid keytest.py` echo KT_PID=$KT_PID kill $KT_PID sleep 0.3 kill -9 $CHILD_PID kill -9 $KT_PID # Or use "exited normally": echo END gdb2 # these tend to take up a huge amount of space: rm -rf $NEWHOME if (grep " signal SIG[^TK]" $GDB || grep KILL_FREEZE $KEYCODE) then extras_save mkdir -p $OUTDIR/save && ( ln $OUTDIR/$SEC.* $OUTDIR/save || cp $OUTDIR/$SEC.* $OUTDIR/save) LAST_CRASH_SEC=$SEC echo $LAST_CRASH_SEC > $OUTDIR/last_crash_sec if [ ! -z "$TAIL_LINES" ] then LAST_EVENT="$SEC" echo Reproducible > $OUTDIR/Reproducible fi TAIL_LINES="" if [ -z "$REPLAYFILE" ] then echo ATTEMPTING TO REPLAY try_replay else export KEYTEST_INFILE=$KEYCODEpure NUM_KEYCODES=`wc -l < $KEYCODEpure` echo NUM_KEYCODES $NUM_KEYCODES, was $LAST_NUM_KEYCODES if [ "$NUM_KEYCODES" != "$LAST_NUM_KEYCODES" ] then LAST_EVENT="$SEC" LAST_NUM_KEYCODES=$NUM_KEYCODES echo "Hooray! we have eleminated some keycodes" fi fi if [ ! -z "$AND_THEN_QUIT" ] then RESULT=1 echo RR 1 return 1 fi if [ ! -z "$LAST_CORE" ] then rm "$LAST_CORE" fi LAST_CORE="$GDB.core" else rm -rf $BAK/* mv $OUTDIR/$SEC.* $BAK/ if [ ! -z "$TAIL_LINES" ] then echo TTL3 $TAIL_LINES echo MAX_TAIL_LINES "$MAX_TAIL_LINES" TAIL_LINES=$(($TAIL_LINES*2)) echo TTL4 $TAIL_LINES if [ "$TAIL_LINES" -ge "0$MAX_TAIL_LINES" -a ! -z "$MAX_TAIL_LINES" ] then echo Giving up because $TAIL_LINES '>' $MAX_TAIL_LINES echo Irreproducible > $OUTDIR/Irreproducible full_exit fi fi if [ ! -z "$AND_THEN_QUIT" ] then RESULT=0 echo RR 0 return 0 fi echo TTL2 $TAIL_LINES fi } if [ ! -z "$1" ] then REPLAYFILE=$1 fi if [ ! -z "$REPLAYFILE" ] then echo REPLAYMODE OUTDIR="$REPLAYFILE.replay/" mkdir -p $REPLAYFILE.replay/ || full_exit export KEYTEST_INFILE=$REPLAYFILE if [ ! -e "$REPLAYFILE" ] then echo "$REPLAYFILE" does not exist echo exiting full_exit 1 fi else do_queued_replays echo RANDOM MODE fi get_pid [0-9].x-session-manager"$" x export X_PID=`get_pid [0-9].x-session-manager x` echo X_PID $X_PID export TAIL_LINES=$TAIL_LINES echo TL $TAIL_LINES BAK="$OUTDIR/backup" mkdir -p $BAK #rename other windows to avoid confusion. wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx export PATH=`cd $DIRNAME0; pwd`/path:$PATH if [ ! -z "$1" ] then SEC=`date +%s` export MAX_DROP=0 if [ ".$SCREENSHOT_OUT." = ".auto." ] then echo SCREENSHOT_OUT was $SCREENSHOT_OUT. export SCREENSHOT_OUT="$OUTDIR/$SEC.s" echo SCREENSHOT_OUT is $SCREENSHOT_OUT. #exit fi export RESULT=179 do_one_test #| tee do_one_test.log RESULT="$?" echo Ressult $RESULT kill `list_all_children.sh $$` sleep 0.1 kill -9 `list_all_children.sh $$` exit $RESULT #echo done ; sleep 1 full_exit fi ( echo TTL $TAIL_LINES LAST_EVENT=`date +%s` # Last time something interesting happened. If nothing interesting has happened for a while, we should quit. ensure_cannot_print echo X_PID $X_PID export X_PID=`get_pid [0-9].x-session-manager"$" x` echo PATH $PATH while true do echo Currently running autolyx PID=$$ if [ ! -z "$TAIL_LINES" ] then echo TAIL_LINES: "$TAIL_LINES" TAIL_FILE=$OUTDIR/tail_"$TAIL_LINES" tail -n "$TAIL_LINES" "$REPLAYFILE" > $TAIL_FILE KEYTEST_INFILE=$TAIL_FILE MAX_DROP=0 else MAX_DROP=0.2 fi export MAX_DROP SEC=`date +%s` if [ ! -z "$REPLAYFILE" ] then echo Boredom factor: $SEC-$LAST_EVENT'=' $(($SEC-$LAST_EVENT)) if [ $(($SEC-$LAST_EVENT)) -gt $BORED_AFTER_SECS ] then echo echo Is is now $SEC seconds echo The last time we managed to eliminate a keycode was at $LAST_EVENT echo We get bored after $BORED_AFTER_SECS seconds echo Giving up now. echo echo $LAST_CRASH_SEC > $OUTDIR/Finished mkdir $OUTDIR/final ln $OUTDIR/$SEC* $OUTDIR/final || cp $OUTDIR/$SEC* $OUTDIR/final CONFIRM_FILE=`calc_confirm_file` echo Reproducible > "$CONFIRM_FILE" full_exit fi else do_queued_replays fi do_one_test done kill_all_children $$ ) 2>&1 |tee $OUTDIR/log kill_all_children $$