source: tags/arb-6.0/SH/arb_launcher

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