137 lines
3.9 KiB
Bash
Executable File
137 lines
3.9 KiB
Bash
Executable File
#! /bin/bash
|
|
#
|
|
# wrappercheck.sh background command args ... -- command args ...
|
|
#
|
|
# Wrapper script which runs one command in the background and the
|
|
# other in the foreground. Once that second command completes, the
|
|
# first one is send a SIGINT+SIGTERM, then a SIGKILL until it terminates.
|
|
#
|
|
# Overall return code of this script is the return code of the
|
|
# foreground command or, if that is 0, the background command.
|
|
|
|
set -e
|
|
set -x
|
|
PS4='wrappercheck-$$ line ${LINENO}: '
|
|
|
|
PIDS=
|
|
|
|
trap "[ \"$PIDS\" ] && kill -TERM $PIDS" TERM
|
|
trap "[ \"$PIDS\" ] && kill -INT $PIDS" INT
|
|
|
|
DAEMON_LOG=
|
|
WAIT_FOR_DAEMON_OUTPUT=
|
|
WAIT_FOR_DBUS_DAEMON=
|
|
|
|
declare -a BACKGROUND
|
|
declare -a ENV
|
|
# parse parameters
|
|
while [ $# -gt 1 ] && [ "$1" != "--" ] ; do
|
|
case "$1" in
|
|
--daemon-log)
|
|
shift
|
|
DAEMON_LOG="$1"
|
|
;;
|
|
--wait-for-dbus-daemon)
|
|
shift
|
|
WAIT_FOR_DBUS_DAEMON="$1"
|
|
;;
|
|
--wait-for-daemon-output)
|
|
shift
|
|
WAIT_FOR_DAEMON_OUTPUT="$1"
|
|
;;
|
|
--daemon-sleep)
|
|
shift
|
|
DAEMON_SLEEP="$1"
|
|
;;
|
|
*=*)
|
|
ENV[${#ENV[*]}]="$1"
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
# gather command and its parameters
|
|
while [ $# -gt 1 ] && [ "$1" != "--" ] ; do
|
|
BACKGROUND[${#BACKGROUND[*]}]="$1"
|
|
shift
|
|
done
|
|
shift
|
|
|
|
if [ "$DAEMON_LOG" ] && [ "$WAIT_FOR_DAEMON_OUTPUT" ]; then
|
|
daemonmatches=$(grep -e "$WAIT_FOR_DAEMON_OUTPUT" "$DAEMON_LOG" | wc -l)
|
|
fi
|
|
|
|
( set +x; echo >&2 "*** starting ${BACKGROUND[0]} as background daemon, output to ${DAEMON_LOG:-stderr}" )
|
|
# We need to create a process group so that we can kill all processes started by the sub-shell.
|
|
# ${BACKGROUND[*]} is used instead of ${BACKGROUND[@]} because although the later should have
|
|
# avoided expansion of words (good!) somehow the quoting got messed up in practice (bad!).
|
|
( set -x; exec >>${DAEMON_LOG:-&2} 2>&1; exec env "${ENV[@]}" setsid /bin/bash -c "set -x -o pipefail; ${BACKGROUND[*]} 2>&1 | $(dirname $0)/logger.py" ) &
|
|
|
|
BACKGROUND_PID=$!
|
|
PIDS+="$BACKGROUND_PID"
|
|
|
|
if [ "$DAEMON_LOG" ] && [ "$WAIT_FOR_DAEMON_OUTPUT" ]; then
|
|
( set +x; echo >&2 "*** waiting for daemon to write '$WAIT_FOR_DAEMON_OUTPUT' into $DAEMON_LOG"
|
|
while kill -0 $BACKGROUND_PID 2>/dev/null &&
|
|
[ $daemonmatches -eq $(grep -e "$WAIT_FOR_DAEMON_OUTPUT" "$DAEMON_LOG" | wc -l) ]; do
|
|
sleep 1
|
|
done
|
|
)
|
|
fi
|
|
|
|
if [ "$WAIT_FOR_DBUS_DAEMON" ]; then
|
|
( set +x; echo >&2 "*** waiting for daemon to connect to D-Bus as '$WAIT_FOR_DBUS_DAEMON'"
|
|
while kill -0 $BACKGROUND_PID 2>/dev/null &&
|
|
! (dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -q "$WAIT_FOR_DBUS_DAEMON"); do
|
|
sleep 1
|
|
done
|
|
)
|
|
fi
|
|
|
|
if kill -0 $BACKGROUND_PID 2>/dev/null; then
|
|
set +e
|
|
if [ "$DAEMON_SLEEP" ]; then
|
|
( set +x; echo >&2 "*** 'sleep $DAEMON_SLEEP' for daemon to settle down" )
|
|
sleep $DAEMON_SLEEP
|
|
fi
|
|
(set -x; "$@")
|
|
RET=$?
|
|
set -e
|
|
else
|
|
echo >&2 "*** ${BACKGROUND[0]} terminated prematurely"
|
|
RET=1
|
|
fi
|
|
|
|
( set +x; echo >&2 "*** killing and waiting for ${BACKGROUND[0]}" )
|
|
if kill -INT -$BACKGROUND_PID >&2 && kill -TERM -$BACKGROUND_PID >&2 || kill -INT $BACKGROUND_PID >&2 && kill -TERM $BACKGROUND_PID >&2; then
|
|
perl -e "sleep(60); kill(9, -$BACKGROUND_PID);" &
|
|
KILL_PID=$!
|
|
else
|
|
ps x --forest >&2
|
|
KILL_PID=
|
|
fi
|
|
set +e
|
|
wait $BACKGROUND_PID
|
|
SUBRET=$?
|
|
case $SUBRET in 0|130|137|139|143) SUBRET=0;; # 130 and 143 indicate that it was killed, probably by us, which is okay
|
|
esac
|
|
SUBRET=0 # TODO: don't ignore daemon results
|
|
if [ "$KILL_PID" ]; then
|
|
msg=$(LC_ALL=C kill -KILL $KILL_PID 2>&1)
|
|
if echo "$msg" | grep -q 'No such process'; then
|
|
# Consider this a success.
|
|
SUBRET=0
|
|
else
|
|
echo "$msg"
|
|
fi
|
|
wait $KILL_PID
|
|
fi
|
|
set -e
|
|
if [ $RET = 0 ]; then
|
|
RET=$SUBRET
|
|
fi
|
|
|
|
exit $RET
|