#!/bin/bash
#
# Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
# 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; either version 2 of the License, or (at your option) any later
# version.
#
# 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, see <http://www.gnu.org/licenses/>.
#
# Author: Michael Calmer <mc@suse.de>
#         Marius Tomaschewski <mt@suse.de>
#
##

unset POSIXLY_CORRECT ; set +o posix # we are using non-posix bash features

# The environment variable ROOT indicates the root of the system to be
# managed by SuSEconfig when that root is not '/'
r="$ROOT"

. "$r/etc/sysconfig/network/scripts/functions.netconfig"

PROGNAME="${0##*/}"
if test "$UID" != "0" -a "$USER" != root -a -z "$ROOT" ; then
    warn "You must be root to start $0."
    exit 1
fi

SYSFSDIR="/sys/class/net"
STATEDIR="/run/netconfig"
debug "$PROGNAME Module called"

. "$r/etc/sysconfig/network/config"

NTP_SERVER_LIST=()

CHRONY_SERVER="$STATEDIR/chrony.servers"
NTPD_DESTFILE="/run/ntp/servers-netconfig"

function dump_chrony_servers()
{
    local ns os SERVERS=()

    for ns in $1; do
        for os in "${SERVERS[@]}" ; do
            [ "x$ns" == "x$os" ] && continue 2
        done

        SERVERS+=("$ns")
        echo "$ns"
    done
}

