source: branches/help/SH/arb_launcher

Last change on this file was 16391, checked in by westram, 7 years ago
  • full update from child 'aci' into 'trunk'
    • allow to view console from inside ARB
    • slightly tweaked ACI trace
  • adds: log:branches/aci@16386:16390
  • Property svn:executable set to *
File size: 12.4 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    $CMD
32    local EXITCODE=${PIPESTATUS[0]}
33    if [ $EXITCODE == 0 ]; then
34        trace "'$CMD' has terminated with success"
35    else
36        trace "'$CMD' has terminated with error $EXITCODE"
37        if [ -n "$LOGDIR" ]; then
38            if [ $EXITCODE = 1 ]; then
39                touch $LOGDIR/failed
40            else
41                touch $LOGDIR/crashed
42            fi
43        fi
44    fi
45
46    send_to_launcher $NAMED_PIPE 'cmd_terminated'
47    debug "pipe_command terminates"
48}
49
50read_line() {
51    local NAMED_PIPE=$1
52    local LINE=""
53
54    if read ATTEMPT <$NAMED_PIPE; then
55        LINE=$ATTEMPT
56    fi
57    echo $LINE
58}
59
60listen_pipe_unlogged() {
61    local NAMED_PIPE=$1; shift
62    local LOGDIR=${1:-}; shift # LOGDIR may be empty/undef -> dont log
63    local RUNNING=1
64    local STARTED=0
65    # RUNNING is set to 1 (otherwise listen_pipe would terminate instantly)
66
67    trace "log for ARB_PID='${ARB_PID}'"
68
69    while (($RUNNING > 0))
70      do
71      LINE=`read_line $NAMED_PIPE 2>/dev/null`
72      if [[ ! -z "$LINE" ]]; then
73          debug "'$NAMED_PIPE' received '$LINE'"
74          if [[ "$LINE" == 'TERMINATE' ]]; then
75              trace "Received request to TERMINATE"
76              break;
77          else
78              if [[ "$LINE" == 'cmd_terminated' ]]; then
79                  RUNNING=$(($RUNNING - 1))
80                  if (($RUNNING>0)); then
81                      trace "Still have $RUNNING arb processes.."
82                  fi
83              else
84                  if [[ "$LINE" == 'allow_termination' ]]; then
85                      RUNNING=$(($RUNNING - 1))
86                  else
87                      pipe_command $NAMED_PIPE "$LINE" $LOGDIR &
88                      RUNNING=$(($RUNNING + 1))
89                      STARTED=$(($STARTED + 1))
90                      debug "RUNNING=$RUNNING"
91                      debug "STARTED=$STARTED"
92                  fi
93              fi
94          fi
95      fi
96    done
97
98    if (($RUNNING==0)); then
99        if (($STARTED>0)); then
100            trace "All launched processes terminated"
101        else
102            trace "Nothing was ever launched"
103        fi
104    else
105        trace "Still have $RUNNING arb-processes - terminating nevertheless"
106    fi
107
108    debug "listen_pipe_unlogged waits for subshells ..."
109    wait
110
111    trace "cleaning up arb session"
112    arb_clean show_session
113    arb_clean session
114
115    debug "listen_pipe_unlogged terminates"
116}
117
118shared_library_dependencies() {
119    case `uname` in
120        Linux)
121            LIST_DYNLIBS="ldd"
122            BINARIES="bin/arb_ntree lib/libARBDB.so lib/libCORE.so lib/libWINDOW.so"
123            ;;
124        Darwin)
125            LIST_DYNLIBS="otool -L"
126            # Darwin ARB links internal stuff static
127            BINARIES="bin/arb_ntree"
128            ;;
129        *)
130            LIST_DYNLIBS="echo UNSUPPORTED_OS "
131            ;;
132    esac
133    for binary in $BINARIES; do
134        echo -e "Library dependencies for $ARBHOME/$binary:"
135        $LIST_DYNLIBS $ARBHOME/$binary
136    done   
137}
138
139wrapped_info() {
140    local TAG=$1; shift
141    local CMD=$1; shift
142    echo "--------------------"
143    echo "[$TAG start]"
144    eval $CMD
145    echo "[$TAG end]"
146    echo ""
147}
148
149collect_system_information() {
150    echo "System information"
151    echo ""
152    echo "The information below has been collected by ARB."
153    echo "Please do not publish without being aware that it might contain personal information."
154    echo ""
155
156    local ARB_RELEVANT="| grep -i ARB"
157
158    wrapped_info "version" "$ARBHOME/bin/arb_ntree --help"
159    wrapped_info "environment" "printenv $ARB_RELEVANT"
160    wrapped_info "OS" "lsb_release -a"
161    wrapped_info "kernel" "uname -mrs ; uname -a ; cat /proc/version"
162    wrapped_info "shared libraries" "shared_library_dependencies"
163    wrapped_info "disk" "df -h"
164    wrapped_info "memory" "free -m ; cat /proc/meminfo"
165    wrapped_info "user limits" "ulimit -a"
166    wrapped_info "ARB processes" "ps aux $ARB_RELEVANT"
167    wrapped_info "KDE desktop version" "konqueror --version"
168    wrapped_info "Gnome desktop version" "gnome-panel --version"
169    wrapped_info "CPU" "cat /proc/cpuinfo"
170    wrapped_info "X server" "xdpyinfo"
171    # wrapped_info "X" "Y"
172}
173
174erase_old_logs() {
175    local LOGBASE=$1
176    if [ -d "$LOGBASE" ]; then
177        # remove files older than 7 days inside and below LOGBASE
178        local OLD=$(( 60 * 24 * 7 ))
179        find $LOGBASE -type f -cmin +$OLD -exec rm {} \;
180        # remove empty directories inside and below LOGBASE
181        find $LOGBASE -type d -depth -empty -mindepth 1 -exec rmdir {} \;
182    fi
183}
184
185listen_pipe() {
186    # this is just a wrapper around listen_pipe_unlogged.
187    # wrapper performs ARB session logging
188    local NAMED_PIPE=$1
189
190    if [ -z ${ARB_PROP:-} ]; then
191        # should never come here, if arb has been started via script 'arb'
192        # (e.g. happens when arb_ntree was started from debugger and then 'start second database' has been called)
193        listen_pipe_unlogged $NAMED_PIPE
194    else
195        local LOGBASE=$ARB_PROP/logs
196        local LOGDIRID=`date '+%Y%m%d_%H%M%S'`.$$
197        local LOGDIR=$LOGBASE/$LOGDIRID
198        local NTREE_STATUS=
199
200        mkdir -p $LOGDIR
201
202        if [ -d "$LOGDIR" ]; then
203            local RUNLOG=$LOGDIR/run.log
204            local SERVERLOG=$LOGDIR/server.log
205            local SYSLOG=$LOGDIR/sys.info
206            local CRASHFLAG=$LOGDIR/crashed
207            local FAILFLAG=$LOGDIR/failed
208
209            # tell arb to start servers as logging daemons
210            export ARB_SERVER_LOG=$SERVERLOG
211            echo "`date` arb server.log created by arb_launcher" > $SERVERLOG
212
213            # forward server output to launcher-tty (non-blocking)
214            tail -f $SERVERLOG &
215            local TAILPID=$!
216
217            ( ( collect_system_information 2>&1 ) > $SYSLOG ; erase_old_logs $LOGBASE ) &
218            ( listen_pipe_unlogged $NAMED_PIPE $LOGDIR ) 2>&1 | tee $RUNLOG
219
220            if [ -e $CRASHFLAG ]; then
221                # only detects crashes of arb_ntree
222                # (clients are not started via arb_launcher and they usually crash when server exits)
223                NTREE_STATUS=crash
224            else
225                if [ -e $FAILFLAG ]; then
226                    NTREE_STATUS=fail
227                fi
228            fi
229
230            if [ "$NTREE_STATUS" != "" ]; then
231                echo "abnormal termination (NTREE_STATUS='$NTREE_STATUS')" >> $RUNLOG
232            else
233                echo "normal termination" >> $RUNLOG
234            fi
235
236            local TARBALLNAME=session.$LOGDIRID.tgz
237
238            debug "killing tail on server-log (pid=$TAILPID)"
239            kill ${TAILPID}
240
241            echo "`date` arb_launcher terminates now. leftover servers may continue logging into this file" >> $SERVERLOG
242            echo "`date` End of log (now archive into $LOGBASE/$TARBALLNAME)" >> $RUNLOG
243
244            ( cd $LOGBASE ; tar -zcf $TARBALLNAME $LOGDIRID )
245            rm -f $RUNLOG $SYSLOG $CRASHFLAG $FAILFLAG
246            rmdir $LOGDIR
247
248            local FULLTARBALL=$LOGBASE/$TARBALLNAME
249            echo ""
250            echo "Session log has been stored in $FULLTARBALL"
251
252            local LATESTLINK=~/ARB_last_session.tgz
253            if [ -h $LATESTLINK ]; then
254                rm $LATESTLINK
255            fi
256            if [ -e $LATESTLINK ]; then
257                echo "$LATESTLINK already exists and is no symlink"
258            else
259                (cd ~; ln -s $FULLTARBALL $LATESTLINK )
260                echo "    and is also accessible via $LATESTLINK"
261            fi
262
263            if [ "$NTREE_STATUS" != "" ]; then
264                echo ""
265                if [ $NTREE_STATUS = "crash" ]; then
266                    echo "ARB crashed :-("
267                    echo "To report this goto http://bugs.arb-home.de/wiki/BugReport"
268                    echo "Please include the session log(s) mentioned above!"
269                    echo ""
270                else
271                    echo "ARB terminated abnormally"
272                fi
273                echo "[press ENTER]"
274                read A
275            fi
276
277            true
278        else
279            echo "Error creating directory '$LOGDIR'"
280            false
281        fi
282    fi
283}
284
285killtree() {
286    local _pid=$1
287    local _sig=${2:-TERM}
288
289    debug "killtree pid=${_pid} with sig=${_sig} pid=$$"
290    kill -stop ${_pid} # stop quickly forking parent from producing childs
291    killchilds ${_pid} ${_sig}
292    kill ${_sig} ${_pid}
293}
294killchilds() {
295    local _pid=$1
296    local _sig=${2:-TERM}
297
298    debug "killchilds pid=${_pid} with sig=${_sig} pid=$$"
299    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
300        killtree ${_child} ${_sig}
301    done
302}
303
304term_handler() {
305    local NAMED_PIPE=$1
306
307    trace "Killing ARB session for ARB_PID=$ARB_PID"
308    arb_clean session
309    debug "arb_clean done - now killing process tree"
310    killchilds $$ -TERM
311    debug "killchilds done - exiting $$"
312    exit
313}
314
315create_pipe_reader() {
316    local NAMED_PIPE=$1
317    local PARENT_PID=$2
318
319    if [ -z "${ARB_LAUNCHER:-}" ]; then
320        export ARB_LAUNCHER=0
321    else
322        export ARB_LAUNCHER=$(($ARB_LAUNCHER+1))
323    fi
324
325    debug "Creating named pipe '$NAMED_PIPE'"
326
327    # (i did not manage to recover from SIGINT w/o termination of listen_pipe)
328    # => disable SIGINT handler
329    trap '' INT
330    trap "term_handler $NAMED_PIPE" TERM
331    trap "rm -f $NAMED_PIPE" EXIT
332
333    { mkfifo -m 600 $NAMED_PIPE && listen_pipe $NAMED_PIPE ; debug "listen_pipe done" ; } || \
334      { echo "Error creating pipe '$NAMED_PIPE'" ; kill $PARENT_PID ; }
335
336    debug "Pipe reader for '$NAMED_PIPE' terminates.."
337    rm -f $NAMED_PIPE
338    debug "Pipe '$NAMED_PIPE' removed"
339}
340
341initial_send_to_launcher() {
342    local NAMED_PIPE=$1
343    local CMD=$2
344
345    send_to_launcher $NAMED_PIPE "$CMD"
346
347    # now allow pipe reader to terminate:
348    send_to_launcher $NAMED_PIPE "allow_termination"
349}
350
351wait_for_pipe() {
352    local NAMED_PIPE=$1
353
354    while [[ ! -p $NAMED_PIPE ]];
355      do
356      echo "Waiting for '$NAMED_PIPE'.."
357      sleep 1
358    done
359    debug "pipe is open"
360}
361
362get_pipe_name() {
363    local SOCKETDIR="$HOME/.arb_tmp/sockets"
364    mkdir -p "$SOCKETDIR"
365    chmod 0700 "$SOCKETDIR"
366    echo "$SOCKETDIR/arb_launcher.$ARB_PID"
367
368    # instead of the above code, use the following to test a pipe-creation failure:
369    # echo "/arb_launcher.$ARB_PID"
370}
371
372launcher() {
373    local ASYNC=0
374    if [ "$1" = "--async" ]; then
375        ASYNC=1
376        shift
377    fi
378    local CMD="$*"
379
380    if [ -z "$ARB_PID" ]; then
381        echo "Error: environment variable ARB_PID is unset. terminating.."
382        false
383    else
384        if [ -z "$1" ]; then
385            echo "Usage: arb_launcher \"shellcommand\""
386            echo ""
387            echo "          runs 'shellcommand'"
388            echo "          "
389            echo "          The initial call to arb_launcher will block until 'shellcommand' terminates."
390            echo ""
391            echo "          Subsequent calls will not block. They are started from the context of the"
392            echo "          initial call. The initial call will wait for all started commands."
393            echo ""
394            echo "       arb_launcher \"TERMINATE\""
395            echo ""
396            echo "          terminate the launcher without waiting for spawned commands."
397            echo ""
398        else
399            debug "Using ARB_PID '$ARB_PID'"
400            local NAMED_PIPE=$(get_pipe_name)
401            debug "Using NAMED_PIPE '$NAMED_PIPE'"
402
403            if [[ ! -p $NAMED_PIPE ]]; then
404                ( wait_for_pipe $NAMED_PIPE ; initial_send_to_launcher $NAMED_PIPE "$CMD" ) &
405                if (( $ASYNC==1 )); then
406                    create_pipe_reader $NAMED_PIPE $$ &
407                else
408                    create_pipe_reader $NAMED_PIPE $$
409                fi
410            else
411                debug "pipe already was open"
412                send_to_launcher $NAMED_PIPE "$CMD"
413            fi
414
415            # if pipe-reader was started from current process
416            # -> blocks until all launched processes have terminated
417            if (( $ASYNC==0 )); then
418                wait
419            fi
420        fi
421    fi
422}
423
424launcher "$@"
425debug "arb_launcher exits!"
426
Note: See TracBrowser for help on using the repository browser.