blob: 55be48b29ca7ee06b3d41d6daf83b6d807c235ee (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
#! /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
|