add proper error handling for all final exec calls
[hband-tools.git] / user-tools / trackrun
blob2401b224340c5b08e1f0210eb984c5a966989324
1 #!/bin/bash
3 set -e
4 set -o pipefail
5 set -u
8 true <<'EOF'
10 =pod
12 =head1 NAME
14 trackrun - Record when the given command was started and ended and expose to it in environment variables
16 =head1 SYNOPSIS
18 trackrun [<OPTIONS>] [--] <COMMAND> [<ARGS>]
20 =head1 OPTIONS
22 =over 4
24 =item -f, --full-command
26 =item -b, --command-basename (default)
28 =item -n, --name NAME
30 =item -e, --env-var ENV
32 =back
34 =head1 DESCRIPTION
36 It records when it starts COMMAND and when it ends, identifying COMMAND either by one of 4 options:
37 (1) Full command line including ARGS.
38 (2) Only the command name, COMMAND.
39 (3) By the name given by the user in NAME.
40 (4) By the environment variable given by name ENV.
42 Set B<TRACKRUN_LAST_STARTED> and B<TRACKRUN_LAST_ENDED> environments for COMMAND to the ISO 8601 representation
43 of the date and time when COMMAND was last started and ended respectively.
44 Set B<TRACKRUN_LAST_STATUS> to the status COMMAND last exited with.
45 Those are left empty if no data yet.
47 =head1 FILES
49 Store tracking data in F<~/.trackrun> directory.
51 =head1 ENVIRONMENT
53 =over 4
55 =item TRACKRUN_LAST_STARTED
57 =item TRACKRUN_LAST_ENDED
59 =item TRACKRUN_LAST_STATUS
61 =back
63 =head1 LIMITATIONS
65 Trackrun does not do locking. You may take care of it if you need using flock(1), cronrun(1), or similar.
67 =cut
69 EOF
72 cmd_id=''
73 cmd_id_by=basename
76 while [ $# -gt 0 ]
78 case "$1" in
79 --help)
80 pod2text "$0"
81 exit 0;;
82 -f|--full-command)
83 cmd_id_by=full
85 -b|--command-basename)
86 cmd_id_by=basename
88 -n|--name)
89 cmd_id_by=name
90 shift
91 cmd_id=$1
93 -e|--env-var)
94 cmd_id_by=env
95 shift
96 cmd_id=${!1}
98 --)
99 shift
100 break;;
102 echo "$0: unknown option: $1" >&1
103 exit -1;;
105 break;;
106 esac
107 shift
108 done
111 if [ $# = 0 ]
112 then
113 pod2text "$0" >&2
114 exit -1
118 declare -a cmd_args=("$@")
121 if [ -z "$cmd_id" ]
122 then
123 case "$cmd_id_by" in
124 full)
125 cmd_id=${cmd_args[*]}
127 basename)
128 cmd_id=`basename "${cmd_args[0]}"`
130 esac
134 track_dir=~/.trackrun
135 cmd_id_hash=`printf %s "$cmd_id" | md5sum | cut -c 1-32`
136 track_file=$track_dir/$cmd_id_hash
138 lookup()
140 # lookup A B C
141 # return the C-th field of the first line in stdin of which A-th field is B
142 awk -F $'\t' -v field_num="$1" -v field_val="$2" -v field_ret="$3" \
143 '{if($field_num == field_val){ print $field_ret; exit; }}'
146 mkdir -p "$track_dir"
147 export TRACKRUN_LAST_STARTED=`tac "$track_file" 2>/dev/null | lookup 1 start 2`
148 export TRACKRUN_LAST_ENDED=`tac "$track_file" 2>/dev/null | lookup 1 end 2`
149 export TRACKRUN_LAST_STATUS=`tac "$track_file" 2>/dev/null | lookup 1 end 3`
151 record()
153 printf "%s\t%(%FT%T%z)T\t%s\t%s\n" "$1" -1 "${2:-}" "${cmd_args[*]}" >> "$track_file"
156 record start
159 exec -- setsid ${cmd_args[@]}
160 exit 127
163 child_pid=$!
164 signal_handler() { interrupted=yes; }
165 trap signal_handler INT
166 while true
168 interrupted=''
169 set +e
170 wait $child_pid
171 exit_code=$?
172 set -e
173 if [ $interrupted ]
174 then
175 exit_code=''
176 kill -s INT $child_pid || true
177 else
178 break
180 done
182 record end $exit_code
184 exit $exit_code