#!/bin/bash
#
# License: Copyright 2007 SpinetiX S.A. This file is licensed
#          under the terms of the GNU General Public License version 2.
#          This program is licensed "as is" without any warranty of any
#          kind, whether express or implied.
#
# Copyright 1999-2003 MontaVista Software, Inc.
# Copyright 2002, 2003, 2004 Sony Corporation
# Copyright 2002, 2003, 2004 Matsushita Electric Industrial Co., Ltd.
#
### BEGIN INIT INFO
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 5
# Default-Stop:
# Short-Description: Sets up updater service
# Description: Sets up updater service
### END INIT INFO
# NOTE: this should be started shortly after syslog and stopped before the
# watchdog.
# chkconfig: 235 15 02

# Init script information
INIT_NAME=updater
DESC="system updater setup"

# The base name of the updater executable
DAEMON="updater"

# The cache dir
CACHEDIR=/var/cache/updater

# The alternate cache dir (for transition)
ALTCACHEDIR=/srv/updater-tmp-cache

# The RPM DB dir (where locks are held)
RPMDBDIR=/var/lib/rpm

# The status file
STATUS_FILE=/var/lib/updater/status

# The file used to prevent updater from running on shutdown
NORUN_FILE=/var/run/updater.norun

# The maximum wait for a running updater to exit (in seconds)
# Note that we do not want a running update to be interrupted
# in the middle, so we set a relatively long timeout here (while
# checking the updater process will exit rapidly, only when
# installing updates through rpm will it take time to exit).
MAX_WAIT=3600

# The init script for splash screens
SPLASH=/etc/init.d/splash

# Load init script configuration
[ -f /etc/default/$INIT_NAME ] && . /etc/default/$INIT_NAME

# Source the init script functions
. /etc/init.d/init-functions

# Ignore SIGHUP, as we may receive it as a side effect of
# running this script (should not but better be safe)
trap '' SIGHUP

# Each init script action is defined below...

clean_packages() {
    find "$CACHEDIR" -mindepth 2 -maxdepth 2 -type d -name packages -print0 | \
	xargs -0r -i find '{}' -type f -print0 | \
	xargs -0r rm -f --
}

# this should not be called on shutdown, only on boot
rm_alt_cache() {
    if [ -e "$ALTCACHEDIR" ]; then
	rm -rf "$ALTCACHEDIR"
    else
	return 0
    fi
}

# returns 0 if the deamon is running, non-zero otherwise
is_daemon_running() {
    # NOTE: pidof does not return running scripts named "$DAEMON" (which
    # could be us) and returns zero if processes found, non-zero otherwise
    pidof "$DAEMON" > /dev/null
    return
}

# signals $DAEMON to stop and returns 0 if any processes found to signal
# non-zero otherwise
signal_daemon_stop() {
    # NOTE: pidof does not return running scripts named "$DAEMON" (which
    # could be us) and returns zero if processes found, non-zero otherwise
    pids="$(pidof "$DAEMON")" || return 1
    # we do not care if a process returned by pidof has just gone
    # so we ignore the return status of kill
    kill -s SIGHUP -- $pids > /dev/null 2>&1
    return 0
}

# returns zero if signal_daemon_stop returns zero or if the status
# file indicates that we are rebooting
rebooting_or_signal_daemon_stop() {
    # Must signal first and check after to avoid race conditions
    signal_daemon_stop && return 0
    if [ -f "$STATUS_FILE" ]; then
	STATUS="$(< "$STATUS_FILE")"
	case "$STATUS" in
	    REBOOTING*)
		return 0
		;;
	esac
    fi
    return 1
}

