Mini Shell
Direktori : /usr/bin/ |
|
Current File : //usr/bin/ntpstat |
#!/bin/bash
#
# This is a shell script which prints the ntpd or chronyd synchronisation
# status, using the ntpq or chronyc program. It emulates the original
# ntpstat program written in C by G. Richard Keech, which implemented a
# subset of the mode6 protocol supported by ntpd.
#
# Copyright (C) 2016 Miroslav Lichvar <mlichvar@redhat.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
CHRONYC=("chronyc" "-n")
NTPQ=("ntpq" "-c" "timeout 100" "-c" "raw")
export LC_ALL=C
parse_tracking_field() {
local tracking=$1 name=$2 field
field=$(echo "$tracking" | grep "^$name")
echo "${field#* : }"
}
get_chronyd_state() {
local output line disp delay
local leap source address stratum distance poll
output=$("${CHRONYC[@]}" tracking 2> /dev/null) || return 2
leap=$(parse_tracking_field "$output" "Leap status")
case "$leap" in
"Normal") leap="0";;
"Insert second") leap="1";;
"Delete second") leap="2";;
"Not synchronised") leap="3";;
esac
address=$(parse_tracking_field "$output" "Reference ID")
address=${address%)*}
address=${address#*(}
stratum=$(parse_tracking_field "$output" "Stratum")
delay=$(parse_tracking_field "$output" "Root delay")
delay=${delay% seconds}
disp=$(parse_tracking_field "$output" "Root dispersion")
disp=${disp% seconds}
offset=$(parse_tracking_field "$output" "System time")
offset=${offset% seconds*}
distance=$(echo "$delay $disp $offset" | \
awk '{ printf "%.3f", ($1 / 2.0 + $2 + $3) * 1e3 }')
if [ -n "$address" ]; then
line=$("${CHRONYC[@]}" sources 2> /dev/null | \
grep " $address ") || return 3
poll=$(echo "$line" | awk '{ print $4 }')
case "${line:0:1}" in
"*"|"=") source="NTP server";;
"#") source="reference clock";;
*) source="unknown source";;
esac
fi
echo "$leap,NTP server,$address,$stratum,$distance,$poll"
}
parse_rv_field() {
local rv=$1 name=$2 field
field=$(echo "$rv" | grep -o "$name=[^,]*")
echo "${field#*=}"
}
get_ntpd_state() {
local output syspeer_id disp delay
local leap source address stratum distance poll
output=$("${NTPQ[@]}" -c "rv 0" 2> /dev/null) || return 2
[[ $output == *"associd"*"status"* ]] || return 3
leap=$(parse_rv_field "$output" "leap")
source=$(parse_rv_field "$output" "status" | \
awk '{ print and(rshift(strtonum($1), 8), 0x3f) }')
case "$source" in
0) source="unspecified";;
1) source="atomic clock";;
2) source="VLF radio";;
3) source="HF radio";;
4) source="UHF radio";;
5) source="local net";;
6) source="NTP server";;
7) source="UDP/TIME";;
8) source="wristwatch";;
9) source="modem";;
*) source="unknown source";;
esac
stratum=$(parse_rv_field "$output" "stratum")
delay=$(parse_rv_field "$output" "rootdelay")
disp=$(parse_rv_field "$output" "rootdisp")
distance=$(echo "$delay $disp" | awk '{ printf "%.3f", $1 / 2.0 + $2 }')
syspeer_id=$("${NTPQ[@]}" -c associations 2> /dev/null |\
grep 'sys\.peer' | awk '{ print $2 }') || return 4
output=$("${NTPQ[@]}" -c "rv $syspeer_id" 2> /dev/null) || return 5
if [ "$source" = "NTP server" ]; then
address=$(parse_rv_field "$output" "srcadr")
fi
poll=$(parse_rv_field "$output" "hpoll")
echo "$leap,$source,$address,$stratum,$distance,$poll"
}
max_distance=""
while getopts "m:h" opt; do
case $opt in
m)
max_distance=$OPTARG
;;
*)
echo "Usage: $0 [-m MAXERROR]"
exit 3
;;
esac
done
if ! state=$(get_chronyd_state) && ! state=$(get_ntpd_state); then
echo "Unable to talk to NTP daemon. Is it running?" >&2
exit 2
fi
IFS=, read -r leap source address stratum distance poll <<< "$state"
if [ "$leap" -ge 0 -a "$leap" -le 2 ]; then
printf "synchronised to %s" "$source"
if [ -n "$address" ]; then
printf " (%s)" "$address"
fi
if [ -n "$stratum" ]; then
printf " at stratum %d\n" "$stratum"
else
printf ", stratum unknown\n"
fi
if [ -n "$distance" ]; then
printf " time correct to within %.0f ms" "$distance"
if [ -n "$max_distance" ] &&
echo "$distance $max_distance" | awk '{ exit $1 <= $2 }'; then
printf " (exceeded maximum of %s ms)\n" "$max_distance"
status=1
else
printf "\n"
status=0
fi
else
printf "accuracy unknown\n"
[ -n "$max_distance" ] && status=1 || status=0
fi
else
printf "unsynchronised\n"
status=1
fi
if [ -n "$poll" ]; then
printf " polling server every %d s\n" "$[2**$poll]"
else
printf "poll interval unknown\n"
fi
exit $status
Zerion Mini Shell 1.0