"Fossies" - the Fresh Open Source Software Archive 
Member "mussh/mussh.bak" (25 Oct 2011, 20807 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 # INITAILIZE THIS CRAP #
17 ########################
18 DEBUG=0
19 SSH_VERBOSE="-q"
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 infinate. (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 -n <netgroup> Get list of hosts from netgroup
79 COMMAND ARGS:
80 If neither is specified, commands will be read from standard input.
81 -c <command> Add a command or quoted list of commands and
82 args to list of commands to be executed on
83 each host. May be used more than once.
84 -C <file> [file ..]
85 Add file contents to list of commands to be
86 executed on each host. May be used more
87 than once.
88
89 At least one host is required. Arguments are in no particular order.
90
91 EXAMPLES:
92 mussh -H ./linuxhosts -C spfiles/testscript.sh
93 mussh -c \"cat /etc/hosts\" -h myhost.mydomain.com
94
95 Comments and Bug Reports: doughnut@doughnut.net
96 "
97
98 ###########################
99 # FUNCTIONS FOR SSH-AGENT #
100 ###########################
101 load_keys() {
102 [ "$AGENT_LOADED" = "0" -a "$IDENT" = "" ] && return
103 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Adding Keys" 1>&2
104 ssh-add $* 1>&2
105 }
106
107 start_agent() {
108 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Starting Agent" 1>&2
109 if [ "$FORCE_AGENT" -ge 1 ] ; then
110 # Load it anyway
111 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Forcing SSH Agent" 1>&2
112 elif [ -S "$SSH_AUTH_SOCK" ] ; then
113 [ "$DEBUG" -ge 1 ] && echo "DEBUG: SSH Agent already loaded" 1>&2
114 return
115 fi
116 eval $(ssh-agent -s) >/dev/null
117 AGENT_LOADED=1
118 }
119 stop_agent() {
120 # get rid of the keys that we added (if any)
121 if [ "$IDENT" != "" ] ; then
122 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Removing keys from agent" 1>&2
123 ssh-add -d $IDENT > /dev/null 2>&1
124 fi
125 [ "$AGENT_LOADED" = "0" ] && return
126 [ "$DEBUG" -ge 1 ] && echo "DEBUG: Stopping Agent" 1>&2
127 eval $(ssh-agent -s -k) >/dev/null
128 }
129
130 ####################################
131 # FUNCTIONS FOR REMOTE CONNECTIONS #
132 ####################################
133 proxy_connect() {
134 [ "$DEBUG" -ge 1 ] && echo "DEBUG: PROXY CONNECT $PROXY" 1>&2
135 echo "$THESCRIPT" \
136 | ssh -T $SSH_ARGS $PROXY \
137 "mussh -h $HOSTLIST \
138 -C - \
139 -d$DEBUG \
140 $PROXY_SSH_ARGS 2>&1 " \
141 | while read SSH_LINE ; do
142 if [ "$QUIET" -lt 1 -a "$SSH_LINE" != "" ] ; then
143 echo "$SSH_LINE" | sed -e "s/^/$HOST: /"
144 fi
145 done
146 }
147
148 ssh_connect() {
149 echo "$THESCRIPT" \
150 | ssh -T $SSH_ARGS $HOST "$REMOTE_SHELL" 2>&1 \
151 | while read SSH_LINE ; do
152 if [ "$QUIET" -lt 1 -a "$SSH_LINE" != "" ] ; then
153 echo "$SSH_LINE" | sed -e "s/^/$HOST: /"
154 fi
155 done
156 }
157
158 ##############################
159 # FUNCTIONS FOR FORKED PROCS #
160 ##############################
161 set_hostlist() {
162 # Create a hostlist file.
163 [ "$DEBUG" -ge 2 ] && echo "DEBUG: BUILDING HOST LIST FILE $TEMP_DIR/hostlist" 1>&2
164 rm -f $TEMP_DIR/hostlist || exit 1
165 for HOST in $HOSTLIST ; do
166 echo $HOST >> "$TEMP_DIR/hostlist" || exit 1
167 done
168 }
169
170 get_next_host() {
171 # lock file
172 while [ 1 ] ; do
173 echo $CHILDNUM >> "$TEMP_DIR/hostlist.lock"
174 TOP_PID=$(head -1 "$TEMP_DIR/hostlist.lock" 2>/dev/null)
175 if [ "$TOP_PID" = $CHILDNUM ] ; then
176 break
177 fi
178 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: hostlist file already locked. Sleep..." 1>&2
179 #usleep 1000
180 sleep 1
181 done
182 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Locked hostfile." 1>&2
183
184 # get next host
185 NEXT_HOST=$(head -1 $TEMP_DIR/hostlist)
186 HOSTFILE_LEN=$(wc -l $TEMP_DIR/hostlist | awk '{print $1}')
187 if [ -z "$HOSTFILE_LEN" -o "$HOSTFILE_LEN" = 0 ] ; then
188 rm -f "$TEMP_DIR/hostlist.lock"
189 return
190 fi
191 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Next host: $NEXT_HOST" 1>&2
192
193 # re-write file removing new host
194 rm -f "$TEMP_DIR/hostlist.new"
195 echo tail -$(expr $HOSTFILE_LEN - 1) $TEMP_DIR/hostlist > $TEMP_DIR/hostlist.new || exit 1
196 tail -$(expr $HOSTFILE_LEN - 1) $TEMP_DIR/hostlist > $TEMP_DIR/hostlist.new || exit 1
197 rm -f "$TEMP_DIR/hostlist"
198 mv "$TEMP_DIR/hostlist.new" "$TEMP_DIR/hostlist"
199
200 # unlock file
201 [ "$DEBUG" -ge 2 ] && echo "DEBUG[#$CHILDNUM]: Removing hostfile lock." 1>&2
202 rm -f "$TEMP_DIR/hostlist.lock"
203
204 # return hostname
205 echo $NEXT_HOST
206 }
207
208 run_child() {
209 trap "exit 0" SIGHUP
210 CHILDNUM=$1
211 [ "$DEBUG" -ge 2 ] && echo "DEBUG: FORKING CHILD #$CHILDNUM of $CONCURRENT (pid $!/$$)" 1>&2
212 while [ 1 ] ; do
213
214 # issue: Cannot call get_next_host inside $() or `` because our trap won't be able to kill that.
215 # solution: avoid subshell here by directing to a file.
216 rm -f $TEMP_DIR/$CHILDNUM.next_host
217 get_next_host >$TEMP_DIR/$CHILDNUM.next_host
218 HOST=$(<$TEMP_DIR/$CHILDNUM.next_host)
219 if [ -z "$HOST" ] ; then
220 rm -f "$TEMP_DIR/$CHILDNUM.pid"
221 break
222 fi
223 [ "$DEBUG" -ge 1 ] && echo "DEBUG[#$CHILDNUM]: CONNECT $HOST" 1>&2
224
225 rm -f "$TEMP_DIR/$CHILDNUM.active"
226 echo "$HOST" > "$TEMP_DIR/$CHILDNUM.active"
227 if [ -n "$BLOCKING" ] ; then
228 ssh_connect > $TEMP_DIR/$HOST.out
229 cat $TEMP_DIR/$HOST.out
230 else
231 ssh_connect
232 fi
233 done
234 [ "$DEBUG" -ge 2 ] && echo "DEBUG: CHILD #$CHILDNUM done" 1>&2
235 rm -f "$TEMP_DIR/$CHILDNUM.pid" "$TEMP_DIR/$CHILDNUM.active"
236 }
237
238
239 ###########################
240 # FUNCTIONS FOR TEMP DIRS #
241 ###########################
242 create_temp() {
243 MKTEMP=$(which mktemp 2>/dev/null)
244 if [ -x "$MKTEMP" ] ; then
245 [ "$DEBUG" -ge 2 ] && echo "DEBUG: using mktemp ($MKTEMP)." 1>&2
246 TEMP_DIR=$(mktemp -d $TEMP_BASE/$(basename $0).XXXXXX) || exit 1
247 else
248 [ "$DEBUG" -ge 2 ] && echo "DEBUG: can't find mktemp... using alternate." 1>&2
249 TEMP_DIR="$TEMP_BASE/$(basename $0).$(date +%s)"
250 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Creating temp dir ($TEMP_DIR)." 1>&2
251 if [ -e "$TEMP_DIR" ] ; then
252 echo "$0: Temp dir \"$TEMP_DIR\" already exists!" 1>&2
253 exit 1
254 fi
255 mkdir -m 700 $TEMP_DIR
256 fi
257 }
258
259 destroy_temp() {
260 if [ -d "$TEMP_DIR" ] ; then
261 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Removing temp dir ($TEMP_DIR)." 1>&2
262 rm -rf "$TEMP_DIR" 2>/dev/null
263 fi
264 }
265
266
267
268 ########################################
269 # REMEMBER TO CLEAN UP BEFORE WE PANIC #
270 ########################################
271 shutdown() {
272 [ "$DEBUG" -ge 1 ] && echo "DEBUG: shutting down children." 1>&2
273 CPIDS=$(cat $TEMP_DIR/*.pid 2>/dev/null)
274 for CPID in $CPIDS ; do
275 [ "$DEBUG" -ge 2 ] && echo "DEBUG: Killing pid: $CPID" 1>&2
276 kill -HUP $CPID
277 done
278 [ "$DEBUG" -ge 2 ] && echo "DEBUG: shutting down ssh-agent" 1>&2
279 stop_agent
280 [ "$DEBUG" -ge 2 ] && echo "DEBUG: removing temp dir" 1>&2
281 destroy_temp
282 [ "$DEBUG" -ge 2 ] && echo "DEBUG: done shutting down." 1>&2
283 exit 1
284 }
285
286 spew_hostlist() {
287 echo "HOSTS RUNNING:" 1>&2
288 cat $TEMP_DIR/*.active 2>/dev/null | sed 's/^/ /' 1>&2
289 echo "HOSTS REMAINING:" 1>&2
290 cat $TEMP_DIR/hostlist 2>/dev/null | sed 's/^/ /' 1>&2
291 return
292 }
293
294 trap shutdown SIGINT
295 trap shutdown SIGTERM
296 trap spew_hostlist SIGQUIT
297 trap "exit 0" SIGHUP
298
299 #############################
300 # PARSE THE COMMAND OPTIONS #
301 #############################
302 while [ "$1" != "" ]; do
303 case "$1" in
304 ###########
305 # OPTIONS #
306 ###########
307 -A)
308 NO_AGENT=1
309 shift
310 ;;
311 -a)
312 FORCE_AGENT=1
313 shift
314 ;;
315 -b)
316 BLOCKING=1
317 shift
318 ;;
319 -B)
320 unset BLOCKING
321 shift
322 ;;
323 -q)
324 QUIET=1
325 DEBUG=0
326 SSH_VERBOSE="-q"
327 shift
328 ;;
329 -o)
330 SSH_ARGS="$SSH_ARGS -o $2"
331 shift 2
332 ;;
333 -u)
334 UNIQUE_HOSTS=1
335 shift
336 ;;
337 -U)
338 UNIQUE_HOSTS=0
339 shift
340 ;;
341 -l)
342 DEFAULT_LOGIN=$2
343 shift 2
344 ;;
345 -L)
346 FORCE_LOGIN=$2
347 shift 2
348 ;;
349 -s)
350 REMOTE_SHELL=$2
351 shift 2
352 ;;
353 -t*)
354 SSH_TIMEOUT="${1#-t}"
355 if [ -z "$SSH_TIMEOUT" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
356 SSH_TIMEOUT=$2
357 shift
358 fi
359 if [ "${SSH_TIMEOUT//[^0-9]/}" != "$SSH_TIMEOUT" -o -z "$SSH_TIMEOUT" ] ; then
360 echo "mussh: Arguement should be numeric: -t $SSH_TIMEOUT" 1>&2
361 exit 1
362 fi
363 shift
364 SSH_ARGS="$SSH_ARGS -o ConnectTimeout=$SSH_TIMEOUT"
365 ;;
366 -m*) # -m0 .. -m999
367 CONCURRENT="${1#-m}"
368 if [ -z "$CONCURRENT" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
369 CONCURRENT=$2
370 shift
371 elif [ -z "$CONCURRENT" ] ; then
372 CONCURRENT=0
373 fi
374 if [ "${CONCURRENT//[^0-9]/}" != "$CONCURRENT" ] ; then
375 echo "mussh: Arguement should be numeric: -m $CONCURRENT" 1>&2
376 exit 1
377 fi
378 shift
379 ;;
380 -d*)
381 DEBUG="${1#-d}"
382 if [ -z "$DEBUG" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
383 DEBUG=$2
384 shift
385 elif [ -z "$DEBUG" ] ; then
386 DEBUG=1
387 fi
388 if [ "${DEBUG//[^0-9]/}" != "$DEBUG" ] ; then
389 echo "mussh: Arguement should be numeric: -d $DEBUG" 1>&2
390 exit 1
391 fi
392 shift
393 ;;
394 -v*)
395 TMP_ARG="${1#-v}"
396 if [ -z "$TMP_ARG" -a -n "$2" -a "${2#-?*}" = "$2" ] ; then
397 TMP_ARG=$2
398 shift
399 elif [ -z "$TMP_ARG" ] ; then
400 TMP_ARG=1
401 fi
402 if [ "${TMP_ARG//[^0-9]/}" != "$TMP_ARG" ] ; then
403 echo "mussh: Arguement should be numeric: -v $TMP_ARG" 1>&2
404 exit 1
405 elif [ "${TMP_ARG//[^0-3]/}" != "$TMP_ARG" ] ; then
406 echo "mussh: Arguement should be between 0 and 3: -v $TMP_ARG" 1>&2
407 exit 1
408 fi
409 SSH_VERBOSE="-v"
410 [ "$TMP_ARG" -ge 2 ] && SSH_VERBOSE="$SSH_VERBOSE -v"
411 [ "$TMP_ARG" -ge 3 ] && SSH_VERBOSE="$SSH_VERBOSE -v"
412 [ "$TMP_ARG" -eq 0 ] && SSH_VERBOSE="-q"
413 shift
414 ;;
415 -V)
416 echo "Version: $MUSSH_VERSION"
417 exit
418 ;;
419 -P)
420 SSH_ARGS="$SSH_ARGS -o PasswordAuthentication=no"
421 shift
422 ;;
423 --help)
424 # print help text
425 echo "$USAGE"
426 echo "$HELPTEXT"
427 exit
428 ;;
429 -i)
430 # Load the identity file in ssh-agent
431 while [ "$2" != "" -a "${2#-}" = "$2" ] ; do
432 IDENT="$IDENT $2"
433 shift
434 done
435 shift
436 ;;
437 ##############
438 # PROXY ARGS #
439 ##############
440 -p)
441 PROXY=$2
442 SSH_ARGS="$SSH_ARGS -o ForwardAgent=yes"
443 shift 2
444 ;;
445 -po)
446 PROXY_SSH_ARGS="$PROXY_SSH_ARGS -o $2"
447 shift 2
448 ;;
449 #############
450 # HOST ARGS #
451 #############
452 -h)
453 while [ "$2" != "" -a "${2#-?*}" = "$2" ] ; do
454 HOSTLIST="$2
455 $HOSTLIST"
456 shift
457 done
458 shift
459 ;;
460 -H)
461 while [ "$2" != "" -a "${2#-?*}" = "$2" ] ; do
462 HOSTFILE="$2"
463 if [ ! -e "$HOSTFILE" -a "$HOSTFILE" != "-" ] ; then
464 echo "mussh: Host file '$HOSTFILE' does not exist!" 1>&2
465 exit 1
466 fi
467 HOSTLIST="$(cat $HOSTFILE | sed -e 's/#.*//' | egrep -v "^ *$" )
468 $HOSTLIST"
469 shift
470 done
471 shift
472 ;;
473 -n)
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 # INFINATE 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