start() {
	local RET ERROR=

	log_status_msg "Starting $DESC: " -n

	if [ -f "$STATUS_FILE" ]; then
	    STATUS="$(< "$STATUS_FILE")"
	    case "$STATUS" in
		UPDATING*|CORRUPTED*)
		    log_status_msg \
			"previous update interrupted - SYSTEM CORRUPTED, " -n
		    echo CORRUPTED > "$STATUS_FILE"
		    ;;
		READY*)
		    ;;
		REBOOTING*)
		    echo READY > "$STATUS_FILE"
		    ;;
		*)
		    log_status_msg \
			"previous run interrupted in safe place, " -n
		    echo READY > "$STATUS_FILE"
		;;
	    esac
	fi

	log_status_msg "cleaning cached packages" -n
	clean_packages && rm_alt_cache
	RET=$?
	if [ $RET -eq 0 ]; then
		log_success_msg ", " -n
	else
		log_failure_msg " failed ($RET: $ERROR), " -n
		return 1
	fi

	log_success_msg "rm rpm lock, " -n
	# This is only safe at early boot time !!!
	rm -f "$RPMDBDIR"/__db*
	
	log_status_msg 'removing "no run" file' -n
	rm -f "$NORUN_FILE"
	RET=$?
	if [ $RET -eq 0 ]; then
		log_success_msg "."
	else
		log_failure_msg " failed ($RET: $ERROR)."
		return 1
	fi
	
	log_status_msg ""
	return 0
}

# Signals any running updater to stop but does not wait for it to stop
# Returns 0 if no updater running, 2 if one still running but the MAX_WAIT
# time has not yet elapsed since originally signalling, and 1 if one still
# running but MAX_WAIT has expired
stop_nowait() {
	local timediff timenow timefile

        # Make sure updater cannot start again
        if [ ! -f "$NORUN_FILE" ]; then
	    touch "$NORUN_FILE" || return
	    timediff=0
	fi

	rebooting_or_signal_daemon_stop || return 0

	# If this is the first time we signal it see if it exited quickly
	if [ -n "$timediff" ]; then
	    sleep 1
	    rebooting_or_signal_daemon_stop || return 0
	fi

	# An updater is still running, check for MAX_WAIT
	if [ -z "$timediff" ]; then
	    timenow="$(date +%s)"
	    timefile="$(stat -c %Y "$NORUN_FILE")"
	    timediff=$(( timenow - timefile ))
	else
	    [ -x "$SPLASH" ] && "$SPLASH" updating > /dev/null 2>&1
	fi
	if [ "$timediff" -le "$MAX_WAIT" ]; then
	    return 2
	else
	    return 1
	fi
}

stop () {
	local RET ERROR=

	log_status_msg "Stopping $DESC: " -n

	log_status_msg "preventing updater from starting" -n
        if [ ! -f "$NORUN_FILE" ]; then
	    touch "$NORUN_FILE"
	    RET=$?
	else
	    RET=0
	fi
	if [ $RET -eq 0 ]; then
		log_success_msg ", " -n
	else
		log_failure_msg " failed ($RET: $ERROR), " -n
	fi

	log_status_msg "terminating current updaters" -n
	signal_daemon_stop
	if [ $? -eq 0 ]; then # an updater is running
	    usleep 250000
	    RET=1
	    ERROR="timed out waiting for updater to exit"
	    for (( i=0; i< "$MAX_WAIT"; i++ )); do
		if ! is_daemon_running; then
		    if [ $i -ne 0 ]; then
			[ -x "$SPLASH" ] && "$SPLASH" stop > /dev/null 2>&1
		    fi
		    RET=0
		    ERROR=
		    break
		fi
		if [ $i -eq 0 ]; then
		    [ -x "$SPLASH" ] && "$SPLASH" updating > /dev/null 2>&1
		fi
		log_status_msg "." -n
		sleep 1
	    done
	else
	    RET=0 # no updater running
	fi
	if [ $RET -eq 0 ]; then
		log_success_msg ", " -n
	else
		log_failure_msg " failed ($RET: $ERROR), " -n
	fi
	RETF=$RET

	log_status_msg "cleaning cached packages" -n
	clean_packages
	RET=$?
	if [ $RET -eq 0 ]; then
		log_success_msg "."
	else
		log_failure_msg " failed ($RET: $ERROR)."
	fi

	log_status_msg ""
	return $RETF
}

parse() {
	case "$1" in
  start)
			start
			return $?
	;;
  stop)
			stop
			return $?
	;;
  stop-nowait)
			stop_nowait
			return $?
	;;
  *)
			echo "Usage: $INIT_NAME " \
			"{start|stop|stop-nowait}" >&2
	;;
	esac
	
	return 1
}

parse $@



