#!/bin/sh
#
# monotone:   This script starts and stops the monotone server
#
# chkconfig: - 90 10
# description: Monotone netsync protocol server
# processname: monotone-server
# pidfile: /var/run/monotone/monotone-server.pid
# config: /etc/sysconfig/monotone
# config: /etc/monotone/monotonerc

# Do not load RH compatibility interface.
WITHOUT_RC_COMPAT=1

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

# Get configuration settings.
[ -f /etc/sysconfig/monotone ] && . /etc/sysconfig/monotone

# By default it's all good
RETVAL=0
STARTED=1

MT=/usr/bin/mtn
MTSERVER=/usr/sbin/monotone-server
PIDFILE=/var/run/monotone/monotone-server.pid
LOGFILE=${MONOTONE_LOGFILE:-/var/log/monotone.log}
MONOTONE_DBDIR=`dirname $MONOTONE_DBFILE`
MONOTONE_OLDDB=$MONOTONE_DBDIR/server.db
LOCKFILE=/var/lock/subsys/monotone
USER=${MONOTONE_USER:-monotone}
GROUP=${MONOTONE_GROUP:-monotone}

random_passphrase()
{
	# As of 0.22, 32 chars is the maximum pass phrase length.
	dd if=/dev/urandom bs=32 count=1 2> /dev/null | md5sum |
	{ read sum rest; echo $sum; }
}

umask 077

check_db_version()
{
	db_version=`su -s /bin/bash - $USER \
			    -c "LC_ALL=C \
	    			$MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS \
				    db version"` || exit 2
	set -- $db_version
	[ "$5" == "(usable)" ]
	return $?
}

start_monotone_daemon()
{
	local ANNOUNCE BASENAME CMDNAME DISPNAME EXPECT FLAGS LOCKFILE MAKE_PIDFILE NICE PIDFILE LOGFILE STATUS SU WHICH

# Process options.
	ANNOUNCE=1
	CMDNAME=
	DISPNAME=
	EXPECT=
	LOCKFILE=
	MAKE_BACKGROUND=
	NICE=0
	PIDFILE=
	LOGFILE=
	SU=
	while [ "$1" != "${1##-}" -o "$1" != "${1##+}" ]; do
		case "$1" in
		--)
			shift
			break
			;;
		--announce)
			shift
			ANNOUNCE=1
			;;
		--no-announce)
			shift
			ANNOUNCE=
			;;
		--displayname)
			shift
			DISPNAME="$1"
			shift
			;;
		--expect-user)
			shift
			EXPECT="$1"
			shift
			;;
		--lockfile)
			shift
			LOCKFILE="$1"
			shift
			;;
		--background)
			shift
			MAKE_BACKGROUND='--background'
			;;
		--name)
			shift
			CMDNAME="$1"
			shift
			;;
		--pidfile)
			shift
			PIDFILE="$1"
			shift
			;;
		--logfile)
			shift
			LOGFILE="$1"
			shift
			;;
		--user|--set-user)
			shift
			SU="$1"
			[ -n "$EXPECT" ] || EXPECT="$SU"
			shift
			;;
		[-+][0-9]*)
			NICE="$1"
			shift
			;;
		*)
			echo "start_daemon: unrecognized option: $1" >&2
			return 1
			;;
		esac
	done

# We need the absolute pathname.
	if [ -z "$1" ]; then
		msg_usage "start_daemon [options]... {program}..."
		return 1
	fi
	WHICH="$(absolute "$1")" || return 1
	[ -n "$CMDNAME" ] &&
		BASENAME="$(basename "$CMDNAME")" ||
		BASENAME="$(basename "$1")" || return 1
	shift

	if [ -n "$CMDNAME" -a -z "$PIDFILE" ]; then
		echo "start_daemon: --name is set but --pidfile is not set" >&2
		return 1
	fi

	[ -n "$DISPNAME" ] || DISPNAME="$BASENAME"

# Use a safe umask
	#umask 077

# Don't do coredumps.
	ulimit -Sc 0 >/dev/null 2>&1

