Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- ############################################################ IDENT(1)
- #
- # $Title: Script to get a file from a remote cloud controller $
- #
- ############################################################ GLOBALS
- #
- # Program name
- #
- pgm="${0##*/}"
- #
- # Global exit status
- #
- SUCCESS=0
- FAILURE=1
- #
- # Command-line options
- #
- DRYRUN=
- RECURSE=
- TELNET=
- VERBOSE=
- #
- # Miscellaneous
- #
- CONTROLLERS=
- OUTPUT=
- PROMPT1="$( id -nu )@$( hostname ) expect> "
- PROMPT2="expect> "
- REMOTE_FILE=
- ############################################################ FUNCTIONS
- usage()
- {
- local optfmt="\t%-4s %s\n"
- exec >&2
- printf "Usage: %s [OPTIONS] host:file1 ... dir|file2\n" "$pgm"
- printf " %s [OPTIONS] -T port:file1 ... dir|file2\n" "$pgm"
- printf "\n"
- printf "OPTIONS:\n"
- printf "$optfmt" "-n" \
- "Dry run. Show what would be written but don't do anything."
- printf "$optfmt" "-r" \
- "Recursively copy the contents of directories."
- printf "$optfmt" "-T" \
- "Telnet to port on localhost instead of \`connect host'."
- printf "$optfmt" "-v" \
- "Verbose. Print a line for each successfully written file."
- exit $FAILURE
- }
- ############################################################ MAIN
- #
- # Process command-line options
- #
- while getopts nrTv flag; do
- case "$flag" in
- n) DRYRUN=1 ;;
- r) RECURSE=$(( ${RECURSE:-0} + 1 )) ;;
- T) TELNET=1 ;;
- v) VERBOSE=1 ;;
- \?|*) usage
- esac
- done
- shift $(( $OPTIND - 1 ))
- #
- # Validate arguments
- #
- [ $# -lt 2 ] && usage
- eval OUTPUT=\"\${$#}\"
- [ "$OUTPUT" ] || usage
- n=1
- while [ $n -lt $# ]; do
- eval argn=\"\${$n}\"
- case "$argn" in
- "") usage ;;
- *:) echo "$pgm: Missing file: $argn" >&2
- usage ;;
- :*) echo "$pgm: Missing host: $argn" >&2
- usage ;;
- *:*) cc="${1%%:*}" REMOTE_FILE="${1#*:}" ;;
- *) echo "$pgm: Missing host: $argn" >&2
- usage
- esac
- case "$cc" in
- *[!.0-9a-zA-Z-]*)
- echo "$pgm: Invalid hostname: $cc" >&2
- usage ;;
- esac
- case "$CONTROLLERS" in
- *" $cc "*) : skip ;;
- *) CONTROLLERS="${CONTROLLERS% } $cc "
- esac
- n=$(( $n + 1 ))
- done
- #
- # XXX Warn user of an edge-case with `-r' XXX
- #
- # NB: This edge-case should go away after specifically addressing recursion.
- # NB: All files in remote directory hierarchy end up in top-level of the given
- # destination directory.
- #
- if [ ${RECURSE:-0} -lt 2 ]; then
- echo "WARNING! Recursion not fully functional yet." >&2
- echo "WARNING! Remote hierarchy not replicated locally!" >&2
- echo "WARNING! Use \`-r' twice to acknowledge and proceed." >&2
- exit $FAILURE
- fi
- #
- # Command to send to Remote Application Server (RAS)
- #
- # NB: Use %s to refer to the current path argument being processed
- # NB: Newlines are removed (so make sure semi-colons are used appropriately)
- #
- exec 9<<-EOF
- exec 3<&1;
- ( for p in %s; do
- RECURSE=$RECURSE;
- if [ -f "\$p" ]; then
- ${DRYRUN:+echo} b64encode "\$p" "\$p";
- elif [ -d "\$p" -a "\$RECURSE" ]; then
- find "\$p" -type f -print0 | xargs -0rn1 -Ifile \
- ${DRYRUN:+echo} b64encode file file;
- else
- echo "SEND_ERROR: $pgm: \$p: not a regular file";
- fi;
- done ) 2>&1 >&3 | (
- while read ERROR; do
- echo "SEND_ERROR: \$ERROR";
- done
- )
- EOF
- RAS_CMD=$( cat <&9 )
- #
- # Interact with each remote application server
- #
- for CONTROLLER in $CONTROLLERS; do
- if [ "$TELNET" ]; then
- spawn_cmd="telnet localhost $CONTROLLER"
- else
- spawn_cmd="connect $CONTROLLER"
- fi
- expect -f- "$RAS_CMD" "$@" <<-EOF | awk \
- -v prefix="$OUTPUT" \
- -v verbose="$VERBOSE" \
- ' # BEGIN AWK
- BEGIN {
- gsub(/'\''/, "'\'\\\\\''&", prefix)
- dir = system("[ -d '\''" prefix "'\'' ]") == 0 ? 1 : 0
- }
- function output(file)
- {
- if (dir) {
- filename = file
- sub(".*/", "", filename)
- gsub(/'\''/, "'\'\\\\\''&", filename)
- return prefix "/" filename
- } else
- return prefix
- }
- match($0, /^SEND_USER: /) {
- print substr($0, RSTART + RLENGTH)
- }
- match($0, /^SEND_ERROR: /) {
- print substr($0, RSTART + RLENGTH) > "/dev/stderr"
- }
- /^====/ {
- if (verbose) print OUTPUT_FILE
- close(cmd)
- close(OUTPUT_FILE)
- dump = 0
- }
- dump && sub(/(\r|)$/, "") { print | cmd }
- match($0, /begin-base64 [0-7]+ /) {
- file = substr($0, RSTART + RLENGTH)
- sub(/\r$/, "", file)
- OUTPUT_FILE = output(file)
- close(cmd) # Pedantic
- close(OUTPUT_FILE)
- cmd = "base64 -d - > '\''" OUTPUT_FILE "'\''"
- dump = 1
- }
- # DRYRUN processing
- match($0, /^b64encode /) {
- file = substr($0, RSTART + RLENGTH)
- file = substr(file, 0, (length(file)-1)/2)
- print output(file)
- }
- ' # END AWK
- # BEGIN EXPECT
- set timeout 300
- set argnum 1
- set argmax [expr {[llength \$argv]-1}]
- if {\$argmax < 2} exit
- set echars "\\t \\"$&'();<>\\\\\\\\\`|"
- proc escape {path} {
- global echars
- regsub -all "(\\[\$echars\\])" \$path {\\\\\\1} path
- regsub -all {(\n)} \$path {'\\1'} path
- return \$path
- }
- set cc "$CONTROLLER:"
- set cclen [expr {[string length \$cc]-1}]
- set ras_cmd [lindex \$argv 0]
- regsub -all {\n} \$ras_cmd { } ras_cmd
- spawn $spawn_cmd
- expect -re {#\s+$} {
- send "PS1='$PROMPT1' PS2='$PROMPT2'\n"
- }
- while {\$argnum < \$argmax} {
- set path [lindex \$argv \$argnum]
- if {[string range \$path 0 \$cclen] != \$cc} {
- incr argnum
- continue
- }
- regsub {^[^:]+:} \$path "" path
- set path [escape \$path]
- expect -re {$PROMPT1$} {
- regsub "%s" \$ras_cmd "\$path" ras_cmd_out
- send "\$ras_cmd_out \\\\\n"
- }
- expect -re {$PROMPT2$} {
- incr argnum
- if {\$argnum < \$argmax} {
- send "\n"
- } else {
- send "; exit\n"
- }
- }
- }
- expect eof
- EOF
- done
- exit $SUCCESS
- ################################################################################
- # END
- ################################################################################
- #
- # $Copyright: 2015 Devin Teske. All rights reserved. $
- #
- # $Header$
- #
- ################################################################################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement