#!/bin/sh
#
# This is a script to clone the local machine's hard drive from another
# machine.  The other machine's name/IP is the only parameter and is required.

# file that must exist for clones to work
CLONE_OK_FILE=/etc/cloneok
ERROR_LOG=/tmp/error.log

# displays help
usage()
{
   echo "Usage: remote-clone [first|second|boot] machine"
   echo "       remote-clone enable [machine [machine ...]]"
   echo "       remote-clone disable"
   echo "       remote-clone status"
   echo
   echo "The first form uses machine as the name of a clone server that the local client"
   echo "is going to clone from.  The optional first parameter may be specified to"
   echo "restrict cloning to either just NT or just BSD."
   echo
   echo "The second form is used to enable a clone server.  Any machine names specified"
   echo "on the command line are enabled as clients that can be cloned off of this"
   echo "server."
   echo
   echo "The third form is used to completely disable a clone server."
   echo
   echo "The fourth form reports whether a clone server is enabled or disabled."
   exit 1
}

# enable a clone server and possible clients
enable()
{
   echo "Cloning enabled on $localhost."
   touch $CLONE_OK_FILE >/dev/null 2>&1
   shift
   for client
   do
      echo "Enabling $client as a client."
      echo "$client" >> /root/.rhosts
   done
}

# disable a clone server
disable()
{
   # first make sure they got the command line right
   if [ $# -gt 1 ]; then
      usage
   fi

   echo "Cloning disabled on $localhost."
   rm -f $CLONE_OK_FILE >/dev/null 2>&1
}

# report the status of a clone server
status()
{
   # first make sure they got the command line right
   if [ $# -gt 1 ]; then
      usage
   fi

   if [ -f $CLONE_OK_FILE ]; then
      echo "Cloning is enabled on $localhost."
   else
      echo "Cloning is disabled on $localhost."
   fi
}

# perform all the pre-clone checks on a client before starting the actual
# cloning process
check_server()
{
   # see if we can ping the remote host
   # disable cloning so that nobody clones from us unless we get a good clone
   # ourselves
   disable

   echo "remote-clone running on $localhost"
   echo -n "checking to see if I can ping $machine... "
   if ! ping -c 1 $machine >/dev/null 2>&1 ; then
      echo "no"
      echo "$machine did not respond to ping.  Aborting."
      exit 2
   fi
   echo "yes"

   # see if we can execute commands remotely from that machine
   echo -n "checking to see if I can run remote commands on $machine... "
   if ! rsh $machine echo hello >/dev/null 2>&1 ; then
      echo "no"
      echo "$machine won't let me run remote commands.  Aborting."
      exit 3
   fi
   echo "yes"

   # see if we shouldn't clone, just checks for $CLONE_OK_FILE on remote machine
   echo -n "checking to see if the remote clone is good... "
   if ! rcp root@$machine:$CLONE_OK_FILE /dev/null >/dev/null 2>&1 ; then
      echo "no"
      echo "$machine doesn't want to be cloned.  Aborting."
      exit 4
   fi
   echo "yes"

   # do actual clone
   echo "starting remote clone from $machine to $localhost..."
}

# clone MBR and any boot manager -assume it is no more than 64k
clone_boot()
{
   echo -n "Cloning MBR and Boot Manager... "
   if (rsh $machine "dd bs=64k if=/dev/wd0 count=1 | gzip -9" | gunzip -9 | dd bs=64k of=/dev/wd0) 2>> $ERROR_LOG ; then
      echo "done."
   else
      echo "failed!"
      cat $ERROR_LOG
      exit 5
   fi
}

# clone slice
# usage: clone_slice slice_num
clone_slice()
{
   echo -n "Cloning Partition $1... "
   if (rsh $machine "dd bs=64k if=/dev/wd0s$1 | gzip -9" | gunzip -9 | dd bs=64k of=/dev/wd0s$1) 2>> $ERROR_LOG ; then
      echo "done."
   else
      echo "failed!"
      cat $ERROR_LOG
      exit 5
   fi
}

# clones an entire disk (old-fashioned cloning)
clone_all()
{
   echo -n "Cloning entire disk... "
   if (rsh $machine "dd bs=64k if=/dev/wd0 | gzip -9" | gunzip -9 | dd bs=64k of=/dev/wd0) 2>> $ERROR_LOG ; then
      echo "done."
   else
      echo "failed!"
      cat $ERROR_LOG
      exit 5
   fi
}

# actual code starts here -----------------------------------------------------

# check for at least some command-line arguments
if [ $# -eq 0 ]; then
   usage
fi

# read the first parameter and get the local host name
command=$1
localhost=`hostname -s`

# branch for each command possiblity
if [ $command = status ]; then
   status $*
   exit 0
elif [ $command = enable ]; then
   enable $*
   exit 0
elif [ $command = disable ]; then
   disable $*
   exit 0
fi

# at this point assume we are at the first form ---------

# can only have 1 or 2 args
if [ $# -gt 2 ]; then
   usage
fi

# if only one arg, then we are doing a full clone to a machine
if [ $# -eq 1 ]; then
   machine=$command
   command=foo
else
   machine=$2
fi

# now start up the actual clone process
check_server
if [ $command = first ]; then
   clone_slice 1
elif [ $command = second ]; then
   clone_slice 2
elif [ $command = boot ]; then
   clone_boot
else
   clone_all
fi

echo "Finished succesfully."