# Don't export these because they may be invalid under another UID and the
# directories may be gone while the daemon is still running.
	export -n HOME TMP TMPDIR

	FLAGS="--start -N $NICE"
	[ -z "$CMDNAME" ] &&
		FLAGS="$FLAGS --exec $WHICH" ||
		FLAGS="$FLAGS --startas $WHICH --name $CMDNAME"
	[ -z "$PIDFILE" ] || FLAGS="$FLAGS --pidfile $PIDFILE"
	[ -z "$EXPECT" ] || FLAGS="$FLAGS --user $EXPECT"
	[ -z "$MAKE_BACKGROUND" ] || FLAGS="$FLAGS $MAKE_BACKGROUND"

# Is it running at all?
	if ! start-stop-daemon $FLAGS --test > /dev/null; then
		msg_already_running "$DISPNAME"
		passed "$BASENAME startup"
		STATUS=$?
		echo
		return $STATUS
	fi
	
	[ -e "$PIDFILE" ] && rm -f "$PIDFILE"

# Announce the action.
	[ -z "$ANNOUNCE" ] || msg_starting "$DISPNAME"

# Actually start the daemon.
	[ -z "$LOGFILE" ] || LOG_ADD=" >>$LOGFILE 2>&1"
	[ -z "$SU" ] ||
		START_CMD="start-stop-daemon $FLAGS -- \"$*$LOG_ADD\"" &&
		START_CMD="start-stop-daemon $FLAGS --startas /bin/su -- -s /bin/sh -l \"$SU\" -c \"$WHICH $*$LOG_ADD\""
	initlog $INITLOG_ARGS -n "$BASENAME" -c "$START_CMD"
	STATUS=$?

	if [ $STATUS = 0 ]; then
		[ -z "$LOCKFILE" ] || touch "$LOCKFILE"
		[ "$BOOTUP" != verbose ] || echo -n " $DISPNAME "
		success "$BASENAME startup"
	else
		failure "$BASENAME startup"
	fi
	echo

	return $STATUS
}

start() {
	if [ -e $MONOTONE_DBFILE ]; then
		check_db_version || $0 migrate
	elif [ -e $MONOTONE_OLDDB ]; then
		echo -n $"Pre-0.26 monotone database must be migrated by hand: "
		failure
		echo
		false
	else
		$0 init
	fi
	RETVAL=$?
	if [ $RETVAL = 0 ] && [ "x`ls $MONOTONE_KEYDIR`" = x ]; then
		$0 genkey
		RETVAL=$?
	fi
	if [ $RETVAL = 0 ]; then
		# Start daemon.
		msg_starting $"monotone server"
		{
		exec 3>> $LOGFILE &&
		chown :$GROUP $LOGFILE &&
		chmod g+w $LOGFILE &&
		echo >&3 "Server restart at `date`" &&
		start_monotone_daemon --no-announce --pidfile "$PIDFILE" --lockfile "$LOCKFILE" \
			--user $USER --logfile $LOGFILE --background -- $MTSERVER \
			       $MONOTONE_RCOPTS $MONOTONE_DBOPTS $MONOTONE_PPOPTS \
			       serve --pid-file=$PIDFILE
		}
		RETVAL=$?
	fi
        return $RETVAL
}

stop() {
        # Stop daemons.
        msg_stopping $"monotone server"
	stop_daemon --no-announce --pidfile "$PIDFILE" --lockfile "$LOCKFILE" \
		--expect-user $USER -HUP -- $MTSERVER
        RETVAL=$?
	[ $RETVAL = 0 ] && [ -e "$PIDFILE" ] && rm -f "$PIDFILE"
        return $RETVAL
}

init() {
        echo -n $"Initializing database" "${MONOTONE_DBFILE}: "
	{ [ -d "$MONOTONE_DBDIR" ] ||
 	  /usr/bin/install -o $USER -g $GROUP \
			   -m 0770 -d $MONOTONE_DBDIR; } &&
	su -s /bin/bash - $USER -c "umask 007; \
		$MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS db init" >>$LOGFILE 2>&1 &&
		success $"database initialization" ||
		failure $"database initialization"
	RETVAL=$?
	echo
        return $RETVAL
}

