#!/bin/sh
#
# @(#)ssync.sh,v 1.11 2011/09/02 14:45:14 kim Exp
#
# Kimmo Suominen 1998-01-14, 1999-08-30, 2009-11-10
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. The name of the author may not be used to endorse or promote
#    products derived from this software without specific prior
#    written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

PATH=/usr/local/bin:/bin:/usr/bin:/usr/sbin:/usr/etc:/usr/ucb
PATH=${PATH}:/usr/pkg/bin:/usr/pkg/sbin
export PATH

noarch=false
norel=false
world=false

allmasters=
servers=
destdir=

delete=

PAWD=pwd
RSH=rsh
RSYNC=rsync
SRSH=/usr/pkg/bin/srsh

# ropts and rargs are given to the local rsync
ropts=
rargs=

# sopts and sargs get passed along to ssync via RSH in an 'ssync -A'
sopts=
sargs=

# Override from configuration file if there.
if [ -f /etc/ssync.conf ]
then
	. /etc/ssync.conf
fi

myname=$(netname)
domain=$(netname -d)
cwd=$(${PAWD})

while getopts AD:RScf:gh:rsvyz opt
do
	case "${opt}" in
	A)	# Don't propagate -A
		world=true
		;;
	f) 	# No need to remember this -- incompatible with -A
		if [ ! -s "${OPTARG}" ]
		then
			echo "${0}: No file ${OPTARG}" 1>&2
			exit 1
		fi
		for i in $(cat "${OPTARG}")
		do
			x=$(netgroup "${i}")
			case "${x}" in
			'')	# Must be a hostname
				x="${i}"
				;;
			*)	# Aha, was a netgroup after all
				;;
			esac
			servers="${servers} ${x}"
		done
		;;
	h) 	# No need to remember this -- incompatible with -A
		x=$(netgroup "${OPTARG}")
		case "${x}" in
		'')	# Must be a hostname
			x="${OPTARG}"
			;;
		*)	# Aha, was a netgroup after all
			;;
		esac
		servers="${servers} ${x}"
		;;
	D)
		sargs="${sargs} -${opt} ${OPTARG}"
		case "${opt}" in
		D)	destdir="${OPTARG}";;
		*)	rargs="${rargs} -${opt} ${OPTARG}";;
		esac
		;;
	*)
		sopts="${sopts}${opt}"
		case "${opt}" in
		c)	norel=true;;
		g)	noarch=true;;
		[rR])	delete="--delete";;
		[sS])	export RSYNC_RSH
			RSYNC_RSH="${SRSH}"
			RSH=ssh
			;;
		v)	rargs="${rargs} --dry-run";;
		y)	rargs="${rargs} --update";;
		z)	rargs="${rargs} --compress";;
		*)	ropts="${ropts}${opt}";;
		esac
		;;
	esac
done
shift $(expr ${OPTIND} - 1)

if [ -z "${servers}" ]
then
	case ${noarch} in
	true)	case ${norel} in
		true)	netgroup=dist-$(osname) ;;
		*)	netgroup=dist-$(osname -release);;
		esac
		;;
	*)	case ${norel} in
		true)	netgroup=dist-$(osname -group);;
		*)	netgroup=dist-$(osname -relgroup);;
		esac
		;;
	esac

	# Always dist to local domain.
	servers=$(netgroup "${netgroup}")
	if [ -z "${servers}" ]
	then
		echo "${0}: No netgroup ${netgroup}" 1>&2
		exit 1
	fi

	case ${world} in
	true)	remotes=$(netgroup "${netgroup}-masters")
		if [ -z "${remotes}" ]
		then
			echo "${0}: No netgroup ${netgroup}-masters" 1>&2
			exit 1
		fi

		# Add the masters to the first pass of rdist. Doing the
		# local servers and remotes in the first pass optimises
		# distribution time as remotes are often behind a slow
		# link. Now we get the local domain updated faster than
		# if we waited for the second round of rdist processes
		# run on each master.
		servers="${servers} ${remotes}"

		# Pull current domain out of list of domains-to-push-to
		# since they should be in the (non-master) netgroup
		# already.
		allmasters=
		for i in ${remotes}
		do
			if [ $(netname -d "${i}") != "${domain}" ]
			then
				allmasters="${allmasters} ${i}"
			fi
		done
		;;
	esac
fi

x=
for i in $servers
do
	case $i in
	$myname)
		;;
	*)
		x="$x $i"
		;;
	esac
done
servers="$x"
if [ -z "$servers" ]
then
	echo "$0: No hosts to update (apparently just myself)" 1>&2
	exit 1
fi

case $# in
0)	set -- ${cwd};;
esac

for directory
do
	case "${destdir}" in
	'')	case "${directory}" in
		/*)	;;
		*)	directory="${cwd}/${directory}";;
		esac
		;;
	*)	;;
	esac
	dirs="${dirs} ${directory}"
done

if [ -n "${ropts}" ]
then
	ropts="-${ropts}"
fi

if [ -n "${sopts}" ]
then
	sopts="-${sopts}"
fi

# Construct the rsync command resembling rdist behaviour.
for i in ${servers}
do
	echo "Updating ${i}"
	for j in ${dirs}
	do
		echo "+ ${j}"
		if [ -d ${j} ]
		then
			k="${delete} ${j}/"
		else
			k="${j}"
		fi
		${RSYNC} -aH ${ropts}${rargs} ${k} ${i}:${destdir:-${j}}
	done
done

if [ -n "${allmasters}" ]
then
	for i in ${allmasters}
	do
		echo "Initiatiating remote updates to ${i}"
		${RSH} -n ${i} "ssync ${sopts}${sargs} ${dirs}" || exit $?
	done
	wait
fi

exit 0
