#!/bin/sh # # Program: RunSafely.sh # # Synopsis: This script simply runs another program. If the program works # correctly, this script has no effect, otherwise it will do things # like print a stack trace of a core dump. It always returns # "successful" so that tests will continue to be run. # # This script funnels stdout and stderr from the program into the # fourth argument specified, and outputs a .time file which # contains a timing of the program and the program's exit code. # # If optional parameters -r -l are # specified, it execute the program remotely using rsh. # # Syntax: # # RunSafely.sh [-d ] [-r ] [-l ] [-rc ] # [-rp ] [-u ] [--show-errors] # [-n [-o ] [-e ]] # -t # # where: # is the directory where the program is executed # is the remote host to execute the program # is the username on the remote host # is the remote client used to execute the program # is the port used by the remote client # is a wrapper that the program is run under # file where standard output is written to # file where standard error output is written to # is a wrapper that is used to collect timing data # is the maximum number of seconds to let the run # is a file from which standard input is directed # is a file to which standard output and error are directed. # If -n was specified this is just used as the basename for the # .time file. # is the path to the program to run # are the arguments to pass to the program. # # If --show-errors is given, then the output file will be printed if the command # fails (returns a non-zero exit code). # The -n switch will enable "new-style" output. This means the exit status is # not appended to the output anymore and stdout and stderr may be redirected # separately. # Without -n stdout and stderr will both be written to the followed by # "exit NN" with NN being the exit status number of the program. if [ $# -lt 4 ]; then echo "./RunSafely.sh [-t ] " \ " " exit 1 fi # Save a copy of the original arguments in a string before we # clobber them with the shift command. ORIG_ARGS="$*" DIR=${0%%`basename $0`} RHOST= RFLAGS="" RCLIENT=rsh RUN_UNDER= TIMEIT= SHOW_ERRORS=0 NEW_MODE=0 STDOUT_FILE="" STDERR_FILE="" PWD=`pwd` WORKDIR="$PWD" if [ $1 = "-d" ]; then WORKDIR="$2" shift 2 fi if [ $1 = "-r" ]; then RHOST=$2 shift 2 fi if [ $1 = "-l" ]; then RFLAGS="$RFLAGS -l $2" shift 2 fi if [ $1 = "-rc" ]; then RCLIENT=$2 shift 2 fi if [ $1 = "-rp" ]; then RFLAGS="$RFLAGS -p $2" shift 2 fi if [ $1 = "-u" ]; then RUN_UNDER=$2 shift 2 fi if [ $1 = "--show-errors" ]; then SHOW_ERRORS=1 shift 1 fi if [ $1 = "-n" ]; then NEW_MODE=1 shift 1 if [ $1 = "-o" ]; then STDOUT_FILE="$2" shift 2 fi if [ $1 = "-e" ]; then STDERR_FILE="$2" shift 2 fi fi if [ $1 = "-t" ]; then TIMEIT=$2 shift 2 fi if [ "$TIMEIT" = "" ]; then echo "error: missing required argument -t for path to 'timeit'" exit 1 fi TIMELIMIT=$1 INFILE=$2 OUTFILE=$3 PROGRAM=$4 shift 4 PROG=${PROGRAM} if [ `basename ${PROGRAM}` = "lli" ]; then PROG=`basename ${PROGRAM}` fi # Run the command, timing its execution and logging the status summary to # $OUTFILE.time. COMMAND="$RUN_UNDER $PROGRAM $*" # Determine absolute paths of infiles/outfiles INFILE="$(cd $(dirname $INFILE); pwd)/$(basename $INFILE)" if [ "$STDOUT_FILE" != "" ]; then case "$STDOUT_FILE" in /*) STDOUT_FILE="$STDOUT_FILE";; *) STDOUT_FILE="$PWD/$STDOUT_FILE";; esac fi if [ "$STDERR_FILE" != "" ]; then case "$STDERR_FILE" in /*) STDERR_FILE="$STDERR_FILE";; *) STDERR_FILE="$PWD/$STDERR_FILE";; esac fi case "$OUTFILE" in /*) OUTFILE="$OUTFILE";; *) OUTFILE="$PWD/$OUTFILE";; esac # Use suffix for remotely created files. REMOTE_SUFFIX="" if [ "x$RHOST" != x ]; then REMOTE_SUFFIX=".remote" fi # Disable core file emission. TIMEITFLAGS="" TIMEITFLAGS="$TIMEITFLAGS --limit-core 0" # Set the CPU limit. We watchdog the process, so this is mostly just for # paranoia. TIMEITFLAGS="$TIMEITFLAGS --limit-cpu $TIMELIMIT" # To prevent infinite loops which fill up the disk, specify a limit on size # of files being output by the tests. # # We set the limit at 100MB. TIMEITFLAGS="$TIMEITFLAGS --limit-file-size 104857600" # Set the virtual memory limit at 800MB. TIMEITFLAGS="$TIMEITFLAGS --limit-rss-size 838860800" TIMEITFLAGS="$TIMEITFLAGS --timeout $TIMELIMIT --chdir $WORKDIR" TIMEITFLAGS="$TIMEITFLAGS --redirect-input ${INFILE}" TIMEITFLAGS="$TIMEITFLAGS --summary ${OUTFILE}.time${REMOTE_SUFFIX}" if [ "$NEW_MODE" = "0" ]; then TIMEITFLAGS="$TIMEITFLAGS --redirect-output ${OUTFILE}${REMOTE_SUFFIX}" else if [ "$STDERR_FILE" != "" ]; then TIMEITFLAGS="$TIMEITFLAGS --redirect-stderr ${STDERR_FILE}${REMOTE_SUFFIX}" fi if [ "$STDOUT_FILE" != "" ]; then TIMEITFLAGS="$TIMEITFLAGS --redirect-stdout ${STDOUT_FILE}${REMOTE_SUFFIX}" fi fi # Run the command rm -f "${OUTFILE}.time" "${OUTFILE}" "${STDOUT_FILE}" "${STDERR_FILE}" if [ "x$RHOST" = x ] ; then $TIMEIT $TIMEITFLAGS $COMMAND else rm -f "${OUTFILE}.time${REMOTE_SUFFIX}" "${OUTFILE}${REMOTE_SUFFIX}" rm -f "${STDOUT_FILE}${REMOTE_SUFFIX}" "${STDERR_FILE}${REMOTE_SUFFIX}" # Pass LLVM_PROFILE_FILE environment variable along PREFIX="" if [ "${LLVM_PROFILE_FILE}" != "" ]; then PREFIX="LLVM_PROFILE_FILE=\"$LLVM_PROFILE_FILE\" " fi # Create .command script COMMANDFILE="${OUTFILE}.command" rm -f "${COMMANDFILE}" echo "${PREFIX}${TIMEIT} $TIMEITFLAGS $COMMAND" > "${COMMANDFILE}" chmod +x "${COMMANDFILE}" ( $RCLIENT $RFLAGS $RHOST "ls ${COMMANDFILE}" ) > /dev/null 2>&1 ( $RCLIENT $RFLAGS $RHOST "${COMMANDFILE}" ) sleep 1 # Copy remote files back cp -f "${OUTFILE}.time${REMOTE_SUFFIX}" "${OUTFILE}.time" rm -f "${OUTFILE}.time${REMOTE_SUFFIX}" if [ "$NEW_MODE" = "0" ]; then cp -f "${OUTFILE}${REMOTE_SUFFIX}" "${OUTFILE}" rm -f "${OUTFILE}${REMOTE_SUFFIX}" else if [ "$STDERR_FILE" != "" ]; then cp -f "${STDERR_FILE}${REMOTE_SUFFIX}" "${STDERR_FILE}" rm -f "${STDERR_FILE}${REMOTE_SUFFIX}" fi if [ "$STDOUT_FILE" != "" ]; then cp -f "${STDOUT_FILE}${REMOTE_SUFFIX}" "${STDOUT_FILE}" rm -f "${STDOUT_FILE}${REMOTE_SUFFIX}" fi fi fi exitval=`grep '^exit ' $OUTFILE.time | sed -e 's/^exit //'` fail=yes if [ -z "$exitval" ] ; then exitval=99 echo "TEST $PROGRAM FAILED: CAN'T GET EXIT CODE!" elif test "$exitval" -eq 126 ; then echo "TEST $PROGRAM FAILED: command not executable (exit status 126)!" elif test "$exitval" -eq 127 ; then echo "TEST $PROGRAM FAILED: command not found (exit status 127)!" elif test "$exitval" -eq 128 ; then # Exit status 128 doesn't have a standard meaning, but it's unlikely # to be expected program behavior. echo "TEST $PROGRAM FAILED: exit status 128!" elif test "$exitval" -gt 128 ; then echo "TEST $PROGRAM FAILED: process terminated by signal (exit status $exitval)!" elif [ "$SHOW_ERRORS" -eq 1 -a "$exitval" -ne 0 ] ; then echo "TEST $PROGRAM FAILED: EXIT != 0" else fail=no fi if [ "$NEW_MODE" = "0" ]; then echo "exit $exitval" >> $OUTFILE fi # If we detected a failure, print the name of the test executable to the # output file. This will cause it to compare as different with other runs # of the same test even if they fail in the same way, because they'll have # different command names. if [ "${fail}" != "no" ]; then echo "RunSafely.sh detected a failure with these command-line arguments: " \ "$ORIG_ARGS" >> $OUTFILE if [ "$SHOW_ERRORS" = "1" ]; then echo "error: command failed while generating $OUTFILE" echo "---" cat $OUTFILE echo "---" fi fi # Always return "successful" so that tests will continue to be run. exit 0