blob: a0043ec72b81892e82b3228eef0c8c147c5409ee (
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
|
#! /bin/sh
#
# spawn [command [argument ...]]
#
spawn() {
set -euf
# create and change working directory
wd=`mktemp -d`
defer rmdir $wd
cd $wd
# create named pipes for the child process's stdio
mkfifo 0 1 2
defer rm 0 1 2
# spawn child process
(exec 0>&- 1>&- 2>&- 0<>0 1<>1 2<>2 "$@") &
pid=$!
# setup a trap to kill the child process if this (parent) process dies
defer kill $pid
# write child process's pid
echo $pid >pid
defer rm pid
# create dummy directory for easier debugging
mkdir -vp /tmp/dummy
ln -vsnf $wd/0 $wd/1 $wd/2 $wd/pid /tmp/dummy/
defer rm -v /tmp/dummy/0 /tmp/dummy/1 /tmp/dummy/2 /tmp/dummy/pid
# wait for the child process's
set +e
wait $pid
code=$?
set -e
# the child is already dead
cancel kill $pid
# return the same way wait did
(exit $code)
}
#
# defer [command [argument ...]]
#
# Defer execution of a command. Deferred commands are executed in LIFO
# order immediately before the script terminates. See (golang's defer
# statement for more information how this should work).
#
defer() {
defer="$*${defer+
$defer}"
trap "$defer" EXIT
}
#
# cancel [command [argument ...]]
#
# Cancel a deferred command. The arguments have to match exactly a
# prior defer call or else chaos and mayhem shall haunt thee and shi-
#
cancel() {
defer="`echo "$defer" | grep -Fxv "$*"`"
trap "$defer" EXIT
}
spawn "$@"
|