#!/bin/bash 
#  COPYOUT - copy the listed files to the indicated node and directory.
#  Utility script for the data assimilation implementation on Beowulf clusters.
#
# SYNOPSIS
#   copyout [options] files
#
# OPTIONS
#   -w dir  : Copy the files to dir  (default: /scratch/$USER)
#   -N node : Remote machine to copy to (default: current node)
#   -r      :  If remote copies are successful, remove files on the source node.
#   -v      :  print the current version date and exit.
#
# DESCRIPTION
#  Copyout copies files to the indicated directory on the node named by -N.
#  The destination directory is created as needed on the remote node.
#  If the remote node is the same as the current node, then copyout does
#  an ordinary copy (with cp), provided that the destination directory differs
#  from the current one.
#
# NOTES
#  The command-line arguments to this script are a subset of those to
#  the component programs of the data assimilation software.
#
#  REVISION HISTORY
#  09/10/04 : allowed the destination and source nodes to be the same.
#  10/03/03 : previous production version.
#--------------------------------------------------------------------------
#  Variables in UPPER CASE are command-line arguments.  Those in lower case
#  are internal to the script.
#  11/23/04 - handle the case where the destination node is the same as
#  the source node; just do a regular copy or no-op as appropriate.
#
#--------------------------------------------------------------------------
function usage {
    echo "Usage: $0 [options] files"
    echo "Version: $version"
    echo "Options:"
    echo "-h (to print this message)"
    echo "-N remote_node_name (current: $DESTNODE)"
    echo "-w destination directory on remote node; current: $DESTDIR)"
    echo "   The destination directory should be an absolute pathname"
    echo "-r (remove sources when copying is complete)"
    exit 1
}
#--------------------------------------------------------------------------
function copy_to_node {
#  Copy the files in the argument list.  Check that everything arrived OK;
#  retry once and exit unsuccessfully if that doesn't work.
#
   errcode=0
   for file in $*
   do
      if [ ! -f $file ]
      then
         echo $0: $file: not found 1>&2
         errcode=1
         continue   #back to top of "for" loop
      fi
      base=$(basename $file)
      remote=$DESTDIR/$base
      rsh $DESTNODE rm -f $remote    # delete any predecessor
      rcp $file ${DESTNODE}:$remote
      rcpret=$?
      if [ $rcpret -eq 0 ]
      then
         checksum=$(cksum $file | cut -d ' ' -f 1-2)
         rcheck=$(rsh $DESTNODE cksum $remote | cut -d ' ' -f 1-2)
         if [ "$checksum" != "$rcheck" ]   # try again
         then
	 rcp $file ${DESTNODE}:$remote
	 rcheck=$(rsh $DESTNODE cksum $remote | cut -d ' ' -f 1-2)
	 if [ "$checksum" != "$rcheck" ]   # give up
	 then
	    echo $0: "error copying $file to $DESTNODE" 1>&2
	    echo $0: "original checksum: $checksum" 1>&2
	    echo $0: "copied checksum: $rcheck" 1>&2
	    errcode=1
	 fi
         elif [ $remove -ne 0 ]
         then
	 rm -f $file
         fi
      else
         errcode=$rcpret
      fi
   done
   return $errcode
}
#--------------------------------------------------------------------------
#  Set defaults

version="11/23/04"
DESTNODE=$(hostname -a)   # local copy
DESTDIR="/scratch/$USER"
remove=0    # don't delete source files when copying is complete
host=$(hostname -a)  # name of the current host

#  Parse the command line
while getopts hN:w:rv opt
do
    case $opt in
    h)  usage;;
    N)  DESTNODE=$OPTARG;;
    r)  remove=1;;
    w)  DESTDIR=$OPTARG;;
    v)  echo $0: version: $version; exit 0 ;;
    \?) usage ;;
    esac
done

#  Create temporary working directories as needed
if [ $host != $DESTNODE ]
then
   ek=$(rsh $DESTNODE "mkdir -p $DESTDIR || echo \$?")
   if [ -n "$ek" ]
   then
      echo "error exit $ek on ${DESTNODE}: cannot create $DESTDIR" 1>&2
      exit 1
   fi
else
   mkdir -p $DESTDIR
   ek=$?
   if [ $ek -ne 0 ]
   then
      echo "error exit $ek on ${host}: cannot create $DESTDIR" 1>&2
      exit 1
   fi
fi

#  Get rid of the options after parsing
shift $(expr $OPTIND - 1)

errcode=0
if [ $host != $DESTNODE ]
then
   copy_to_node $*
   ek=$?
   if [ $ek -ne 0 ]
   then
      exit $ek
   fi
#
#  There's no easy check if $* contains a mix of files with absolute
#  and relative pathnames, some of which might coincide with files of
#  the sam ename in $DESTDIR.  So that's the risk we run: if a source
#  file coincides with the destination, then cp exits with a nonzero
#  return code and this script exits.
#
elif [ $(pwd) != $DESTDIR ]
then
   if ! cp $* $DESTDIR
   then
      exit 1
   fi
   if [ $remove -ne 0 ]
   then
      rm -f $*
   fi
fi

exit $errcode
