Newer
Older
#!/bin/bash
# This script measure the drift between the local system clock and
# a NTP server
tmpdir="/tmp"
cronFile="/etc/cron.d/root"
tmpCronFile="$tmpdir/root.cron"
prefix="system_clock_monitor"
debugLogFile="$tmpdir/$prefix.log"
script="/etc/init.d/system_clock_monitor"
systemClockMonitoringStatus="$tmpdir/${prefix}_status"
systemClockMonitoringDrift="$tmpdir/${prefix}_drift"
dotConfig="/wr/etc/dot-config"
fileNtpServerConfig="/etc/wr_date.conf"
ntpTool="/usr/sbin/ntpd"
suspendKillDaemon=0
pidKillDaemon=0
verbose=0
#
# Write message to file
# $1: Message
# $2: Output file
writeMsg() {
msg=$1
of=$2
oft="$of.old"
# If old file exists then remove it
if [ -f $oft ] ; then
rm -f $oft
fi
# if file exists then rename it
if [ -f $of ] ; then
mv $of $oft
fi
# create the file
echo "$msg" > $of
}
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#
# Print message if verbose is set
#
debug () {
if [[ $verbose == 1 ]]; then
echo $1 >&1| tee -a $debugLogFile
eval echo $1 $LOGPIPE
fi
}
#
# remove from cron file any entry related to system clock monitor
#
cleanCronConfig ()
{
local entryPresent=0
set -f
: > $tmpCronFile
while IFS= read -r line; do
if [[ "$line" =~ $script ]] ; then
entryPresent=1
else
echo "$line" >> $tmpCronFile
fi
done < "$cronFile"
if (( entryPresent == 1 )) ; then
debug "$cronFile has been cleaned up"
mv $cronFile $cronFile.old
mv $tmpCronFile $cronFile
else
debug "$cronFile does not need to be cleaned up "
rm -f $tmpCronFile
fi
set +f
}
#
# Add system clock monitor entry in crontab
#
setCronConfig ()
{
local __entry=$1
debug "Add new entry in cron file $cronFile"
debug "New entry added \"$__entry\""
echo "$entry" >> $cronFile
}
#
# Compare the offset to the threshold value
#
compareToThreshold ()
{
local __resultvar=$1
Adam Wujek
committed
# $(( )) to remove leading "+"
local __c_offset=$(( $2 ))
local __c_threshold=$3
if (( $__c_offset >= __c_threshold )) ; then
Adam Wujek
committed
x=$(( $__c_offset - $__c_threshold ))
debug "X1System clock drift is exceeding the threshold by ${x} sec"
eval $__resultvar="1"
elif (( -$__c_offset >= __c_threshold )) ; then
x=$(( $__c_offset + $__c_threshold ))
debug "X2System clock drift is exceeding the threshold by ${x} sec"
eval $__resultvar="1"
else
debug "System clock drift is not exceeding the threshold"
eval $__resultvar="0"
fi
}
#
Adam Wujek
committed
# Decode NTPD deamon output to get the offset in seconds.useconds
Adam Wujek
committed
decodeOffset ()
{
local __resultvar=$1
local __str=$2
Adam Wujek
committed
local __offset=$(echo $__str | sed -n 's/.* offset:\?\([+-][0-9]*\)\.\?\([0-9]*\) .*/\1.\2/p')
if [[ -z "$__offset" ]] ; then
# Empty string
debug "Invalid Offset !!!"
debug "NTP msg=\"$__str\""
Adam Wujek
committed
return 1
else
# Change the sign of the offset. ntpd returns a positive
# offset when the ntp time is ahead of the local time, which is
# counter-intuitive.
if [ "${__offset:0:1}" = "-" ]; then
__offset=+${__offset:1}
elif [ "${__offset:0:1}" = "+" ]; then
__offset=-${__offset:1}
fi
debug "NTP offset=$__offset s"
Adam Wujek
committed
return 0
Adam Wujek
committed
#
# Kill the NTPD daemon in background after few seconds
#
killNTPD ()
{
local delay=$1 # Delay in seconds
if (( $pidKillDaemon != 0 )) ; then
debug "Daemon actif !!!"
kill -9 $pidKillDaemon &>/dev/null
pidKillDaemon=0
fi
(
sleep $delay
Adam Wujek
committed
ppid=$$
# Search for a ntpd only within this script's childs
p=$(pgrep -g $ppid $ntpTool)
if [[ -n "$p" ]] ; then
kill -9 $p &>/dev/null
fi
pidKillDaemon=0
) &
pidKillDaemon=$!
}
#
# Read the NTP server to get the offset between NTP and local system time
#
read_ntp_server()
{
local __result=$1
local ltThreshold=$2
local server=$3
local retries=2
local offset=-1
debug "NTP server=$server"
for i in `seq $retries` ; do # Manual retries
killNTPD 10
ntpRes=$($ntpTool -n -w -q -d -p $server 2>&1)
if [ -n "$ntpRes" ] ; then
Adam Wujek
committed
decodeOffset offset "$ntpRes"
if [ $? -eq 0 ] ; then
compareToThreshold alarmState ${offset%.*} $ltThreshold
if (( $alarmState == 1 )) ; then
# Exceeded Threshold
writeMsg "exceeded_threshold" $systemClockMonitoringStatus
writeMsg "no_error" $systemClockMonitoringStatus
writeMsg $offset $systemClockMonitoringDrift
eval $__result="0"
return
fi
eval echo "Retry $i/$retries : Cannot extract offset from NTP message." $LOGPIPE
eval echo "Retry $i/$retries : NTP query failed, unable to contact server ($server)." $LOGPIPE
eval echo "ERROR: could not reach NTP server '$S' after $retries retries" $LOGPIPE
eval $__result="1"
}
#
# Apply dot-config configuration
#
if [ -f $dotConfig ]; then
# source dot-config
. $dotConfig
else
echo "$0 unable to source dot-config ($dotConfig)!"
fi
WRS_LOG=$CONFIG_WRS_LOG_OTHER
# if empty turn it to /dev/null
if [ -z $WRS_LOG ]; then
WRS_LOG="/dev/null";
fi
# if a pathname, use it
if echo "$WRS_LOG" | grep / > /dev/null; then
eval LOGPIPE=\" \> $WRS_LOG 2\>\&1 \";
Maciej Lipinski
committed
elif [ "$WRS_LOG" = "default_syslog" ]; then
# not a pathname: use verbatim
Maciej Lipinski
committed
eval LOGPIPE=\" 2\>\&1 \| logger -t $prefix --prio-prefix -p daemon.info\"
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
else
# not a pathname: use verbatim
eval LOGPIPE=\" 2\>\&1 \| logger -t $prefix -p $WRS_LOG\"
fi
debug "Script started with options \"$@\""
# Read options
if [ "$#" -eq 1 ] && [ "$1" == "-s" ] ; then
debug "Setup configuration"
cleanCronConfig
if [ "$CONFIG_SNMP_SYSTEM_CLOCK_MONITOR_ENABLED" = "y" ] ; then
set -f # Disable globbing
NEWLINE=$'\n'
# System clock monitor enabled. Setup cron file
if [ "$CONFIG_SNMP_SYSTEM_CLOCK_UNIT_MINUTES" = "y" ] ; then
intervalValue=$CONFIG_SNMP_SYSTEM_CLOCK_CHECK_INTERVAL_MINUTES
debug "Time interval: ${intervalValue} minutes"
entry="# System clock monitor: Execute the script \"${script}\" every ${intervalValue} minute(s)${NEWLINE}"
entry+="*/${intervalValue} * * * * ${script}";
setCronConfig "$entry"
else
if [ "$CONFIG_SNMP_SYSTEM_CLOCK_UNIT_HOURS" = "y" ] ; then
intervalValue=$CONFIG_SNMP_SYSTEM_CLOCK_CHECK_INTERVAL_HOURS
debug "Time interval: ${intervalValue} hours"
entry="# System clock monitor: Execute the script \"${script}\" every ${intervalValue} hour(s)${NEWLINE}"
Adam Wujek
committed
entry+="0 */${intervalValue} * * * ${script}"
setCronConfig "$entry"
else
if [ "$CONFIG_SNMP_SYSTEM_CLOCK_UNIT_DAYS" = "y" ]; then
intervalValue=$CONFIG_SNMP_SYSTEM_CLOCK_CHECK_INTERVAL_DAYS
debug "Time interval: ${intervalValue} days"
entry="# System clock monitor: Execute the script \"${script}\" every ${intervalValue} day(s)${NEWLINE}"
Adam Wujek
committed
entry+="0 0 */${intervalValue} * * ${script}"
setCronConfig "$entry"
else
eval echo "Invalid unit for system clock check interval." $LOGPIPE
writeMsg "config_error" $systemClockMonitoringStatus
writeMsg "0" $systemClockMonitoringDrift
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
exit 1
fi
fi
fi
set +f # Re-enable globbing
eval echo "cron file \"root\" configured" $LOGPIPE
else
# System clock monitor disabled. Make a clean up
rm -f $systemClockMonitoringStatus
rm -f $systemClockMonitoringDrift
fi
exit 0
fi
if [ "$CONFIG_SNMP_SYSTEM_CLOCK_MONITOR_ENABLED" = "y" ] ; then
threshold=$CONFIG_SNMP_SYSTEM_CLOCK_DRIFT_THOLD
ntpServer=""
# Get the NTP server
if [ -f $fileNtpServerConfig ]; then
# pick the first server, if any
ntpServer=$(grep 'ntpserver' $fileNtpServerConfig | sed 's/ntpserver//' | head -n 1)
fi
if [ -z "$threshold" ] ; then
eval echo "System clock drift threshold not set." $LOGPIPE
writeMsg "config_error" $systemClockMonitoringStatus
writeMsg "0" $systemClockMonitoringDrift
exit 1
fi
if [ -z "$ntpServer" ]; then
eval echo "Empty NTP server name" $LOGPIPE
writeMsg "config_error" $systemClockMonitoringStatus
writeMsg "0" $systemClockMonitoringDrift
exit 1
fi
read_ntp_server result $threshold $ntpServer
if (( result != 0 )) ; then
writeMsg "ntp_error" $systemClockMonitoringStatus
writeMsg "0" $systemClockMonitoringDrift