source: tags/arb-6.0-rc1/SH/arb_launcher

Last change on this file was 11773, checked in by westram, 11 years ago
  • work around situations where ARB_PROP is undefined (can't create session log → skip it; fixes #482)
  • avoid warning ("rm: cannot remove `/home/ralf/.arb_prop/logs/20140311_143417.16245/crashed': No such file or directory")
  • Property svn:executable set to *
File size: 10.1 KB
Line 
1#!/bin/bash
2
3set -u
4
5trace() {
6    local MSG=$1
7    echo "[arb_launcher[${ARB_LAUNCHER:-}]: $1]"
8}
9debug() {
10    local MSG=$1
11    # to debug uncomment next line:
12    # trace "DEBUG: $MSG"
13}
14
15send_to_launcher() {
16    local NAMED_PIPE=$1
17    local CMD=$2
18
19    debug "Sending '$CMD' to $NAMED_PIPE"
20    echo "$CMD" >$NAMED_PIPE
21    sleep 1
22    debug "send_to_launcher terminates"
23}
24
25pipe_command() {
26    local NAMED_PIPE=$1; shift
27    local CMD=$1; shift
28    local LOGDIR=${1:-}; shift # LOGDIR may be empty/undef -> dont signal crash
29
30    trace "Starting '$CMD'.."
31    local ERROR=0
32    $CMD || ERROR=1
33
34    if [ $ERROR == 1 ]; then
35        trace "'$CMD' has terminated with error"
36        if [ -n "$LOGDIR" ]; then
37            touch $LOGDIR/crashed
38        fi
39    else
40        trace "'$CMD' has terminated with success"
41    fi
42
43    send_to_launcher $NAMED_PIPE 'cmd_terminated'
44}
45
46read_line() {
47    local NAMED_PIPE=$1
48    local LINE=""
49
50    if read ATTEMPT <$NAMED_PIPE; then
51        LINE=$ATTEMPT
52    fi
53    echo $LINE
54}
55
56listen_pipe_unlogged() {
57    local NAMED_PIPE=$1; shift
58    local LOGDIR=${1:-}; shift # LOGDIR may be empty/undef -> dont log
59    local RUNNING=1
60    local STARTED=0
61    # RUNNING is set to 1 (otherwise listen_pipe would terminate instantly)
62
63    while (($RUNNING > 0))
64      do
65      LINE=`read_line $NAMED_PIPE 2>/dev/null`
66      if [[ ! -z "$LINE" ]]; then
67          debug "'$NAMED_PIPE' received '$LINE'"
68          if [[ "$LINE" == 'TERMINATE' ]]; then
69              trace "Received request to TERMINATE"
70              break;
71          else
72              if [[ "$LINE" == 'cmd_terminated' ]]; then
73                  RUNNING=$(($RUNNING - 1))
74                  if (($RUNNING>0)); then
75                      trace "Still have $RUNNING arb processes.."
76                  fi
77              else
78                  if [[ "$LINE" == 'allow_termination' ]]; then
79                      RUNNING=$(($RUNNING - 1))
80                  else
81                      pipe_command $NAMED_PIPE "$LINE" $LOGDIR &
82                      RUNNING=$(($RUNNING + 1))
83                      STARTED=$(($STARTED + 1))
84                      debug "RUNNING=$RUNNING"
85                      debug "STARTED=$STARTED"
86                  fi
87              fi
88          fi
89      fi
90    done
91
92    if (($RUNNING==0)); then
93        if (($STARTED>0)); then
94            trace "All launched processes terminated"
95        else
96            trace "Nothing was ever launched"
97        fi
98    else
99        trace "Still have $RUNNING arb-processes - terminating nevertheless"
100    fi
101}
102
103wrapped_info() {
104    local TAG=$1; shift
105    local CMD=$1; shift
106    echo "--------------------"
107    echo "[$TAG start]"
108    bash -c "$CMD"
109    echo "[$TAG end]"
110}
111
112collect_system_information() {
113    echo "System information"
114    echo ""
115    echo "The information below has been collected by ARB."
116    echo "Please do not publish without being aware that it might contain personal information."
117    echo ""
118
119    local ARB_RELEVANT="| grep -i ARB"
120
121    wrapped_info "version info" "$ARBHOME/bin/arb_ntree --help"
122    wrapped_info "environment" "printenv $ARB_RELEVANT"
123    wrapped_info "OS info" "lsb_release -a"
124    wrapped_info "Kernel info" "uname -mrs ; uname -a ; cat /proc/version"
125    wrapped_info "glibc" "ls -l /lib/libc-*.so /lib/libc.so*"
126    wrapped_info "Disk info" "df -h"
127    wrapped_info "Memory info" "free -m ; cat /proc/meminfo"
128    wrapped_info "User limits" "ulimit -a"
129    wrapped_info "ARB processes" "ps aux $ARB_RELEVANT"
130    wrapped_info "KDE Desktop version" "konqueror --version"
131    wrapped_info "Gnome Desktop version" "gnome-panel --version"
132    wrapped_info "CPU info" "cat /proc/cpuinfo"
133    wrapped_info "X server information" "xdpyinfo"
134    # wrapped_info "X" "Y"
135}
136
137erase_old_logs() {
138    local LOGBASE=$1
139    if [ -d "$LOGBASE" ]; then
140        # remove files older than 7 days inside and below LOGBASE
141        local OLD=$(( 60 * 24 * 7 ))
142        find $LOGBASE -type f -cmin +$OLD -exec rm {} \;
143        # remove empty directories inside and below LOGBASE
144        find $LOGBASE -type d -depth -empty -mindepth 1 -exec rmdir {} \;
145    fi
146}
147
148listen_pipe() {
149    # this is just a wrapper around listen_pipe_unlogged.
150    # wrapper performs ARB session logging
151    local NAMED_PIPE=$1
152
153    if [ -z ${ARB_PROP:-} ]; then
154        # should never come here, if arb has been started via script 'arb'
155        # (e.g. happens when arb_ntree was started from debugger and then 'start second database' has been called)
156        listen_pipe_unlogged $NAMED_PIPE
157    else
158        local LOGBASE=$ARB_PROP/logs
159        local LOGDIRID=`date '+%Y%m%d_%H%M%S'`.$$
160        local LOGDIR=$LOGBASE/$LOGDIRID
161        local NTREE_CRASHED=0
162
163        mkdir -p $LOGDIR
164
165        if [ -d "$LOGDIR" ]; then
166            local RUNLOG=$LOGDIR/run.log
167            local SYSLOG=$LOGDIR/sys.info
168            local CRASHFLAG=$LOGDIR/crashed
169
170            ( ( collect_system_information 2>&1 ) > $SYSLOG ; erase_old_logs $LOGBASE ) &
171            ( listen_pipe_unlogged $NAMED_PIPE $LOGDIR ) 2>&1 | tee $RUNLOG
172
173            if [ -e $CRASHFLAG ]; then
174            # only detects crashes of arb_ntree
175            # (client are not started via arb_launcher and they usually crash when server exits)
176                NTREE_CRASHED=1
177            fi
178
179            local TARBALLNAME=session.$LOGDIRID.tgz
180            ( cd $LOGBASE ; tar -zcf $TARBALLNAME $LOGDIRID )
181            rm -f $RUNLOG $SYSLOG $CRASHFLAG
182            rmdir $LOGDIR
183
184            local FULLTARBALL=$LOGBASE/$TARBALLNAME
185            echo ""
186            echo "Session log has been stored in $FULLTARBALL"
187
188            local LATESTLINK=~/ARB_last_session.tgz
189            if [ -h $LATESTLINK ]; then
190                rm $LATESTLINK
191            fi
192            if [ -e $LATESTLINK ]; then
193                echo "$LATESTLINK already exists and is no symlink"
194            else
195                (cd ~; ln -s $FULLTARBALL $LATESTLINK )
196                echo "    and is also accessible via $LATESTLINK"
197            fi
198
199            if [ $NTREE_CRASHED == 1 ]; then
200                echo ""
201                echo "ARB crashed :-("
202                echo "To report this goto http://bugs.arb-home.de/wiki/BugReport"
203                echo "Please include the session log mentioned above"
204                echo ""
205                echo "[press ENTER]"
206                read A
207            fi
208
209            true
210        else
211            echo "Error creating directory '$LOGDIR'"
212            false
213        fi
214    fi
215}
216
217killtree() {
218    local _pid=$1
219    local _sig=${2:-TERM}
220
221    debug "killtree pid=${_pid} with sig=${_sig} pid=$$"
222    kill -stop ${_pid} # stop quickly forking parent from producing childs
223    killchilds ${_pid} ${_sig}
224    kill ${_sig} ${_pid}
225}
226killchilds() {
227    local _pid=$1
228    local _sig=${2:-TERM}
229
230    debug "killchilds pid=${_pid} with sig=${_sig} pid=$$"
231    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
232        killtree ${_child} ${_sig}
233    done
234}
235
236term_handler() {
237    local NAMED_PIPE=$1
238
239    trace "Killing ARB session for ARB_PID=$ARB_PID"
240    arb_clean session
241    debug "arb_clean done - now killing process tree"
242    killchilds $$ -TERM
243    debug "killchilds done - exiting $$"
244    exit
245}
246
247create_pipe_reader() {
248    local NAMED_PIPE=$1
249    local PARENT_PID=$2
250
251    if [ -z "${ARB_LAUNCHER:-}" ]; then
252        export ARB_LAUNCHER=0
253    else
254        export ARB_LAUNCHER=$(($ARB_LAUNCHER+1))
255    fi
256
257    debug "Creating named pipe '$NAMED_PIPE'"
258
259    # (i did not manage to recover from SIGINT w/o termination of listen_pipe)
260    # => disable SIGINT handler
261    trap '' INT
262    trap "term_handler $NAMED_PIPE" TERM
263    trap "rm -f $NAMED_PIPE" EXIT
264
265    { mkfifo $NAMED_PIPE && listen_pipe $NAMED_PIPE ; } || \
266      { echo "Error creating pipe '$NAMED_PIPE'" ; kill $PARENT_PID ; }
267
268    debug "Pipe reader for '$NAMED_PIPE' terminates.."
269    rm -f $NAMED_PIPE
270}
271
272initial_send_to_launcher() {
273    local NAMED_PIPE=$1
274    local CMD=$2
275
276    send_to_launcher $NAMED_PIPE "$CMD"
277
278    # now allow pipe reader to terminate:
279    send_to_launcher $NAMED_PIPE "allow_termination"
280}
281
282wait_for_pipe() {
283    local NAMED_PIPE=$1
284
285    while [[ ! -p $NAMED_PIPE ]];
286      do
287      echo "Waiting for '$NAMED_PIPE'.."
288      sleep 1
289    done
290    debug "pipe is open"
291}
292
293get_pipe_name() {
294    local SOCKETDIR=$HOME/.arb_tmp/sockets
295    mkdir -p $SOCKETDIR
296    echo "$SOCKETDIR/arb_launcher.$ARB_PID"
297
298    # instead of the above code, use the following to test a pipe-creation failure:
299    # echo "/arb_launcher.$ARB_PID"
300}
301
302launcher() {
303    local ASYNC=0
304    if [ "$1" = "--async" ]; then
305        ASYNC=1
306        shift
307    fi
308    local CMD="$*"
309
310    if [ -z "$ARB_PID" ]; then
311        echo "Error: environment variable ARB_PID is unset. terminating.."
312        false
313    else
314        if [ -z "$1" ]; then
315            echo "Usage: arb_launcher \"shellcommand\""
316            echo ""
317            echo "          runs 'shellcommand'"
318            echo "          "
319            echo "          The initial call to arb_launcher will block until 'shellcommand' terminates."
320            echo ""
321            echo "          Subsequent calls will not block. They are started from the context of the"
322            echo "          initial call. The initial call will wait for all started commands."
323            echo ""
324            echo "       arb_launcher \"TERMINATE\""
325            echo ""
326            echo "          terminate the launcher without waiting for spawned commands."
327            echo ""
328        else
329            debug "Using ARB_PID '$ARB_PID'"
330            local NAMED_PIPE=$(get_pipe_name)
331            debug "Using NAMED_PIPE '$NAMED_PIPE'"
332
333            if [[ ! -p $NAMED_PIPE ]]; then
334                ( wait_for_pipe $NAMED_PIPE ; initial_send_to_launcher $NAMED_PIPE "$CMD" ) &
335                if (( $ASYNC==1 )); then
336                    create_pipe_reader $NAMED_PIPE $$ &
337                else
338                    create_pipe_reader $NAMED_PIPE $$
339                fi
340            else
341                debug "pipe already was open"
342                send_to_launcher $NAMED_PIPE "$CMD"
343            fi
344
345            # if pipe-reader was started from current process
346            # -> blocks until all launched processes have terminated
347            if (( $ASYNC==0 )); then
348                wait
349            fi
350        fi
351    fi
352}
353
354launcher "$@"
355debug "arb_launcher exits!"
Note: See TracBrowser for help on using the repository browser.