#! /bin/bash

set -e
set -u

# runmirrors script for Debian
# Based losely on existing scripts, written by an unknown number of
# different people over the years.
#
# Copyright (C) 2008 Joerg Jaspert <joerg@debian.org>
#
# 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; version 2.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.

# In case the admin somehow wants to have this script located someplace else,
# he can set BASEDIR, and we will take that. If it is unset we take ${HOME}
BASEDIR=${BASEDIR:-"${HOME}"}

NAME="`basename $0`"

# In case we are called with an argument we look for a different configuration.
CONF=${1:-""}
if [ -n "${CONF}" ]; then
	NAME="${NAME}-${CONF}"
fi

# Read our config file
. "${BASEDIR}/etc/${NAME}.conf"

# Source our common functions
. "${BASEDIR}/etc/common"

# Set sane defaults if the configfile didn't do that for us.
# The directory for our logfiles
LOGDIR=${LOGDIR:-"${BASEDIR}/log"}
# Our own logfile
LOG=${LOG:-"${LOGDIR}/${NAME}.log"}
# Our lockfile directory
LOCKDIR=${LOCKDIR:-"${BASEDIR}/locks"}
# How many logfiles to keep
LOGROTATE=${LOGROTATE:-14}
# Our mirrorfile
MIRRORS=${MIRRORS:-"${BASEDIR}/etc/${NAME}.mirror"}
# used by log()
PROGRAM=${PROGRAM:-"${NAME}-$(hostname -s)"}
# extra ssh options we might want hostwide
SSH_OPTS=${SSH_OPTS:-""}
# Whats our archive name? We will also tell our leafs about it
PUSHARCHIVE=${PUSHARCHIVE:-"${CONF}"}
# How long to wait for mirrors to do stage1 if we have multi-stage syncing
PUSHDELAY=${PUSHDELAY:-600}
# Which ssh key to use?
KEYFILE=${KEYFILE:-".ssh/pushmirror"}
# where to send mails to
if [ "x$(hostname -s)x" != "x${MIRRORNAME%%.debian.org}x" ]; then
	# We are not on a debian.org host
	MAILTO=${MAILTO:-"root"}
else
	# Yay, on a .debian.org host
	MAILTO=${MAILTO:-"mirrorlogs@debian.org"}
fi

if ! [ -f "${BASEDIR}/${KEYFILE}" ]; then
	error "SSH Key ${BASEDIR}/${KEYFILE} does not exist" >> ${LOG}
	exit 5
fi

# Hooks
HOOK1=${HOOK1:-""}
HOOK2=${HOOK2:-""}
HOOK3=${HOOK3:-""}

# Some sane defaults
cd ${BASEDIR}
umask 022

# Make sure we have our log and lock directories
mkdir -p "${LOGDIR}"
mkdir -p "${LOCKDIR}"

trap 'log "Mirrorpush done" >> ${LOG}; savelog "${LOG}" > /dev/null' EXIT

log "Pushing leaf mirrors" >> ${LOG}

HOOK=(
	HOOKNR=1
	HOOKSCR=${HOOK1}
)
hook $HOOK

# From here on we do *NOT* want to exit on errors. We don't want to
# stop pushing mirrors just because we can't reach one of them.
set +e

# Built up our list of 2-stage mirrors.
PUSHLOCKS=""
PUSHLOCKS=$(get2stage)

# In case we have it - remove. It is used to synchronize multi-stage mirroring
rm -f "${LOCKDIR}/all_stage1"

# Now read our mirrorfile and push the mirrors defined in there.
# We use grep to easily sort out all lines having a # in front of them or are empty.
egrep -v '^[[:space:]]*(#|$)' "${MIRRORS}" |
while read MTYPE MLNAME MHOSTNAME MUSER MPROTO MKEYFILE; do
	if [ "x${MTYPE}x" = "xDELAYx" ]; then
		# We should wait a bit.
		if [ -z ${MLNAME} ]; then
			MLNAME=60
		fi
		log "Delay of ${MLNAME} requested, sleeping" >> "${LOG}"
		sleep ${MLNAME}
		continue
	fi

	# Process the two options that can be left blank in the config
	if [ -z ${MPROTO} ]; then
		MPROTO=2
	fi
	if [ -z ${MKEYFILE} ]; then
		MKEYFILE="${BASEDIR}/${KEYFILE}"
	fi
	# Now, people can do stupid things and leave out the protocol, but
	# define a keyfile...
	if [ ${MPROTO} -ne 1 ] && [ ${MPROTO} -ne 2 ]; then
		error "Need a correct ssh protocol version for ${MLNAME}, skipping" >> ${LOG}
		continue
	fi

	# Built our array
	SIGNAL_OPTS=(
		MIRROR="${MLNAME}"
		HOSTNAME="${MHOSTNAME}"
		USERNAME="${MUSER}"
		SSHPROTO="${MPROTO}"
		SSHKEY="${MKEYFILE}"
		PUSHLOCKOWN="${LOCKDIR}/${MLNAME}.stage1"
		PUSHTYPE="${MTYPE}"
		PUSHARCHIVE=${PUSHARCHIVE}
	)

	# And finally, push the mirror
	log "Trigger ${MLNAME}" >> ${LOG}
	signal "${SIGNAL_OPTS}" &
	log "Trigger for ${MLNAME} done" >> ${LOG}

	HOOK=(
		HOOKNR=2
		HOOKSCR=${HOOK2}
	)
	hook $HOOK
	set +e
done

HOOK=(
	HOOKNR=3
	HOOKSCR=${HOOK3}
)
hook $HOOK

exit 0
