source: trunk/SH/arb_launcher

Last change on this file was 19494, checked in by westram, 11 months ago
  • collection of sysinfo terminated with error
    • caused by undefined environment variable
    • relevant info (like available memory) was not collected
  • Property svn:executable set to *
File size: 13.3 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
118if_command() {
119    local CMD=$1; shift
120
121    local FULL_CMD=$($ARBHOME/bin/arb_path.sh -x ${CMD})
122    if [ -n "${FULL_CMD}" ]; then
123        local CALL="${FULL_CMD} $@"
124        echo "{${CALL}}"
125        ${CALL}
126    # else
127        # echo "{no ${CMD}}"
128    fi
129    # never report errors from here
130    true
131}
132
133desktop_info() {
134    echo "XDG_CURRENT_DESKTOP='${XDG_CURRENT_DESKTOP:-}'"
135    echo "GDMSESSION='${GDMSESSION:-}'"
136    # for combinations occurring on different systems see
137    # https://askubuntu.com/questions/72549/how-to-determine-which-window-manager-is-running/227669#227669
138
139    if_command konqueror --version
140    if_command gnome-panel --version
141    if_command xfce4-about --version
142    if_command cinnamon --version
143}
144
145shared_library_dependencies() {
146    case `uname` in
147        Linux)
148            LIST_DYNLIBS="ldd"
149            BINARIES="bin/arb_ntree lib/libARBDB.so lib/libCORE.so lib/libWINDOW.so"
150            ;;
151        Darwin)
152            LIST_DYNLIBS="otool -L"
153            # Darwin ARB links internal stuff static
154            BINARIES="bin/arb_ntree"
155            ;;
156        *)
157            LIST_DYNLIBS="echo UNSUPPORTED_OS "
158            ;;
159    esac
160    for binary in $BINARIES; do
161        echo -e "Library dependencies for $ARBHOME/$binary:"
162        $LIST_DYNLIBS $ARBHOME/$binary
163    done
164}
165
166wrapped_info() {
167    local TAG=$1; shift
168    local CMD=$1; shift
169    echo "--------------------"
170    echo "[$TAG start]"
171    eval $CMD
172    echo "[$TAG end]"
173    echo ""
174}
175
176collect_system_information() {
177    echo "System information"
178    echo ""
179    echo "The information below has been collected by ARB."
180    echo "Please do not publish without being aware that it might contain personal information."
181    echo "[current date: `date`]"
182    echo ""
183
184    local ARB_RELEVANT="| grep -i ARB"
185
186    wrapped_info "version" "$ARBHOME/bin/arb_ntree --help"
187    wrapped_info "environment" "printenv $ARB_RELEVANT"
188    wrapped_info "sina" "$ARBHOME/bin/arb_sina.sh runldd"
189    wrapped_info "OS" "lsb_release -a"
190    wrapped_info "kernel" "uname -mrs ; uname -a ; cat /proc/version"
191    wrapped_info "desktop" "desktop_info"
192
193    wrapped_info "shared libraries" "shared_library_dependencies"
194    wrapped_info "disk" "df -h"
195    wrapped_info "memory" "free -m ; cat /proc/meminfo"
196    wrapped_info "user limits" "ulimit -a"
197    wrapped_info "ARB processes" "ps aux $ARB_RELEVANT"
198
199    wrapped_info "CPU" "cat /proc/cpuinfo"
200    wrapped_info "X server" "xdpyinfo"
201    # wrapped_info "X" "Y"
202}
203
204erase_old_logs() {
205    local LOGBASE=$1
206    if [ -d "$LOGBASE" ]; then
207        # remove files older than 15 days inside and below LOGBASE
208        local OLD=$(( 60 * 24 * 15 ))
209        find $LOGBASE -type f -cmin +$OLD -exec rm {} \;
210        # remove empty directories inside and below LOGBASE
211        find $LOGBASE -type d -depth -empty -mindepth 1 -exec rmdir {} \;
212    fi
213}
214
215listen_pipe() {
216    # this is just a wrapper around listen_pipe_unlogged.
217    # wrapper performs ARB session logging
218    local NAMED_PIPE=$1
219
220    if [ -z ${ARB_PROP:-} ]; then
221        # should never come here, if arb has been started via script 'arb'
222        # (e.g. happens when arb_ntree was started from debugger and then 'start second database' has been called)
223        listen_pipe_unlogged $NAMED_PIPE
224    else
225        local LOGBASE=$ARB_PROP/logs
226        local LOGDIRID=`date '+%Y%m%d_%H%M%S'`.$$
227        local LOGDIR=$LOGBASE/$LOGDIRID
228        local NTREE_STATUS=
229
230        mkdir -p $LOGDIR
231
232        if [ -d "$LOGDIR" ]; then
233            local RUNLOG=$LOGDIR/run.log
234            local SERVERLOG=$LOGDIR/server.log
235            local SYSLOG=$LOGDIR/sys.info
236            local CRASHFLAG=$LOGDIR/crashed
237            local FAILFLAG=$LOGDIR/failed
238
239            # tell arb to start servers as logging daemons
240            export ARB_SERVER_LOG=$SERVERLOG
241            echo "`date` arb server.log created by arb_launcher" > $SERVERLOG
242
243            # forward server output to launcher-tty (non-blocking)
244            tail -f $SERVERLOG &
245            local TAILPID=$!
246
247            ( ( collect_system_information 2>&1 ) > $SYSLOG ; erase_old_logs $LOGBASE ) &
248            ( listen_pipe_unlogged $NAMED_PIPE $LOGDIR ) 2>&1 | tee $RUNLOG
249
250            if [ -e $CRASHFLAG ]; then
251                # only detects crashes of arb_ntree
252                # (clients are not started via arb_launcher and they usually crash when server exits)
253                NTREE_STATUS=crash
254            else
255                if [ -e $FAILFLAG ]; then
256                    NTREE_STATUS=fail
257                fi
258            fi
259
260            if [ "$NTREE_STATUS" != "" ]; then
261                echo "abnormal termination (NTREE_STATUS='$NTREE_STATUS')" >> $RUNLOG
262            else
263                echo "normal termination" >> $RUNLOG
264            fi
265
266            local TARBALLNAME=session.$LOGDIRID.tgz
267
268            debug "killing tail on server-log (pid=$TAILPID)"
269            kill ${TAILPID}
270
271            echo "`date` arb_launcher terminates now. leftover servers may continue logging into this file" >> $SERVERLOG
272            echo "`date` End of log (now archive into $LOGBASE/$TARBALLNAME)" >> $RUNLOG
273
274            ( cd $LOGBASE ; tar -zcf $TARBALLNAME $LOGDIRID )
275            rm -f $RUNLOG $SYSLOG $CRASHFLAG $FAILFLAG
276            rmdir $LOGDIR
277
278            local FULLTARBALL=$LOGBASE/$TARBALLNAME
279            echo ""
280            echo "Session log has been stored in $FULLTARBALL"
281
282            local LATESTLINK=~/ARB_last_session.tgz
283            if [ -h $LATESTLINK ]; then
284                rm $LATESTLINK
285            fi
286            if [ -e $LATESTLINK ]; then
287                echo "$LATESTLINK already exists and is no symlink"
288            else
289                (cd ~; ln -s $FULLTARBALL $LATESTLINK )
290                echo "    and is also accessible via $LATESTLINK"
291            fi
292
293            if [ "$NTREE_STATUS" != "" ]; then
294                echo ""
295                if [ $NTREE_STATUS = "crash" ]; then
296                    echo "ARB crashed :-("
297                    echo "To report this goto http://bugs.arb-home.de/wiki/BugReport"
298                    echo "Please include the session log(s) mentioned above!"
299                    echo ""
300                else
301                    echo "ARB terminated abnormally"
302                fi
303
304                echo "[$(date)]"
305                local DAYWAIT=3
306                echo "[press ENTER or wait ${DAYWAIT} days]"
307                local SECWAIT=$((${DAYWAIT}*24*60*60))
308                read -t ${SECWAIT} A
309            fi
310
311            true
312        else
313            echo "Error creating directory '$LOGDIR'"
314            false
315        fi
316    fi
317}
318
319killtree() {
320    local _pid=$1
321    local _sig=${2:-TERM}
322
323    debug "killtree pid=${_pid} with sig=${_sig} pid=$$"
324    kill -stop ${_pid} # stop quickly forking parent from producing childs
325    killchilds ${_pid} ${_sig}
326    kill ${_sig} ${_pid}
327}
328killchilds() {
329    local _pid=$1
330    local _sig=${2:-TERM}
331
332    debug "killchilds pid=${_pid} with sig=${_sig} pid=$$"
333    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
334        killtree ${_child} ${_sig}
335    done
336}
337
338term_handler() {
339    local NAMED_PIPE=$1
340
341    trace "Killing ARB session for ARB_PID=$ARB_PID"
342    arb_clean session
343    debug "arb_clean done - now killing process tree"
344    killchilds $$ -TERM
345    debug "killchilds done - exiting $$"
346    exit
347}
348
349create_pipe_reader() {
350    local NAMED_PIPE=$1
351    local PARENT_PID=$2
352
353    if [ -z "${ARB_LAUNCHER:-}" ]; then
354        export ARB_LAUNCHER=0
355    else
356        export ARB_LAUNCHER=$(($ARB_LAUNCHER+1))
357    fi
358
359    debug "Creating named pipe '$NAMED_PIPE'"
360
361    # (i did not manage to recover from SIGINT w/o termination of listen_pipe)
362    # => disable SIGINT handler
363    trap '' INT
364    trap "term_handler $NAMED_PIPE" TERM
365    trap "rm -f $NAMED_PIPE" EXIT
366
367    { mkfifo -m 600 $NAMED_PIPE && listen_pipe $NAMED_PIPE ; debug "listen_pipe done" ; } || \
368      { echo "Error creating pipe '$NAMED_PIPE'" ; kill $PARENT_PID ; }
369
370    debug "Pipe reader for '$NAMED_PIPE' terminates.."
371    rm -f $NAMED_PIPE
372    debug "Pipe '$NAMED_PIPE' removed"
373}
374
375initial_send_to_launcher() {
376    local NAMED_PIPE=$1
377    local CMD=$2
378
379    send_to_launcher $NAMED_PIPE "$CMD"
380
381    # now allow pipe reader to terminate:
382    send_to_launcher $NAMED_PIPE "allow_termination"
383}
384
385wait_for_pipe() {
386    local NAMED_PIPE=$1
387
388    while [[ ! -p $NAMED_PIPE ]];
389      do
390      echo "Waiting for '$NAMED_PIPE'.."
391      sleep 1
392    done
393    debug "pipe is open"
394}
395
396get_pipe_name() {
397    local SOCKETDIR="$HOME/.arb_tmp/sockets"
398    mkdir -p "$SOCKETDIR"
399    chmod 0700 "$SOCKETDIR"
400    echo "$SOCKETDIR/arb_launcher.$ARB_PID"
401
402    # instead of the above code, use the following to test a pipe-creation failure:
403    # echo "/arb_launcher.$ARB_PID"
404}
405
406launcher() {
407    local ASYNC=0
408    if [ "$1" = "--async" ]; then
409        ASYNC=1
410        shift
411    fi
412    local CMD="$*"
413
414    if [ -z "$ARB_PID" ]; then
415        echo "Error: environment variable ARB_PID is unset. terminating.."
416        false
417    else
418        if [ -z "$1" ]; then
419            echo "Usage: arb_launcher \"shellcommand\""
420            echo ""
421            echo "          runs 'shellcommand'"
422            echo "          "
423            echo "          The initial call to arb_launcher will block until 'shellcommand' terminates."
424            echo ""
425            echo "          Subsequent calls will not block. They are started from the context of the"
426            echo "          initial call. The initial call will wait for all started commands."
427            echo ""
428            echo "       arb_launcher \"TERMINATE\""
429            echo ""
430            echo "          terminate the launcher without waiting for spawned commands."
431            echo ""
432        else
433            debug "Using ARB_PID '$ARB_PID'"
434            local NAMED_PIPE=$(get_pipe_name)
435            debug "Using NAMED_PIPE '$NAMED_PIPE'"
436
437            if [[ ! -p $NAMED_PIPE ]]; then
438                ( wait_for_pipe $NAMED_PIPE ; initial_send_to_launcher $NAMED_PIPE "$CMD" ) &
439                if (( $ASYNC==1 )); then
440                    create_pipe_reader $NAMED_PIPE $$ &
441                else
442                    create_pipe_reader $NAMED_PIPE $$
443                fi
444            else
445                debug "pipe already was open"
446                send_to_launcher $NAMED_PIPE "$CMD"
447            fi
448
449            # if pipe-reader was started from current process
450            # -> blocks until all launched processes have terminated
451            if (( $ASYNC==0 )); then
452                wait
453            fi
454        fi
455    fi
456}
457
458launcher "$@"
459debug "arb_launcher exits!"
460
Note: See TracBrowser for help on using the repository browser.