"Fossies" - the Fresh Open Source Software Archive 
Member "mussh/mussh" (25 Oct 2011, 20815 Bytes) of package /linux/privat/old/mussh-1.0.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bash source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 #!/bin/bash
2 #
3 # $Id: mussh,v 1.12 2006/12/26 21:57:22 doughnut Exp $
4 MUSSH_VERSION="1.0"
5 #
6 # Description: This script is used to execute the same command(s) on
7 # many hosts.
8 #
9 # by doughnut
10 #
11
12
13
14
15 ########################
16 # INITIALIZE THIS CRAP #
17 ########################
18 DEBUG=0
19 SSH_VERBOSE=""
20 QUIET=0
21 FORCE_AGENT=0
22 UNIQUE_HOSTS=1
23 PROXY_SSH_ARGS="-o PasswordAuthentication=no"
24 SSH_ARGS="-o BatchMode=yes"
25 AGENT_LOADED=0
26 REMOTE_SHELL='bash'
27 TEMP_BASE=/tmp
28 CONCURRENT=1
29
30 ############################
31 # GOTTA LOVE DOCUMENTATION #
32 ############################
33 USAGE="Usage: mussh [OPTIONS] <-h host.. | -H hostfile> [-c cmd] [-C scriptfile]
34 mussh --help for full help text"
35 HELPTEXT="
36 Send a command or list of commands to multiple hosts.
37
38 OPTIONS:
39 --help This text.
40 -d [n] Verbose debug. Prints each action, all hosts
41 and commands to be executed to STDERR. 'n' can
42 be from 0 to 2.
43 -v [n] Ssh debug levels. Can be from 0 to 3.
44 -m [n] Run concurrently on 'n' hosts at a time (asynchronous).
45 Use '0' (zero) for infinite. (default if -m)
46 -q No output unless necessary.
47 -i <identity> [identity ..]
48 Load an identity file. May be used
49 more than once.
50 -o <ssh-args> Args to pass to ssh with -o option.
51 -a Force loading ssh-agent.
52 -A Do NOT load ssh-agent.
53 -b Print each hosts' output in a block without mingling
54 with other hosts' output.
55 -B Allow hosts' output to mingle. (default)
56 -u Unique. Eliminate duplicate hosts. (default)
57 -U Do NOT make host list unique.
58 -P Do NOT fall back to passwords on any host. This will
59 skip hosts where keys fail.
60 -l <login> Use 'login' when no other is specified with hostname.
61 -L <login> Force use of 'login' name on all hosts.
62 -s <shell> Path to shell on remote host. (Default: $REMOTE_SHELL)
63 -t <secs> Timeout setting for each session.
64 (requires openssh 3.8 or newer)
65 -V Print version info and exit.
66 PROXY ARGS:
67 -p [user@]<host>
68 Host to use as proxy. (Must have mussh installed)
69 -po <ssh-args> Args to pass to ssh on proxy with -o option.
70 HOST ARGS:
71 -h [user@]<host> [[user@]<host> ..]
72 Add a host to list of hosts. May be
73 used more than once.
74 -H <file> [file ..]
75 Add contents of file(s) to list of hosts.
76 Files should have one host per line. Use
77 \"#\" for comments.
78 COMMAND ARGS:
79 If neither is specified, commands will be read from standard input.
80 -c <command> Add a command or quoted list of commands and
81 args to list of commands to be executed on
82 each host. May be used more than once.
83 -C <file> [file ..]
84 Add file contents to list of commands to be
85 executed on each host. May be used more
86 than once.
87
88 At least one host is required. Arguments are in no particular order.
89
90 EXAMPLES:
91 mussh -H ./linuxhosts -C spfiles/testscript.sh
92 mussh -c \"cat /etc/hosts\" -h myhost.mydomain.com
93
94 Comments and Bug Reports: doughnut@doughnut.net
95 "
96
97 ###########################
98 # FUNCTIONS FOR SSH-AGENT #
99 ###########################
100 load_keys() {
101 [ "$AGENT_LOADED" = "0" -a "$IDENT" = "" ] && return
102 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Adding Keys" 1>&2
103 ssh-add $* 1>&2
104 }
105
106 start_agent() {
107 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Starting Agent" 1>&2
108 if [ "$FORCE_AGENT" -ge 1 ] ; then
109 # Load it anyway
110 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Forcing SSH Agent" 1>&2
111 elif [ -S "$SSH_AUTH_SOCK" ] ; then
112 [ "$DEBUG" -ge 1 ] && echo "DEBUG: SSH Agent already loaded" 1>&2
113 return
114 fi
115 eval $(ssh-agent -s) >/dev/null
116 AGENT_LOADED=1
117 }
118 stop_agent() {
119 # get rid of the keys that we added (if any)
120 if [ "$IDENT" != "" ] ; then
121 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Removing keys from agent" 1>&2
122 ssh-add -d $IDENT > /dev/null 2>&1
123 fi
124 [ "$AGENT_LOADED" = "0" ] && return
125 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Stopping Agent" 1>&2
126 eval $(ssh-agent -s -k) >/dev/null
127 }
128
129 ####################################
130 # FUNCTIONS FOR REMOTE CONNECTIONS #
131 ####################################
132 proxy_connect() {
133 [ "$DEBUG" -ge 1 ] && echo "DEBUG: PROXY CONNECT $PROXY" 1>&2
134 echo "$THESCRIPT" \
135 | ssh -T $SSH_ARGS $PROXY \
136 "mussh -h $HOSTLIST \
137 -C - \
138 -d$DEBUG \
139 $PROXY_SSH_ARGS 2>&1 " \
140 | while read SSH_LINE ; do
141 if [ "$QUIET" -lt 1 -a "$SSH_LINE" != "" ] ; then
142 echo "$SSH_LINE" | sed -e "s/^/$HOST: /"
143 fi
144 done
145 }
146
147 ssh_connect() {
148 echo "$THESCRIPT" \
149 | ssh -T $SSH_ARGS $HOST "$REMOTE_SHELL" 2>&1 \
150 | while read SSH_LINE ; do
151 if [ "$QUIET" -lt 1 -a "$SSH_LINE" != "" ] ; then
152 echo "$SSH_LINE" | sed -e "s/^/$HOST: /"
153 fi
154 done
155 }
156
157 ##############################
158 # FUNCTIONS FOR FORKED PROCS #
159 ##############################
160 set_hostlist() {
161 # Create a hostlist file.
162 [ "$DEBUG" -ge 2 ] && echo "DEBUG: BUILDING HOST LIST FILE $TEMP_DIR/hostlist" 1>&2
163 rm -f $TEMP_DIR/hostlist || exit 1
164 for HOST in $HOSTLIST ; do
165 echo $HOST >> "$TEMP_DIR/hostlist" || exit 1
166 done
167 }
168
169 get_next_host() {
170 # lock file
171 while [ 1 ] ; do
172 echo $CHILDNUM >> "$TEMP_DIR/hostlist.lock"
173 TOP_PID=$(head -1 "$TEMP_DIR/hostlist.lock" 2>/dev/null)
174 if [ "$TOP_PID" = $CHILDNUM ] ; then
175 break
176 fi
177 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: hostlist file already locked. Sleep..." 1>&2
178 #usleep 1000
179 sleep 1
180 done
181 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Locked hostfile." 1>&2
182
183 # get next host
184 NEXT_HOST=$(head -1 $TEMP_DIR/hostlist)
185 HOSTFILE_LEN=$(wc -l $TEMP_DIR/hostlist | awk '{print $1}')
186 if [ -z "$HOSTFILE_LEN" -o "$HOSTFILE_LEN" = 0 ] ; then
187 rm -f "$TEMP_DIR/hostlist.lock"
188 return
189 fi
190 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Next host: $NEXT_HOST" 1>&2
191
192 # re-write file removing new host
193 rm -f "$TEMP_DIR/hostlist.new"
194 echo tail -$(( $HOSTFILE_LEN - 1 )) $TEMP_DIR/hostlist > $TEMP_DIR/hostlist.new || exit 1
195 tail -$(( $HOSTFILE_LEN - 1 )) $TEMP_DIR/hostlist > $TEMP_DIR/hostlist.new || exit 1
196 rm -f "$TEMP_DIR/hostlist"
197 mv "$TEMP_DIR/hostlist.new" "$TEMP_DIR/hostlist"
198
199 # unlock file
200 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Removing hostfile lock." 1>&2
201 rm -f "$TEMP_DIR/hostlist.lock"
202
203 # return hostname
204 echo $NEXT_HOST
205 }
206
207 run_child() {
208 trap "exit 0" SIGHUP
209 CHILDNUM=$1
210 [ "$DEBUG" -ge 2 ] && echo "DEBUG: FORKING CHILD #$CHILDNUM of $CONCURRENT (pid $!/$$)" 1>&2
211 while [ 1 ] ; do
212
213 # issue: Cannot call get_next_host inside $() or `` because our trap won't be able to kill that.
214 # solution: avoid subshell here by directing to a file.
215 rm -f $TEMP_DIR/$CHILDNUM.next_host
216 get_next_host >$TEMP_DIR/$CHILDNUM.next_host
217 HOST=$(<$TEMP_DIR/$CHILDNUM.next_host)
218 if [ -z "$HOST" ] ; then
219 rm -f "$TEMP_DIR/$CHILDNUM.pid"
220 break
221 fi
222 [ "$DEBUG" -ge 1 ] && echo "DEBUG[#$CHILDNUM]: CONNECT $HOST" 1>&2
223
224 rm -f "$TEMP_DIR/$CHILDNUM.active"
225 echo "$HOST" > "$TEMP_DIR/$CHILDNUM.active"
226 if [ -n "$BLOCKING" ] ; then
227 ssh_connect > $TEMP_DIR/$HOST.out
228 cat $TEMP_DIR/$HOST.out
229 else
230 ssh_connect
231 fi
232 done
233 [ "$DEBUG" -ge 2 ] && echo "DEBUG: CHILD #$CHILDNUM done" 1>&2
234 rm -f "$TEMP_DIR/$CHILDNUM.pid" "$TEMP_DIR/$CHILDNUM.active"
235 }
236
237
238 ###########################
239 # FUNCTIONS FOR TEMP DIRS #
240 ###########################
241 create_temp() {
242 MKTEMP=$(which mktemp 2>/dev/null)
243 if [ -x "$MKTEMP" ] ; then
244 [ "$DEBUG" -ge 2 ] && echo "DEBUG: using mktemp ($MKTEMP)." 1>&2
245 TEMP_DIR=$(mktemp -d $TEMP_BASE/$(basename $0).XXXXXX) || exit 1
246 else
247 [ "$DEBUG" -ge 2 ] && echo "DEBUG: can't find mktemp... using alternate." 1>&2
248 TEMP_DIR="$TEMP_BASE/$(basename $0).$(date +%s)"
249 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Creating temp dir ($TEMP_DIR)." 1>&2
250 if [ -e "$TEMP_DIR" ] ; then
251 echo "$0: Temp dir \"$TEMP_DIR\" already exists!" 1>&2
252 exit 1
253 fi
254 mkdir -m 700 $TEMP_DIR
255 fi
256 }
257
258 destroy_temp() {
259 if [ -d "$TEMP_DIR" ] ; then
260 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Removing temp dir ($TEMP_DIR)." 1>&2
261 rm -rf "$TEMP_DIR" 2>/dev/null
262 fi
263 }
264
265
266
267 ########################################
268 # REMEMBER TO CLEAN UP BEFORE WE PANIC #
269 ########################################
270 shutdown() {
271 [ "$DEBUG" -ge 1 ] && echo "DEBUG: shutting down children." 1>&2
272 CPIDS=$(cat $TEMP_DIR/*.pid 2>/dev/null)
273 for CPID in $CPIDS ; do
274 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Killing pid: $CPID" 1>&2
275 kill -HUP $CPID
276 done
277 [ "$DEBUG" -ge 2 ] && echo "DEBUG: shutting down ssh-agent" 1>&2
278 stop_agent
279 [ "$DEBUG" -ge 2 ] && echo "DEBUG: removing temp dir" 1>&2
280 destroy_temp
281 [ "$DEBUG" -ge 2 ] && echo "DEBUG: done shutting down." 1>&2
282 exit 1
283 }
284
285 spew_hostlist() {
286 echo "HOSTS RUNNING:" 1>&2
287 cat $TEMP_DIR/*.active 2>/dev/null | sed 's/^/ /' 1>&2
288 echo "HOSTS REMAINING:" 1>&2
289 cat $TEMP_DIR/hostlist 2>/dev/null | sed 's/^/ /' 1>&2
290 return
291 }
292
293 trap shutdown SIGINT
294 trap shutdown SIGTERM
295 trap spew_hostlist SIGQUIT
296 trap "exit 0" SIGHUP
297
298 #############################
299 # PARSE THE COMMAND OPTIONS #
300 #############################
301 while [ "$1" != "" ]; do
302 case "$1" in
303 ###########
304 # OPTIONS #
305 ###########
306 -A)
307 NO_AGENT=1
308 shift
309 ;;
310 -a)
311 FORCE_AGENT=1
312 shift
313 ;;
314 -b)
315 BLOCKING=1
316 shift
317 ;;
318 -B)
319 unset BLOCKING
320 shift
321 ;;
322 -q)
323 QUIET=1
324 DEBUG=0
325 SSH_VERBOSE="-q"
326 shift
327 ;;
328 -o)
329 SSH_ARGS="$SSH_ARGS -o $2"
330 shift 2
331 ;;
332 -u)
333 UNIQUE_HOSTS=1
334 shift
335 ;;
336 -U)
337 UNIQUE_HOSTS=0
338 shift
339 ;;
340 -l)
341 DEFAULT_LOGIN=$2
342 shift 2
343 ;;
344 -L)
345 FORCE_LOGIN=$2
346 shift 2
347 ;;
348 -s)
349 REMOTE_SHELL=$2
350 shift 2
351 ;;
352 -t*)
353 SSH_TIMEOUT="${1#-t}"
354 if [ -z "$SSH_TIMEOUT" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
355 SSH_TIMEOUT=$2
356 shift
357 fi
358 if [ "${SSH_TIMEOUT//[^0-9]/}" != "$SSH_TIMEOUT" -o -z "$SSH_TIMEOUT" ] ; then
359 echo "mussh: Argument should be numeric: -t $SSH_TIMEOUT" 1>&2
360 exit 1
361 fi
362 shift
363 SSH_ARGS="$SSH_ARGS -o ConnectTimeout=$SSH_TIMEOUT"
364 ;;
365 -m*) # -m0 .. -m999
366 CONCURRENT="${1#-m}"
367 if [ -z "$CONCURRENT" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
368 CONCURRENT=$2
369 shift
370 elif [ -z "$CONCURRENT" ] ; then
371 CONCURRENT=0
372 fi
373 if [ "${CONCURRENT//[^0-9]/}" != "$CONCURRENT" ] ; then
374 echo "mussh: Argument should be numeric: -m $CONCURRENT" 1>&2
375 exit 1
376 fi
377 shift
378 ;;
379 -d*)
380 DEBUG="${1#-d}"
381 if [ -z "$DEBUG" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
382 DEBUG=$2
383 shift
384 elif [ -z "$DEBUG" ] ; then
385 DEBUG=1
386 fi
387 if [ "${DEBUG//[^0-9]/}" != "$DEBUG" ] ; then
388 echo "mussh: Argument should be numeric: -d $DEBUG" 1>&2
389 exit 1
390 fi
391 shift
392 ;;
393 -v*)
394 TMP_ARG="${1#-v}"
395 if [ -z "$TMP_ARG" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
396 TMP_ARG=$2
397 shift
398 elif [ -z "$TMP_ARG" ] ; then
399 TMP_ARG=1
400 fi
401 if [ "${TMP_ARG//[^0-9]/}" != "$TMP_ARG" ] ; then
402 echo "mussh: Argument should be numeric: -v $TMP_ARG" 1>&2
403 exit 1
404 elif [ "${TMP_ARG//[^0-3]/}" != "$TMP_ARG" ] ; then
405 echo "mussh: Argument should be between 0 and 3: -v $TMP_ARG" 1>&2
406 exit 1
407 fi
408 SSH_VERBOSE="-v"
409 [ "$TMP_ARG" -ge 2 ] && SSH_VERBOSE="$SSH_VERBOSE -v"
410 [ "$TMP_ARG" -ge 3 ] && SSH_VERBOSE="$SSH_VERBOSE -v"
411 [ "$TMP_ARG" -eq 0 ] && SSH_VERBOSE="-q"
412 shift
413 ;;
414 -V)
415 echo "Version: $MUSSH_VERSION"
416 exit
417 ;;
418 -P)
419 SSH_ARGS="$SSH_ARGS -o PasswordAuthentication=no"
420 shift
421 ;;
422 --help)
423 # print help text
424 echo "$USAGE"
425 echo "$HELPTEXT"
426 exit
427 ;;
428 -i)
429 # Load the identity file in ssh-agent
430 while [ "$2" != "" -a "${2#-}" = "$2" ] ; do
431 IDENT="$IDENT $2"
432 shift
433 done
434 shift
435 ;;
436 ##############
437 # PROXY ARGS #
438 ##############
439 -p)
440 PROXY=$2
441 SSH_ARGS="$SSH_ARGS -o ForwardAgent=yes"
442 shift 2
443 ;;
444 -po)
445 PROXY_SSH_ARGS="$PROXY_SSH_ARGS -o $2"
446 shift 2
447 ;;
448 #############
449 # HOST ARGS #
450 #############
451 -h)
452 while [ "$2" != "" -a "${2#-?*}" = "$2" ] ; do
453 HOSTLIST="$2
454 $HOSTLIST"
455 shift
456 done
457 shift
458 ;;
459 -H)
460 while [ "$2" != "" -a "${2#-?*}" = "$2" ] ; do
461 HOSTFILE="$2"
462 if [ ! -e "$HOSTFILE" -a "$HOSTFILE" != "-" ] ; then
463 echo "mussh: Host file '$HOSTFILE' does not exist!" 1>&2
464 exit 1
465 fi
466 HOSTLIST="$(cat $HOSTFILE | sed -e 's/#.*//' | egrep -v "^ *$" )
467 $HOSTLIST"
468 shift
469 done
470 shift
471 ;;
472 -n)
473 # I've left this undocumented for lack of testing. Volunteers?
474 NETGROUP=$2
475 NETGROUP_LIST="$(getent netgroup $NETGROUP | xargs -n 1 echo | sed -n '/^(.*,$/s/[,(]//gp')"
476 if [ -z "$NETGROUP_LIST" ] ; then
477 echo "mussh: Failed to get netgroup: $NETGROUP" 2>&1
478 exit 1
479 fi
480 HOSTLIST="$NETGROUP_LIST
481 $HOSTLIST"
482 shift 2
483 ;;
484 ################
485 # COMMAND ARGS #
486 ################
487 -c)
488 THESCRIPT="$THESCRIPT
489 $2"
490 #set "" ; shift
491 shift 2
492 ;;
493 -C)
494 while [ "$2" != "" -a "${2#-?*}" = "$2" ] ; do
495 SCRIPTFILE="$2"
496 if [ ! -e "$SCRIPTFILE" -a "$SCRIPTFILE" != "-" ] ; then
497 echo "mussh: Script File '$SCRIPTFILE' does not exist!" 1>&2
498 exit 1
499 fi
500 THESCRIPT="$THESCRIPT
501 $(cat $SCRIPTFILE )"
502 shift
503 done
504 shift
505 ;;
506 *)
507 echo "mussh: invalid command - \"$1\"" 1>&2
508 echo "$USAGE" 1>&2
509 exit 1
510 ;;
511 esac
512 done
513
514 #####################
515 # CLEAN UP HOSTLIST #
516 #####################
517 HOSTLIST=$(echo "$HOSTLIST" | sed -e 's/#.*//' | egrep -v "^ *$" )
518
519 if [ "$FORCE_LOGIN" != "" ] ; then
520 [ "$DEBUG" -ge 1 ] && echo "DEBUG: FORCE_LOGIN: $FORCE_LOGIN" 1>&2
521 HOSTLIST=$(echo "$HOSTLIST" | sed -e "s/^\(.*@\)\{0,1\}\([^@]*\)\$/$FORCE_LOGIN@\2/")
522 elif [ "$DEFAULT_LOGIN" != "" ] ; then
523 [ "$DEBUG" -ge 1 ] && echo "DEBUG: DEFAULT_LOGIN: $DEFAULT_LOGIN" 1>&2
524 HOSTLIST=$(echo "$HOSTLIST" | sed -e "s/^\([^@]*\)\$/$DEFAULT_LOGIN@\1/")
525 fi
526 [ $UNIQUE_HOSTS -ge 1 ] && HOSTLIST=$(echo "$HOSTLIST" | sort -uf )
527
528
529 ################
530 # CHECK SYNTAX #
531 ################
532 if [ "$HOSTLIST" = "" ] ; then
533 echo "mussh: ERROR: You must supply at least one host!" 1>&2
534 echo "$USAGE" 1>&2
535 exit 1
536 fi
537
538 ###################################
539 # DEFAULT TO STDIN IF NO COMMANDS #
540 ###################################
541 if [ "$THESCRIPT" = "" ] ; then
542 echo "Enter your script here. End with single \".\" or EOF." 1>&2
543 while read THISLINE
544 do
545 if [ "$THISLINE" = "." ] ; then
546 break
547 fi
548 THESCRIPT="$THESCRIPT
549 $THISLINE"
550 done
551 fi
552
553 ###################################################
554 # INFINITE CONCURRENCY IS REALLY JUST ALL AT ONCE #
555 ###################################################
556 COUNT_HOSTS=$(echo "$HOSTLIST" | wc -w)
557 if [ $CONCURRENT -eq 0 ] || [ $CONCURRENT -gt $COUNT_HOSTS ] ; then
558 CONCURRENT=$COUNT_HOSTS
559 [ "$DEBUG" -ge 1 ] && echo "DEBUG: setting concurrency (-m) to $CONCURRENT (all hosts)" 1>&2
560 fi
561 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Concurrency: $CONCURRENT" 1>&2
562
563 #################################
564 # ADD SSH VERBOSITY TO SSH ARGS #
565 #################################
566 if [ "$SSH_VERBOSE" ] ; then
567 SSH_ARGS="$SSH_VERBOSE $SSH_ARGS"
568 fi
569
570 ############################
571 # PRINT VERBOSE DEBUG INFO #
572 ############################
573 if [ "$DEBUG" -ge 1 ] ; then
574 echo "DEBUG: DEBUG LEVEL: $DEBUG" 1>&2
575 echo "DEBUG: SSH DEBUG LEVEL: $SSH_VERBOSE" 1>&2
576 fi
577 if [ "$DEBUG" -ge 2 ] ; then
578 echo "DEBUG: HOSTLIST: " $HOSTLIST 1>&2
579 echo "DEBUG: THE SCRIPT: $THESCRIPT" 1>&2
580 echo "DEBUG: SSH ARGS: $SSH_ARGS" 1>&2
581 fi
582
583 ############################
584 # LOAD SSH-AGENT WITH KEYS #
585 ############################
586 if [ "$NO_AGENT" = "1" ] ; then
587 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Not using ssh-agent" 1>&2
588 elif [ "$IDENT" != "" ] ; then
589 start_agent
590 load_keys "$IDENT"
591 elif [ ! -f "$HOME/.ssh/identity" -a ! -f "$HOME/.ssh/id_dsa" ] ; then
592 [ "$DEBUG" -ge 1 ] && echo "DEBUG: No identity file found. Skipping agent."
593 else
594 start_agent
595 load_keys "$IDENT"
596 fi
597 #echo
598
599 ###################
600 # CREATE TEMP DIR #
601 ###################
602 create_temp
603
604 ########################
605 # EXECUTE THE COMMANDS #
606 ########################
607 if [ -z "$CONCURRENT" ] ; then
608 CONCURRENT=1
609 fi
610
611 if [ "$PROXY" != "" ] ; then
612 proxy_connect
613
614 # Don't background process when we're only doing one at a time
615 #elif [ -z "$CONCURRENT" -o "$CONCURRENT" = 1 ] ; then
616 # set $HOSTLIST
617 # while [ "$1" != "" ] ; do
618 # HOST="$1"
619 # [ "$DEBUG" -ge 1 ] && echo "DEBUG: CONNECT $HOST" 1>&2
620 # shift
621 # ssh_connect
622 # done
623 else
624 # Fork $CONCURRENT children
625 set_hostlist
626 CHILDNUM=1
627 while [ $CHILDNUM -le $CONCURRENT ] ; do
628 run_child $CHILDNUM &
629 [ "$DEBUG" -ge 2 ] && echo "DEBUG: FORKED CHILD #$CHILDNUM with pid $!" 1>&2
630 rm -f "$TEMP_DIR/$CHILDNUM.pid"
631 echo $! > "$TEMP_DIR/$CHILDNUM.pid"
632 (( CHILDNUM++ ))
633 done
634 wait
635 # since trap causes waits to stop waiting with a return value >128
636 # We need to check that we really meant to stop waiting.
637 RETVAL=$?
638 while [ "$RETVAL" -gt 128 ] ; do
639 [ "$DEBUG" -ge 2 ] && echo "DEBUG: wait returned with a value of $RETVAL" 1>&2
640 DO_WAIT=0
641 for CPID in $(cat $TEMP_DIR/*.pid 2>/dev/null) ; do
642 if [ -d "/proc/$CPID" ] ; then
643 DO_WAIT=1
644 [ "$DEBUG" -ge 2 ] && echo "DEBUG: $CPID is still running." 1>&2
645 fi
646 done
647 [ "$DO_WAIT" = 0 ] && break
648 wait
649 done
650 fi
651
652 ############
653 # CLEAN UP #
654 ############
655 destroy_temp
656 stop_agent
657