genkey() {
	MONOTONE_KEYID=${2:-${MONOTONE_KEYID:-`/bin/hostname -f`}}
	MONOTONE_PPFILE=${MONOTONE_PPFILE:-$MONOTONE_DBDIR/passphrase.lua}
        echo -n $"Generating RSA key for server $MONOTONE_KEYID"
	tmp=/tmp/mtserver$$
	if
		passphrase=`random_passphrase` &&
		{ echo $passphrase; echo $passphrase; } |
		(umask 027; $MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS \
				genkey $MONOTONE_KEYID >>$LOGFILE 2>&1) &&
		/bin/chgrp $GROUP \
			   "$MONOTONE_KEYDIR/$MONOTONE_KEYID" &&
		/bin/chmod 0640 "$MONOTONE_KEYDIR/$MONOTONE_KEYID" &&
		cat > $tmp <<EOF &&
function get_passphrase(keyid)
  return "$passphrase"
end
EOF
		/usr/bin/install -o root -g $GROUP \
				 -m 0440 $tmp ${MONOTONE_PPFILE}
	then
		success $"key generation"
	else
		failure $"key generation"
	fi
	RETVAL=$?
	rm -f $tmp
	echo
        return $RETVAL
}

migrate() {
  	oppfile=$MONOTONE_DBDIR/passphrase.lua
	RETVAL=0
	if [ ! -e $MONOTONE_PPFILE ] && [ -e $oppfile ]; then
		echo -n $"Moving old server passphrase file to new location: "
		/usr/bin/install -o root -g $GROUP \
				 -m 0440 $oppfile ${MONOTONE_PPFILE} &&
		success $"move passphrase file" ||
		failure $"move passphrase file"
		RETVAL=$?
		echo
	fi
	[ $RETVAL -eq 0 ] || exit $RETVAL
	# Note this must run as root in case migration is writing
	# into /etc/monotone/private-keys.
	(umask 027
	 $MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS $MONOTONE_PPOPTS db migrate >>$LOGFILE 2>&1 &&
	 $MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS $MONOTONE_PPOPTS db regenerate_caches >>$LOGFILE 2>&1 &&
	 /bin/chgrp -R $GROUP $MONOTONE_KEYDIR)
	RETVAL=$?
        echo -n $"Checking database format in" "${MONOTONE_DBFILE}: "
	[ $RETVAL = 0 ] &&
		success $"database check" ||	
		failure $"database check"
	echo
        return $RETVAL
}

import() {
	started && stop
	echo -n $"Importing packets to monotone database: "
	su -s /bin/bash - $USER -c "umask 007; \
		$MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS read" >>$LOGFILE 2>&1 &&
		success $"packet import" ||
		failure $"packet import"
	RETVAL=$?
	echo
	started && start
        return $RETVAL
}

checkstatus() {
	status --pidfile "$PIDFILE" --expect-user $USER $MTSERVER
	return $?
}

checkstarted() {
	checkstatus >/dev/null 2>&1
	STARTED=$?
}

started() {
	return $STARTED
}

list() {
	started && stop
	echo $"Printing monotone database list of imported keys:"
	su -s /bin/bash - $USER -c "umask 007; \
		$MT $MONOTONE_RCOPTS $MONOTONE_DBOPTS list $1"
	RETVAL=$?
	started && start
        return $RETVAL
}

# See how we were called.
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        checkstatus
	RETVAL=$?
        ;;
    restart)
        stop
        start
        ;;
    condstop)
        if [ -f "$LOCKFILE" ]; then
	    stop
	fi
	;;
    condrestart)
        if [ -f "$LOCKFILE" ]; then
            stop
            start
        fi
	;;
    init)
        init
	;;
    genkey)
        genkey
	;;
    migrate)
        migrate
	;;
    # Use "monotone pubkey me@my.com | service monotone import"
    # to import the first keys to enable in /etc/monotone/write-permission.
    # Thereafter, those with write permission can add other keys via
    # netsync with "monotone push --key-to-push=IDENT" and then IDENT
    # can be used in the read-permission and write-permission files.
    import)
        checkstarted
        import
	;;
    listkeys)
        checkstarted
        list keys
	;;
    listbranches)
        checkstarted
        list branches
	;;
    *)
	echo "\
Usage: $0 {start|stop|restart|status|condrestart|init|import|genkey [IDENT]}"
	RETVAL=1
	;;
esac
exit $RETVAL
