Advertisement
devinteske

rget2

Jul 1st, 2015
443
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 8.28 KB | None | 0 0
  1. #!/bin/sh
  2. ############################################################ IDENT(1)
  3. #
  4. # $Title: Script to get a file from a remote cloud controller $
  5. #
  6. ############################################################ GLOBALS
  7.  
  8. #
  9. # Program name
  10. #
  11. pgm="${0##*/}"
  12.  
  13. #
  14. # Global exit status
  15. #
  16. SUCCESS=0
  17. FAILURE=1
  18.  
  19. #
  20. # Command-line options
  21. #
  22. DRYRUN=
  23. RECURSE=
  24. TELNET=
  25. VERBOSE=
  26.  
  27. #
  28. # Miscellaneous
  29. #
  30. CONTROLLERS=
  31. OUTPUT=
  32. PROMPT1="$( id -nu )@$( hostname ) expect> "
  33. PROMPT2="expect> "
  34. REMOTE_FILE=
  35.  
  36. ############################################################ FUNCTIONS
  37.  
  38. usage()
  39. {
  40.         local optfmt="\t%-4s %s\n"
  41.         exec >&2
  42.         printf "Usage: %s [OPTIONS] host:file1 ... dir|file2\n" "$pgm"
  43.         printf "       %s [OPTIONS] -T port:file1 ... dir|file2\n" "$pgm"
  44.         printf "\n"
  45.         printf "OPTIONS:\n"
  46.         printf "$optfmt" "-n" \
  47.                 "Dry run. Show what would be written but don't do anything."
  48.         printf "$optfmt" "-r" \
  49.                 "Recursively copy the contents of directories."
  50.         printf "$optfmt" "-T" \
  51.                 "Telnet to port on localhost instead of \`connect host'."
  52.        printf "$optfmt" "-v" \
  53.                "Verbose. Print a line for each successfully written file."
  54.        exit $FAILURE
  55. }
  56.  
  57. ############################################################ MAIN
  58.  
  59. #
  60. # Process command-line options
  61. #
  62. while getopts nrTv flag; do
  63.        case "$flag" in
  64.        n) DRYRUN=1 ;;
  65.        r) RECURSE=$(( ${RECURSE:-0} + 1 )) ;;
  66.        T) TELNET=1 ;;
  67.        v) VERBOSE=1 ;;
  68.        \?|*) usage
  69.        esac
  70. done
  71. shift $(( $OPTIND - 1 ))
  72.  
  73. #
  74. # Validate arguments
  75. #
  76. [ $# -lt 2 ] && usage
  77. eval OUTPUT=\"\${$#}\"
  78. [ "$OUTPUT" ] || usage
  79. n=1
  80. while [ $n -lt $# ]; do
  81.        eval argn=\"\${$n}\"
  82.        case "$argn" in
  83.        "") usage ;;
  84.        *:) echo "$pgm: Missing file: $argn" >&2
  85.            usage ;;
  86.        :*) echo "$pgm: Missing host: $argn" >&2
  87.            usage ;;
  88.        *:*) cc="${1%%:*}" REMOTE_FILE="${1#*:}" ;;
  89.        *) echo "$pgm: Missing host: $argn" >&2
  90.           usage
  91.        esac
  92.        case "$cc" in
  93.        *[!.0-9a-zA-Z-]*)
  94.                echo "$pgm: Invalid hostname: $cc" >&2
  95.                usage ;;
  96.        esac
  97.        case "$CONTROLLERS" in
  98.        *" $cc "*) : skip ;;
  99.        *) CONTROLLERS="${CONTROLLERS% } $cc "
  100.        esac
  101.        n=$(( $n + 1 ))
  102. done
  103.  
  104. #
  105. # XXX Warn user of an edge-case with `-r' XXX
  106. #
  107. # NB: This edge-case should go away after specifically addressing recursion.
  108. # NB: All files in remote directory hierarchy end up in top-level of the given
  109. #     destination directory.
  110. #
  111. if [ ${RECURSE:-0} -lt 2 ]; then
  112.        echo "WARNING! Recursion not fully functional yet." >&2
  113.        echo "WARNING! Remote hierarchy not replicated locally!" >&2
  114.        echo "WARNING! Use \`-r' twice to acknowledge and proceed." >&2
  115.        exit $FAILURE
  116. fi
  117.  
  118. #
  119. # Command to send to Remote Application Server (RAS)
  120. #
  121. # NB: Use %s to refer to the current path argument being processed
  122. # NB: Newlines are removed (so make sure semi-colons are used appropriately)
  123. #
  124. exec 9<<-EOF
  125.        exec 3<&1;
  126.        ( for p in %s; do
  127.                RECURSE=$RECURSE;
  128.                if [ -f "\$p" ]; then
  129.                        ${DRYRUN:+echo} b64encode "\$p" "\$p";
  130.                elif [ -d "\$p" -a "\$RECURSE" ]; then
  131.                        find "\$p" -type f -print0 | xargs -0rn1 -Ifile \
  132.                                ${DRYRUN:+echo} b64encode file file;
  133.                else
  134.                        echo "SEND_ERROR: $pgm: \$p: not a regular file";
  135.                fi;
  136.        done ) 2>&1 >&3 | (
  137.                while read ERROR; do
  138.                        echo "SEND_ERROR: \$ERROR";
  139.                done
  140.        )
  141. EOF
  142. RAS_CMD=$( cat <&9 )
  143.  
  144. #
  145. # Interact with each remote application server
  146. #
  147. for CONTROLLER in $CONTROLLERS; do
  148.  
  149.        if [ "$TELNET" ]; then
  150.                spawn_cmd="telnet localhost $CONTROLLER"
  151.        else
  152.                spawn_cmd="connect $CONTROLLER"
  153.        fi
  154.  
  155.        expect -f- "$RAS_CMD" "$@" <<-EOF | awk \
  156.                -v prefix="$OUTPUT" \
  157.                -v verbose="$VERBOSE" \
  158.        ' # BEGIN AWK
  159.  
  160.                 BEGIN {
  161.                         gsub(/'\''/, "'\'\\\\\''&", prefix)
  162.                        dir = system("[ -d '\''" prefix "'\'' ]") == 0 ? 1 : 0
  163.                }
  164.  
  165.                function output(file)
  166.                {
  167.                        if (dir) {
  168.                                filename = file
  169.                                sub(".*/", "", filename)
  170.                                gsub(/'\''/, "'\'\\\\\''&", filename)
  171.                                return prefix "/" filename
  172.                        } else
  173.                                return prefix
  174.                }
  175.  
  176.                match($0, /^SEND_USER: /) {
  177.                        print substr($0, RSTART + RLENGTH)
  178.                }
  179.                match($0, /^SEND_ERROR: /) {
  180.                        print substr($0, RSTART + RLENGTH) > "/dev/stderr"
  181.                }
  182.  
  183.                /^====/ {
  184.                        if (verbose) print OUTPUT_FILE
  185.                        close(cmd)
  186.                        close(OUTPUT_FILE)
  187.                        dump = 0
  188.                }
  189.  
  190.                dump && sub(/(\r|)$/, "") { print | cmd }
  191.  
  192.                match($0, /begin-base64 [0-7]+ /) {
  193.                        file = substr($0, RSTART + RLENGTH)
  194.                        sub(/\r$/, "", file)
  195.                        OUTPUT_FILE = output(file)
  196.                        close(cmd) # Pedantic
  197.                        close(OUTPUT_FILE)
  198.                        cmd = "base64 -d - > '\''" OUTPUT_FILE "'\''"
  199.                        dump = 1
  200.                }
  201.  
  202.                # DRYRUN processing
  203.                match($0, /^b64encode /) {
  204.                        file = substr($0, RSTART + RLENGTH)
  205.                        file = substr(file, 0, (length(file)-1)/2)
  206.                        print output(file)
  207.                }
  208.  
  209.        ' # END AWK
  210.  
  211.                 # BEGIN EXPECT
  212.                 set timeout 300
  213.  
  214.                 set argnum 1
  215.                 set argmax [expr {[llength \$argv]-1}]
  216.                 if {\$argmax < 2} exit
  217.  
  218.                 set echars "\\t \\"$&'();<>\\\\\\\\\`|"
  219.                 proc escape {path} {
  220.                         global echars
  221.                         regsub -all "(\\[\$echars\\])" \$path {\\\\\\1} path
  222.                         regsub -all {(\n)} \$path {'\\1'} path
  223.                         return \$path
  224.                 }
  225.  
  226.                 set cc "$CONTROLLER:"
  227.                 set cclen [expr {[string length \$cc]-1}]
  228.  
  229.                 set ras_cmd [lindex \$argv 0]
  230.                 regsub -all {\n} \$ras_cmd { } ras_cmd
  231.  
  232.                 spawn $spawn_cmd
  233.  
  234.                 expect -re {#\s+$} {
  235.                         send "PS1='$PROMPT1' PS2='$PROMPT2'\n"
  236.                 }
  237.  
  238.                 while {\$argnum < \$argmax} {
  239.  
  240.                         set path [lindex \$argv \$argnum]
  241.                         if {[string range \$path 0 \$cclen] != \$cc} {
  242.                                 incr argnum
  243.                                 continue
  244.                         }
  245.  
  246.                         regsub {^[^:]+:} \$path "" path
  247.                         set path [escape \$path]
  248.  
  249.                         expect -re {$PROMPT1$} {
  250.                                 regsub "%s" \$ras_cmd "\$path" ras_cmd_out
  251.                                 send "\$ras_cmd_out \\\\\n"
  252.                         }
  253.  
  254.                         expect -re {$PROMPT2$} {
  255.                                 incr argnum
  256.                                 if {\$argnum < \$argmax} {
  257.                                         send "\n"
  258.                                 } else {
  259.                                         send "; exit\n"
  260.                                 }
  261.                         }
  262.                 }
  263.  
  264.                 expect eof
  265.         EOF
  266. done
  267.  
  268. exit $SUCCESS
  269.  
  270. ################################################################################
  271. # END
  272. ################################################################################
  273. #
  274. # $Copyright: 2015 Devin Teske. All rights reserved. $
  275. #
  276. # $Header$
  277. #
  278. ################################################################################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement