# scp transport plugin for vcbMounter/vcbRestore
# This transport plugin uses scp to copy files to/from remote
# machines. Data is copied to/from a temporary directory. The
# location of the directory can be specified by changing the
# TEMPDIR variable in /etc/vmware/backuptools.conf
#
# (C) 2005 VMware, Inc. All rights reserved.function 



#
# Description:
# Prepare a temporary directory as a holding space for scp.
#
# Arguments:
# None.
#
# Results:
# Prints the name of the temporary directory to stdout.
# Also creates the directory. Returns 0 on success.
#
function scp_prepare_tempdir
{
    local tempname
    local rv

    tempname="${TEMPDIR}/vm-scp-$$"
    rm -fr "$tempname"
    mkdir "${tempname}"
    rv=$?
    if [ "$rv" != "0" ] ; then
	echo "Could not create temporary directory ${tempname}." >&2
	return 15
    fi
    echo "${tempname}"
    return 0
}



#
# Description:
# The COS version of OpenSSH has a bug that causes it to not print
# a progress indicator while copying stuff to the ESX host. 
#
# This function (to be run as a background task) monitors the temp.
# holding space and prints its size.
#
# Arguments:
# $1: Directory to monitor
#
# Results:
# Prints the current size of the directory that it monitors to stderr.
#
function scpP_monitor_kludge
{
    local dir="$1"
    local size

    while `true`
    do
      size=`du -sm "$dir" | cut -f1`
      echo -ne "\\rAmount of data copied: $size MB." >&2
      sleep 5
    done
}



#
# Description:
# Actually pull a set of files representing a virtual machine
# across the wire using scp.
#
# Arguments:
# $1: Remote source path in a format that scp understands:
#     <user>@<host>:<path>
# $2: Local temporary holding dir. (destination)
#
# Results:
# Conforms to transport plugin. Returns0 on success and prints
# the local directory to stdout.
#
function scpP_get_fullvm
{
    local source="$1"
    local tempdir="$2"


    # Since the remote host re-interprets the arguments passed along
    # with scp, we have to quote username and path, since both could
    # contain spaces.
    local prefix="${source%%:*}"
    local remotepath="${source#*:}"
    local remotedir="${prefix}":\"${remotepath}\"

    scp -r -o "StrictHostKeyChecking no" ${remotedir} "${tempdir}"
    rv=$?
    if [ "$rv" != "0" ] ; then
	rm -fr "${tempname}"
	echo "Secure copy (scp) of $source to ${tempname} failed with error code $rv." >&2
	return 15
    fi

    echo "${tempname}"/`basename "${remotepath}"`
    return 0
}


#
# Description:
# Get data from a remote machine using scp. Place the data
# in a local directory where vcbRestore can pick it up from.
#
# Arguments:
# $1: Remote source path in a format that scp understands:
#     <user>@<host>:<path>
# $2: "fullvm" when an entire VM is restored; "disk", if just
#     a virtual disk image is restored.
# Also uses global variable TEMPDIR for location of temporary
# directory.
#
# Results:
# Conforms to transport plugin. Returns 0 on success and prints
# the local directory to stdout.
#
function scp_get
{
    local source="$1"
    local type="$2"
    local tempname
    local prefix
    local remotepath
    local remotedir
    local base
    local rv
    local pid

    tempname=`scp_prepare_tempdir`
    rv=$?
    if [ "$rv" != "0" ] ; then
	return $rv
    fi

    # Fire up the montioring thread on the temp. dir, since the
    # current version of scp in the COS does not print any progress
    # indicators in this case.
    scpP_monitor_kludge "$tempname" &
    pid=$!

    if [ "$type" == "fullvm" ] ; then
	scpP_get_fullvm "$source" "$tempname"
	rv=$?
    elif [ "$type" == "disk" ] ; then
	echo "Restoring single virtual disks across SSH is currently unsupported." >&2
	rv=12
    else
	echo "Internal error: Backup type $type unknown." >&2
	rv=12
    fi

    ## Kill monitor kludge
    kill $pid >/dev/null 2>&1
    wait $pid >/dev/null 2>&1
    echo >&2
    echo "Data copied successfully." >&2

    return $rv
}



#
# Description:
# Deletes the local directory that scp_get created.
#
# Arguments:
# $1: Temporary directory path as returned by scp_get
#
# Results:
# None.
#
function scp_get_done
{
    local tempdir=`dirname "$1"`
    local rv

    rm -fr "$tempdir"
    rv=$?
    if [ "$rv" != "0" ] ; then
	echo "Warning: Could not remove temporary directory $tempdir" >&2
    fi

    return 0
}



#
# Description:
# Creates a local temporary directory to hold backup data.
# scp_put_done will move data to the remote machine using scp
# and delete the temporary directory created by this function.
#
# Arguments:
# $1: Destination path that must make sense to scp.
# Also uses global variable TEMPDIR for temporary directory location.
#
# Results:
# Returns 0 on success. Also prints the local directory path to
# stdout on success.
#
function scp_put
{
    local source="$1"
    local tempname
    local rv

    tempname=`scp_prepare_tempdir`
    rv=$?
    if [ "$rv" != "0" ] ; then
	return $rv
    fi
    echo "${tempname}"/`basename "${source#*:}"`
   
}



#
# Description:
# Copies data from the temporary location created by "scp_put" to
# the remote machine using scp. Deletes the temporary directory
# on success. If the operation fails, the temporary directory will
# not get deleted.
#
# Arguments:
# $1: Temporary path name (as returned by scp_put)
# $2: Remote directory name that must be parseable by scp. (Same
#     as argument for "scp_put".
# $3: 0 if the export operation was successful.
#
# Results:
# Returns 0 on success.
#
function scp_put_done
{
    local source=`dirname "$1"`
    local dest="$2"
    local ok="$3"
    local prefix
    local remotepath
    local remotedir
    local dirbase

    # Only do the scp if there is anything in the temp. dir:
    if [ "$ok" != "0" ] ; then
	echo "Export failed. Nothing to transfer to remote host." >&2
	rm -fr "$source"
	return 0
    fi

    # Since the remote host re-interprets the arguments passed along
    # with scp, we have to quote username and path, since both could
    # contain spaces.
    prefix="${dest%%:*}"
    remotepath="${dest#*:}"
    remotedir="${prefix}":\"`dirname "${remotepath}"`\"

    scp -r -o "StrictHostKeyChecking no" "${source}"/* "${remotedir}"
    rv=$?
    if [ "$rv" != "0" ] ; then
	echo "Secure copy (scp) of $source to $dest failed." >&2
	echo "Files are available locally under ${source}." >&2
	return 15
    else
	rm -fr "$source"
    fi
    return 0
}



#
# Description:
# Lists all subdirectories that potentially contain virtual machine
# backups found in a given directory. Prints all the directories that
# are candidates for virtual machine backups to stdout.
#
# Arguments
# $1: Directory containing virtual machine backups
#
# Results
# Returns 0 if a list of directories could be retrieved (list could be
# empty, tho..). 1 If there was a problem retrieving the list, 2 if
# the operation is not supported by a transport plugin.
#
function scp_listvms
{
    local sourcedir="$1"
    local host
    local path	

    # Split up user@host:path into user@host, path
    host=${sourcedir%%:*}
    path=${sourcedir#*:}

    ssh "${host}" find \"${path}\" -type d -mindepth 1 -maxdepth 1 |\
        sed s@.\*/@@g
    rv=$?
    if [ $rv != 0 ] ; then
	return 1
    fi
    return 0
}
