-#!/bin/bash
-
-# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
-# based on vserver-copy by Mark Lawrence <nomad@null.net>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-# Copy/Sync a virtual host from one machine to another
-#
-# History:
-#
-# 2003-04-04: Version 0.4 - Mark lawrence
-# - Set "ONBOOT=no" in the destination .conf file when --startstop
-# is not used, in case the destination roothost reboots. We don't
-# want two copies of a vserver running at the same time.
-#
-# 2003-03-04: Version 0.3 - Mark lawrence
-# - Changed all checks for [ "" != "$var" ] into [ -n|-z "$var" ]. "" doesn't
-# seem to work for bash on the Sparc architecture.
-# - Changed $ssh variable into $shcmd.
-#
-# 2003-02-23: Version 0.2 - Mark Lawrence
-# - Set ONBOOT to "no" in the original .conf file when the "-s" flag is
-# used so that if/when you reboot the source roothost you don't have the
-# same vserver and IP address running on two machines.
-
-: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
-test -e "$UTIL_VSERVER_VARS" || {
- echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
- exit 1
-}
-. "$UTIL_VSERVER_VARS"
-
-VERSION="0.4"
-umask 022
-me=${0##*/}
-
-
-### Helper functions ###
-
-# Save stdin and stdout for later use
-exec 3>&1
-exec 4>&2
-
-noninteractive () {
- exec &> /dev/null
-}
-
-interactive () {
- exec 1>&3
- exec 2>&4
-}
-
-info () {
- ! $quiet && echo "I: $me: $1" >&3
-}
-
-warn () {
- ! $quiet && echo "W: $me: $1" >&4
-}
-
-error () {
- ! $quiet && echo "E: $me: $2" >&4
- exit $1
-}
-
-
-### Usage/Info functions ###
-
-usage () {
- cat <<EOF 1>&2
-Usage: $me [-hVvqidrRs] vserver newname
- $me [-hVvqidrRs] vserver host:[newname]
-EOF
-}
-
-full_usage () {
- usage
- cat <<EOF
-
-$me uses rsync to make a copy of a vserver. If the destination
-name contains a host specification the vserver will be synchronised to
-the remote destination over ssh/rsh.
-
-This can be used on a running vserver to make a warm backup. With the -s
-flag a vserver can even be operationally moved to different hardware within
-seconds.
-
-The -i and -d flags can be used to minimally reconfigure the destination
-vserver (rewrites /etc/vservers/newname.conf and $__DEFAULT_VSERVERDIR/newname/etc/hosts)
-
-Options:
- -h, --help this help
- -V, --version copyright and version information
- -v, --verbose show all output
- -q, --quiet direct all output to /dev/null (no password
- prompt for logins on remote hosts!)
- -d, --domain [string] new dns domain (must be used with -i)
- -i, --ip [addr] new IP address (must be used with -d)
- -r, --vsroot location of "/vserver/" directory
- -R, --rsh use rsh (instead of default ssh) for
- network transport
- -s, --stopstart stop the local vserver before copying and start
- it on the destination host afterwards
-
-EOF
-}
-
-full_version () {
- cat <<EOF
-$me version $VERSION
-Copyright (c) 2002 Mark Lawrence <nomad@null.net>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-EOF
-}
-
-
-### Default values and Command line options ###
-
-stopstart=(false)
-verbose=(false)
-quiet=(false)
-shcmd="ssh"
-rsflag="-e"
-rsh=(false)
-colon=":"
-domain=""
-ip=""
-vsroot=$__DEFAULT_VSERVERDIR
-
-if [ $# -eq 0 ]; then # Script invoked with no command-line args?
- usage
- exit 1
-fi
-
-temp=$(getopt -o hVvqd:i:rRs --long help,version,verbose,quiet,domain:,ip:,vsroot,rsh,stopstart, -n $me -- "$@")
-
-if [ $? -ne 0 ]; then
- echo " (See -h for help)"
- exit 1
-fi
-
-# Note the quotes around `$temp': they are essential!
-eval set -- "$temp"
-
-while true; do
- case "$1" in
- -h|--help) full_usage
- exit 1
- ;;
- -V|--version) full_version
- exit 1
- ;;
- -v|--verbose) verbose=(true)
- shift
- ;;
- -q|--quiet) quiet=(true)
- shift
- ;;
- -d|--domain) domain="$2"
- shift 2
- ;;
- -i|--ip) ip="$2"
- shift 2
- ;;
- -r|--vsroot) vsroot="$2"
- shift 2
- ;;
- -R|--rsh) rsh=(true)
- shift
- ;;
- -s|--stopstart) stopstart=(true)
- shift
- ;;
- --) shift
- break
- ;;
- *) echo "Internal error!"
- exit 1
- ;;
- esac
-done
-
-if [ $# -ne 2 ]; then
- usage
- exit 1
-fi
-
-
-### ###
-
-# By default we are reasonably quiet (ouput only via info, warn & error)
-if $verbose; then
- interactive
-else
- noninteractive
-fi
-
-now=$(date)
-info "called on $(hostname) at $now"
-
-
-vserver=$1
-vconf=/etc/vservers/$vserver.conf
-vroot=$vsroot/$vserver
-
-if $rsh; then
- shcmd="rsh"
-fi
-
-if (echo $2 | grep '^[a-z][a-z0-9]\+$'); then
- dhost=""
- newname=$2
- shcmd=""
- rsflag=""
- colon=""
- if $rsh; then
- warn "rsh is set but not used for a local copy"
- fi
-elif (echo $2 | grep '^[a-z].*[a-z0-9]:$'); then
- dhost=${2/:/}
- newname=$vserver
-elif (echo $2 | grep '^[a-z].*[a-z0-9]:[a-z].*[a-z0-9]$'); then
- dhost=${2/:*/}
- newname=${2/*:/}
-else
- error 1 "Second argument must be of the form \"[host:]name\" or \"host:\""
-fi
-
-target=$vsroot/$newname
-targetconf=/etc/vservers/$newname.conf
-
-
-### Perform some sanity checks ###
-
-if [ ! -d $vroot ]; then
- error 1 "Directory \"$vroot\" does not exist"
-fi
-
-if [ ! -e $vconf ]; then
- error 1 "Vserver file \"$vconf\" does not exist"
-fi
-
-if [ -z "$dhost" ] && [ "$vserver" == "$newname" ]; then
- error 1 "Source and destination names cannot be the same on the localhost"
-fi
-
-if [ -n "$dhost" ] && ! (host $dhost | grep 'has address'); then
- warn "$dhost does not resolve into an IP address"
-fi
-
-if [ \( -n "$ip" -a -z "$domain" \) -o \
- \( -z "$ip" -a -n "$domain" \) ]
-then
- error 1 "Both IP address and domain must be specified together"
-fi
-
-if [ -n "$ip" ] && \
-! (echo $ip | grep '^[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}$' ); then
- error 1 "\"$ip\" is not a valid IP address"
-fi
-
-# This works both locally and remote
-if ($shcmd $dhost $__SBINDIR/vserver $newname running | grep 'is running'); then
- warn "destination vserver \"$newname\" is running"
- error 1 "Cannot copy over a running vserver"
-fi
-
-
-### Do the copy ###
-
-info "Attempting to copy $vserver to $dhost$colon$newname"
-
-if $stopstart; then
- info "Stopping virtual server \"$vserver\" on localhost"
- $__SBINDIR/vserver $vserver stop
-fi
-
-info "Syncing directories"
-# trailing slashes very important in the rsync!
-if ! rsync -Havxz --numeric-ids $rsflag $shcmd $vroot/ $dhost$colon$target/; then
- error 1 "rsync failed"
-fi
-
-if [ -n "$ip" -a -n "$domain" ]; then
- # Insert the new IPROOT/S_HOSTNAME values into the config file
- info "Modifying $targetconf"
- tmpf=$(tempfile)
- if (sed -e "s/^S_HOSTNAME=.*/S_HOSTNAME=\"$newname\"/" \
- -e "s/^IPROOT=.*/IPROOT=\"$ip\"/" $vconf > $tmpf)
- then
- if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$targetconf; then
- error $? "vserver config file copy/change failed"
- fi
-
- else
- warn "Unable to reconfigure virtual server config file"
- fi
-
- # create a new /etc/hostname
- info "Creating hostname file"
- echo $newname > $tmpf
- if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hostname; then
- error 1 "vserver /etc/hostname copy failed"
- fi
-
- info "Creating /etc/hosts"
- cat << EOF > $tmpf
-# /etc/hosts (automatically generated by $me)
-
-127.0.0.1 localhost
-$ip $newname.$domain $newname
-
-# The following lines are desirable for IPv6 capable hosts
-
-::1 ip6-localhost ip6-loopback
-fe00::0 ip6-localnet
-ff00::0 ip6-mcastprefix
-ff02::1 ip6-allnodes
-ff02::2 ip6-allrouters
-ff02::3 ip6-allhosts
-EOF
-
- # copy /etc/hosts
- if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hosts; then
- error 1 "vserver /etc/hosts copy failed"
- fi
- rm -f $tmpf
-
-else
- if ! $stopstart; then
- # Make sure that this vserver doesn't start on the
- # destination host if it reboots
- tmpf=$(tempfile)
- sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf
- vconf=$tmpf
- fi
-
- # copy newname.conf unchanged
- info "Copying $targetconf"
- if ! rsync -v $rsflag $shcmd $vconf $dhost$colon$targetconf; then
- error 1 "vserver config file copy/change failed"
- fi
-
- rm -f $tmpf
-fi
-
-
-if $stopstart; then
- info "Starting virtual server \"$vserver\" on $dhost"
- $shcmd $dhost $__SBINDIR/vserver $vserver start
- if ($shcmd $dhost $__SBINDIR/vserver $vserver running | \
- grep 'not running'); then
- error 1 "Virtual server \"$vserver\" failed to start on $dhost"
- fi
-
- # Make sure that we don't start the original on next boot
- tmpf=$(tempfile)
- sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf
- mv $tmpf $vconf
-fi
-
-exit 0