#!/bin/bash
#
# Copyright (c) 2001-2002 SuSE Linux AG, Nuernberg, Germany.
# Copyright (c) 2008-2011 SuSE LINUX Products GmbH, Nuernberg, Germany.
#
# /etc/init.d/boot.clock
#
### BEGIN INIT INFO
# Provides:          boot.clock
# Required-Start:    boot.rootfsck
# Required-Stop:     boot.rootfsck
# Should-Start:      $null
# Should-Stop:       apparmor
# X-Start-Before:    boot.localfs
# X-Stop-After:      $null
# Default-Start:     B S
# Default-Stop:
# X-Interactive:     true
# Description:       Read hardware clock and set system clock
# Short-Description: Read hardware clock and set system clock
### END INIT INFO

. /etc/rc.status
. /etc/sysconfig/clock

: ${HWCLOCK:=-u}
: ${SYSTOHC:=yes}

#
# Only compensate for clock drift if RTC is UTC
#
USE_ADJFILE=no
case "$HWCLOCK" in
*-u*) USE_ADJFILE=yes ;;
esac
test "$SYSTOHC" != yes && USE_ADJFILE=no

#
# Don't use hwclock if not valid
#
USE_HWCLOCK=yes
case "$(uname -i)" in
s390*) USE_HWCLOCK=no ;;
esac
if test -r /proc/xen/capabilities ; then
    read -t1 caps < /proc/xen/capabilities
    test "$caps" = "${caps%control_d*}" && USE_HWCLOCK=no
fi

#
# Get current status of kernel time variables, if kernel
# is within "11 minute mode" do not adjust HW clock nor
# write system time back to HW clock, bug bnc#492921.
#
ELEVENMIN_MODE=no
typeset -i STA_CLOCK=$(adjtimex --print | sed -rn '/^[[:blank:]]*status:/{ s/[^[:digit:]]*([[:digit:]]+)/\1/p; }')
test $((STA_CLOCK & 64)) -eq 0 && ELEVENMIN_MODE=yes

#
# Without having rtc_cmos module loaded hwclock will fail on at least x86
#
rtc_rule()
{
    local temprules=/dev/.udev/rules.d
    local uevseqnum=/sys/kernel/uevent_seqnum
    local rule=$temprules/95-rtc-cmos.rules
    local -i start=0 end=0

    if test -e /dev/rtc ; then
	${1+"$@"}
	return $?
    fi

    if test -z "$(/sbin/modprobe -l rtc_cmos)" ; then
	${1+"$@"}
	return $?
    fi

    /bin/mkdir -m 0755 -p $temprules
    echo ACTION==\"add\", KERNEL==\"rtc0\", RUN=\"${1+"$@"} --rtc=\$env{DEVNAME}\" > $rule

    test -e $uevseqnum && read -t 1 start < $uevseqnum

    if /sbin/modprobe -q rtc_cmos ; then
	test -e $uevseqnum && read -t 1 end < $uevseqnum
	if test $start -lt $end ; then
	    /sbin/udevadm settle --quiet --seq-start=$start --seq-end=$end
	else
	    /sbin/udevadm settle --quiet
	fi
    else
	rm -f $rule
	${1+"$@"}
    fi
}

adjfile_thirdline()
{
    case "$HWCLOCK" in
    *-u*) grep -q LOCAL /etc/adjtime && sed -ir 's/LOCAL/UTC/' /etc/adjtime ;;
    *-l*) grep -q UTC   /etc/adjtime && sed -ir 's/UTC/LOCAL/' /etc/adjtime ;;
    esac 2> /dev/null
}

rc_reset

case "$1" in
    start|restart|reload|force-reload)
	#
	# mkinitrd will set this variable if the system time was older than
	# the mkinitrd.rpm build time.
	if test -n "$SYSTEM_TIME_INCORRECT" ; then
	    echo -n "The system time was incorrect: '${warn}$SYSTEM_TIME_INCORRECT${norm}'"
	    rc_status -s
	    rc_exit
	fi
	if test "$USE_HWCLOCK" != yes ; then

	    echo -n Setting up the System Clock

	    unset TZ

	    case "$1$HWCLOCK" in
	    start*-l*)
		date --set "$(date --utc +'%Y-%m-%d %H:%M:%S.%N')"
		rc_status
		;;
	    esac

	    rc_status -v
	    rc_exit
	fi
	if test "$ELEVENMIN_MODE" = yes ; then
	    echo "The System Time is in sync with Hardware Clock ${stat}${done}good${norm}"
	    rc_status
	    rc_exit
	fi
	#
	# Set and adjust the hardware clock
	#	
	echo -n "Set System Time to the current Hardware Clock"
	#
	# Read out to hardware clock and for UTC calculate adjtime
	# write back the system time later at reboot/shutdown time.
	#
	if test "$USE_ADJFILE" = yes ; then
	    #
	    # For UTC calculate adjtime
	    #
	    if test ! -s /etc/adjtime ; then
		{
			echo "0.0 0 0.0"
			echo "0"
			echo "UTC"
		} > /etc/adjtime
	    else
		test -w /etc/adjtime && adjfile_thirdline
	    fi
	    rtc_rule /sbin/hwclock $HWCLOCK --adjust
	else
	    # Change any /etc/adjtime left over
	    test -w /etc/adjtime && adjfile_thirdline
	    SYSTZ="--systz"
            test -e /dev/shm/warpclock && SYSTZ=""
	    rtc_rule /sbin/hwclock $SYSTZ $HWCLOCK --noadjfile
	fi
	rc_status -v
	;;
    stop)
	if test "$ELEVENMIN_MODE" = yes ; then
	    echo "The System Time is in sync with Hardware Clock ${stat}${done}good${norm}"
	    rc_status
	    rc_exit
	fi
	if test "$USE_HWCLOCK" = yes -a "$SYSTOHC" = yes ; then
	    echo -n "Set Hardware Clock to the current System Time"
	    #
	    # Write system time back to hardware clock
	    #
	    if test "$USE_ADJFILE" = yes ; then
		/sbin/hwclock --systohc $HWCLOCK
	    else
		# Change any /etc/adjtime left over
		test -w /etc/adjtime && adjfile_thirdline
		/sbin/hwclock --systohc $HWCLOCK --noadjfile
	    fi
	    rc_status -v
	fi
	;;
    timezone)
	echo -n "Set Hardware Clock to the current System Time"
	if test "$USE_HWCLOCK" = yes ; then
	    /sbin/hwclock --systohc $HWCLOCK --noadjfile
	    /sbin/hwclock --hctosys $HWCLOCK --noadjfile
	else
	    rc_status -u
	fi
	;;
    status)
	echo -n "Current Hardware Clock: "
	/sbin/hwclock --show
	rc_status -v1
	;;
    *)
	echo "Usage: $0 {start|stop|status|restart|reload|force-reload|timezone}"
	exit 1
	;;
esac

rc_exit