function dump_ntpd_servers()
{
    cat << EOT
### $DESTFILE file autogenerated by netconfig!
#
# Before you change this file manually, consider to define the
# static NTP configuration using the following variables in the
# /etc/sysconfig/network/config file:
#     NETCONFIG_NTP_STATIC_SERVERS
# or disable NTP configuration updates via netconfig by setting:
#     NETCONFIG_NTP_POLICY=''
#
# See also the netconfig(8) manual page and other documentation.
#
EOT

    for ns in $1; do
        for os in "${SERVERS[@]}" ; do
            [ "x$ns" == "x$os" ] && continue 2
        done

        SERVERS+=("${ns}")
    done

    if [ ${#SERVERS[@]} -gt 0 ]; then
        echo "RUNTIME_SERVERS='${SERVERS[@]}'"
    fi
}

function write_chrony_servers()
{
    local TMP_FILE=""
    local changed=0

    debug "write_chrony_servers: $1"

    TMP_FILE=`netconfig_mktemp "$ROOT$CHRONY_SERVER" 0644 0755` || return 3
    if ! dump_chrony_servers "$@" >> "$TMP_FILE"     ; then
        rm -f -- "$TMP_FILE" ; return 3
    fi
    if cmp -s -- "$TMP_FILE" "$ROOT$CHRONY_SERVER"   ; then
        rm -f -- "$TMP_FILE" # unchanged
    elif mv -f -- "$TMP_FILE" "$ROOT$CHRONY_SERVER"  ; then
        changed=1
    else
        rm -f -- "$TMP_FILE"
        return 3
    fi

    debug "ntp servers written to $CHRONY_SERVER"
    test $changed -ne 0
}

function write_ntpd_servers()
{
    local TMP_FILE=""
    local changed=0

    if [ "X$1" = "X" ]; then
        # empty list of ntp servers 
        # => remove the runtime configuration file and report a change
        rm -f -- "$ROOT$NTPD_DESTFILE"
        return 1
    fi

    debug "write_ntpd_servers: $1"

    TMP_FILE=`netconfig_mktemp "$ROOT$NTPD_DESTFILE" 0644 0755` || return 3
    if ! dump_ntpd_servers "$@" >> "$TMP_FILE"       ; then
        rm -f -- "$TMP_FILE" ; return 3
    fi
    if cmp -s -- "$TMP_FILE" "$ROOT$NTPD_DESTFILE"   ; then
        rm -f -- "$TMP_FILE" # unchanged
    elif mv -f -- "$TMP_FILE" "$ROOT$NTPD_DESTFILE"  ; then
        changed=1
    else
        rm -f -- "$TMP_FILE" ; return 3
    fi

    debug "ntp servers written to $NTPD_DESTFILE"
    test $changed -ne 0
}

function get_ntp_settings()
{
    local cfg=$1 ; shift
    test "x$cfg" = x && return 1
    local NTPSERVERS

    debug "exec get_ntp_settings: $cfg"

    get_variable "NTPSERVERS" "$cfg"
    if [ "x$NTPSERVERS" != "x" ]; then
        for ns in $NTPSERVERS; do
            for os in "${NTP_SERVER_LIST[@]}" ; do
                [ "x$ns" == "x$os" ] && continue 2
            done
            NTP_SERVER_LIST+=($ns)
        done
    fi
    unset NTPSERVERS
    debug "     get_ntp_settings: NTP_SERVER_LIST='${NTP_SERVER_LIST[@]}'"

    debug "exit get_ntp_settings: $cfg"
    return 0
}

function manage_interfaceconfig()
{
    local cfg dir="$1" ; shift
    test "x$dir" != x -a -d "$dir" || return 1

    debug "exec manage_interfaceconfig: $dir"
    for cfg in `ls -X -r "$dir/" 2>/dev/null`; do
        get_ntp_settings "$dir/$cfg"
    done
    debug "exit manage_interfaceconfig: $dir"
    return 0
}


# *********************
# EXECUTION STARTS HERE
# *********************

# just for the case we need the original value...
_NETCONFIG_NTP_POLICY=`netconfig_policy "$NETCONFIG_NTP_POLICY" ntp`
if [ "x$_NETCONFIG_NTP_POLICY" = "x" ]; then
    #
    # empty policy means do not touch anything. 
    # successful exit.
    #
    exit 0;
fi

sf=0
_g=1
# disable filename glob expansion if needed
shopt -o -q noglob || _g=0
[ $_g ] && shopt -o -s noglob
for POL in $_NETCONFIG_NTP_POLICY; do
    shopt -o -u noglob
    case "$POL" in
    (NetworkManager)
        debug "Use NetworkManager policy merged settings"
        cfg="$ROOT$STATEDIR/NetworkManager.netconfig"
        if [ -r "$cfg" ] ; then
            get_ntp_settings "$cfg"
        fi
        break
    ;;
    (STATIC)
        debug "Keep Static"
        NTP_SERVER_LIST=(${NTP_SERVER_LIST[@]} $NETCONFIG_NTP_STATIC_SERVERS)
        ;;
        (STATIC_FALLBACK)
        debug "Static Fallback"
        sf=1
    ;;
    (*)
        debug "Other: $POL"
        for IFDIR in $ROOT$STATEDIR/$POL; do
            test -d "$IFDIR" -a \
                 -d "$SYSFSDIR/${IFDIR##*/}" || continue
            # proceed every interface we find with this match
            manage_interfaceconfig  "$IFDIR"
        done
    ;;
    esac
done
[ $_g ] && shopt -o -u noglob

if [ $sf -eq 1 -a ${#NTP_SERVER_LIST[@]} -eq 0 ]; then
    NTP_SERVER_LIST=($NETCONFIG_NTP_STATIC_SERVERS)
fi

RET=0

write_chrony_servers "${NTP_SERVER_LIST[*]}"
result=$?
case $result in
0)  # server list successfully changed
    for dir in /usr/libexec /usr/lib ; do
      if test -x "$dir/chrony/helper" ; then
        (
            exec </dev/null 1>/dev/null 2>/dev/null
            "$dir/chrony/helper" update-daemon &
        )
        disown -a
        break
      fi
    done
    ;;
1)  # nothing changed; we are finished
    ;;
2)  # user modified the config. note: unused case now.
    echo "ATTENTION: You have modified ${CHRONY_SERVER}."
    RET=20
    ;;
esac

write_ntpd_servers "${NTP_SERVER_LIST[*]}"
result=$?
case $result in
0)  # server list successfully changed
    if test -x /usr/sbin/start-ntpd ; then
        (
            exec </dev/null 1>/dev/null 2>/dev/null
            /usr/sbin/start-ntpd addserver "${NTP_SERVER_LIST[*]}" &
        )
        disown -a
    fi
    ;;
1)  # nothing changed; we are finished
    ;;
2)  # user modified the config. note: unused case now.
    echo "ATTENTION: You have modified ${NTPD_DESTFILE}."
    RET=20
    ;;
esac

exit $RET

# vim: set ts=8 sts=4 sw=4 ai et:
