cmptime_k93
Korn Shell 93 function to compare the date between two or more systems and generates a time synchronization report in HTML format.
This script compares the system time from the local system running this script to the system time of a remote system, and reports the difference between the times. The "daytime" daemon on the remote system is used to obtain the system time of the remote system and is assumed to be running.
This script assumes the "daytime" daemon is started and running on the remote system, or is configured and started by the "inetd" daemon.
The following standard unix commands are assumed to be accessible via the PATH environment variable:
This script is dependent upon a VERY RECENT version of Korn Shell 93 being used as the script interpreter. The IBM AIX version of ksh93 at /usr/bin/ksh93 is about 7 years out of date, even on the latest version of AIX (5.3), and WILL NOT WORK. It is recommended that you download and install the ATT version of ksh93 from www.kornshell.com and install it at the location "/usr/bin/ksh93.att". Then change the shebang line (#!/usr/bin/ksh93) of this script to use the ATT ksh93 (#!/usr/bin/ksh93.att)
This script generates HTML output that may be redirected to a file, or the output file may be specified on the command line.
This script may executed from the command line, called by other scripts as a function, or integrated into a script function library. When used as a scheduled job to run periodically, it is best to use a server list file containing the names of the systems to poll.
#!/usr/bin/ksh93
#################################################################
function usagemsg_cmptime_k93 {
print -u 2 -- "
Program: cmptime_k93
Compare the time from the system running this script to
the time on each system from a list of remote systems,
and generate a time synchronization report in HTML
format to identify the differences. Color coded output
is generated to segment the synchronized systems from
the out-of-sync.
Usage: ${1##*/} [-?] [-vV][ -s serverListFile ] [ -h HTMLfile ]
[ -u userName ] [ -w webServer ] [ -d /dir/Name ]
[ -m # ] [ -x # ] [ hostName ... ]
Where:
-s fileName = File containing list of server names
File format: nodeName|commName
where "commName" is the network accessible host name
-t delimiter = Single character delimiter used by server name list file
( default: | )
-h fileName = HTML output file name
( default: STDOUT )
-u userName = Web server user name for password-less ssh
file transfer of output file
( default: NULL )
-w webServer = Web server host name
( default: NULL )
-d /dir/Name = Web server directory for output file storage
( default: /srv/www/htdocs )
-m # = Number of seconds to consider time synchronized
( default: 3 )
-x # = Number of seconds to alert as unsynchronized
( default: 60 )
-v = Verbose Mode
-V = Very Verbose Mode
Author: Dana French (dfrench@mtxia.com)
Copyright 2007 by Dana French: All Rights Reserved
\"AutoContent\" enabled
"
}
################################################################
####
#### Description:
####
#### This script compares the system time from the local
#### system running this script to the system time of a
#### remote system, and reports the difference between the
#### times. The "daytime" daemon on the remote system is
#### used to obtain the system time of the remote system and
#### is assumed to be running.
####
#### Assumptions:
####
#### This script assumes the "daytime" daemon is started and
#### running on the remote system, or is configured and
#### started by the "inetd" daemon.
####
#### The following standard unix commands are assumed to be
#### accessible via the PATH environment variable:
####
#### host
#### ping
#### grep
#### wc
####
#### Dependencies:
####
#### This script is dependent upon a VERY RECENT version of
#### Korn Shell 93 being used as the script interpreter. The
#### IBM AIX version of ksh93 at /usr/bin/ksh93 is about 7
#### years out of date, even on the latest version of AIX
#### (5.3), and WILL NOT WORK. It is recommended that you
#### download and install the ATT version of ksh93 from
#### www.kornshell.com and install it at the location
#### "/usr/bin/ksh93.att". Then change the shebang line
#### (#!/usr/bin/ksh93) of this script to use the ATT ksh93
#### (#!/usr/bin/ksh93.att)
####
#### Products:
####
#### This script generates HTML output that may be redirected
#### to a file, or the output file may be specified on the
#### command line.
####
#### Configured Usage:
####
#### This script may executed from the command line, called
#### by other scripts as a function, or integrated into a
#### script function library. When used as a scheduled job
#### to run periodically, it is best to use a server list
#### file containing the names of the systems to poll.
####
#### Details:
####
################################################################
function cmptime_k93 {
typeset VERSION="1.0"
typeset TRUE="0"
typeset FALSE="1"
typeset VERBOSE="${FALSE}"
typeset VERYVERB="${FALSE}"
typeset -l NODE
typeset -l COMM
typeset SERVLIST=""
typeset DELIM='|'
typeset TMPLIST="/tmp/tmp${$}.list"
typeset TMPFILE="/tmp/tmp${$}.html"
typeset HTMLFILE="cmptime.html"
typeset WEBUSER=""
typeset WEBHOST=""
typeset WEBDIR="/srv/www/htdocs"
typeset MINDIFF="3"
typeset MAXDIFF="60"
typeset DELTA
typeset BGCOLOR
typeset LOCTIME
typeset REMTIME
typeset LOCSEC
typeset REMSEC
typeset JOBCNT
typeset IP
typeset OPTION
while getopts ":vVs:t:h:u:w:d:m#x#" OPTION
do
case "${OPTION}" in
's') SERVLIST="${OPTARG}";;
't') DELIM="${OPTARG}";;
'h') HTMLFILE="${OPTARG}";;
'u') WEBUSER="${OPTARG}";;
'w') WEBHOST="${OPTARG}";;
'd') WEBDIR="${OPTARG}";;
'm') MINDIFF="${OPTARG}";;
'x') MAXDIFF="${OPTARG}";;
'v') VERBOSE="${TRUE}";;
'V') VERYVERB="${TRUE}";;
[?:#]) usagemsg_cmptime_k93 "${0}" && return 1 ;;
esac
done
shift $(( ${OPTIND} - 1 ))
(( VERBOSE == TRUE )) && print -u 2 -- "# Version................................: ${VERSION}"
################################################################
####
#### Determine if remote server names or a server name list
#### file was specified on the command line. Which ever was
#### specified, copy the information to a temporary list file
#### to use for polling each server individually.
trap "usagemsg_cmptime_k93 ${0}" EXIT
rm -f "${TMPLIST}"
if [[ "_${SERVLIST}" == "_" ]]
then
(( VERBOSE == TRUE )) && print -u 2 -- "# Remote server names found on cmd line..: ${#@}"
for H in "${@}"
do
(( VERBOSE == TRUE )) && print -u 2 -- "# Remote server name specified on cmdline: ${H}"
print -- "${H}${DELIM}${H}${DELIM}"
done > "${TMPLIST}"
else
if [[ -s "${SERVLIST}" ]]
then
(( VERBOSE == TRUE )) && print -u 2 -- "# Server list file found.................: ${SERVLIST}"
cp -f "${SERVLIST}" "${TMPLIST}"
else
(( VERBOSE == TRUE )) && print -u 2 -- "# ERROR: Server list file not found......: ${SERVLIST}"
return 1
fi
fi
trap "-" EXIT
################################################################
####
#### If verbose mode was specified by the user on the command
#### line, output the configuration information to the
#### standard error stream STDERR.
(( VERBOSE == TRUE )) && print -u 2 -- "# Server list file delimiter ............: ${DELIM}"
(( VERBOSE == TRUE )) && print -u 2 -- "# HTML output file name..................: ${HTMLFILE}"
(( VERBOSE == TRUE )) && print -u 2 -- "# User w/pwd-less ssh access to web srvr.: ${WEBUSER}"
(( VERBOSE == TRUE )) && print -u 2 -- "# Web server host name...................: ${WEBHOST}"
(( VERBOSE == TRUE )) && print -u 2 -- "# Web server output directory name.......: ${WEBDIR}"
(( VERBOSE == TRUE )) && print -u 2 -- "# Minimum difference for sync (seconds)..: ${MINDIFF}"
(( VERBOSE == TRUE )) && print -u 2 -- "# Maximum difference for alert (seconds).: ${MAXDIFF}"
if [[ "_${WEBUSER}" != "_" ]] &&
[[ "_${WEBHOST}" != "_" ]] &&
[[ "_${HTMLFILE}" != "_" ]]
then
(( VERBOSE == TRUE )) && print -u 2 -- "# Output file WILL be transferred to web server"
else
(( VERBOSE == TRUE )) && print -u 2 -- "# Output file WILL NOT be transferred to web server"
fi
################################################################
####
#### Open the HTML output file and output the page
#### initialization information.
exec 3>"${TMPFILE}"
print -u 3 -- "<HTML>
<BODY>
<P><H4>Time Synchronization Report</H4></P>
<P>
<TABLE Border="1" Cellspacing="2" Cellpadding="2">
<P><TR>
<TH Bgcolor=\"white\">Server Name</TH>
<TH Bgcolor=\"white\">Base Time</TH>
<TH Bgcolor=\"white\">Server Time</TH>
<TH Bgcolor=\"white\">Delta</TH>
</TR></P>"
####
#### Read the node and communication names from a temporary
#### file created from node names provided on the command
#### line, or from a server name list file specified on the
#### command line by the user.
while IFS="${DELIM}" read -r -- NODE COMM OS
do
[[ "_${NODE}" == "_" ]] && continue
[[ "_${NODE}" == _\#* ]] && continue
( if ping -c 2 ${COMM} > /dev/null 2>&1
then
(( VERBOSE == TRUE )) && print -u 2 -- "# Successful ping........................: ${COMM}"
DELTA="0"
LOCTIME=$( printf '%(%c)T\n' )
####
#### Determine if the value of the communication name variable "COMM"
#### contains and IP address or a host name. If it is a host
#### name, resolve the IP address from it.
if [[ "_${COMM}" == _+([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
then
IP="${COMM}"
else
IP=$( host ${COMM} | grep '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*' )
IP="${IP%%,*}"
IP="${IP##* }"
fi
(( VERBOSE == TRUE )) && print -u 2 -- "# IP Address.............................: ${IP}"
####
#### Open a network connection to the remote system's daytime
#### network port (13), and retrieve the current system time.
#### Also obtain the local system time for comparison.
if exec 4</dev/tcp/${IP}/13 > /dev/null 2>&1
then
read -u 4 -r -- REMTIME
LOCTIME=$( printf '%(%c)T\n' )
LOCTIME="${LOCTIME// [A-Z][SD]T / }"
REMTIME=${REMTIME%[!a-zA-Z0-9: ]}
REMTIME="${REMTIME// [A-Z][SD]T / }"
exec 4<&-
else
(( VERBOSE == TRUE )) && print -u 2 -- "# ERROR: No connection to daytime port...: ${COMM}"
fi
if [[ "_${REMTIME}" == "_" ]]
then
(( VERBOSE == TRUE )) && print -u 2 -- "# ERROR: Invalid remote time from........: ${COMM}"
fi
####
#### If the local time variable "LOCTIME" and the remote
#### system time variable "REMTIME" are both non-NULL, then
#### convert the dates to seconds since epoch and determine
#### the difference between them.
if [[ "_${LOCTIME}" != "_" ]] && [[ "_${REMTIME}" != "_" ]]
then
LOCSEC=$( printf '%(%s)T\n' "${LOCTIME}" )
REMSEC=$( printf '%(%s)T\n' "${REMTIME}" )
[[ "_${LOCSEC}" != "_" ]] &&
[[ "_${REMSEC}" != "_" ]] &&
(( DELTA = LOCSEC - REMSEC ))
BGCOLOR="lightgrey"
(( abs(DELTA) >= 0 )) && (( abs(DELTA) <= MINDIFF )) && BGCOLOR="lightgreen"
(( abs(DELTA) >= MAXDIFF )) && BGCOLOR="red"
[[ "_${LOCTIME}" == "_" ]] || [[ "_${REMTIME}" == "_" ]] && BGCOLOR="yellow"
#### Output the node and time information in HTML format
print -u 3 -- "<P><TR>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\">${NODE}</FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\">${LOCTIME}</FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\">${REMTIME}</FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\" Align=\"right\"><FONT Size=\"1\">${DELTA}</FONT></TD>
</TR></P>"
fi
else
#### If the node was not pingable, output the node and local
#### time information in HTML format.
(( VERBOSE == TRUE )) && print -u 2 -- "# Unsuccessful ping......................: ${COMM}"
BGCOLOR="yellow"
LOCTIME=$( printf '%(%c)T\n' )
print -u 3 -- "<P><TR>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\">${NODE}</FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\">${LOCTIME}</FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\"> </FONT></TD>
<TD Bgcolor=\"${BGCOLOR}\"><FONT Size=\"1\"> </FONT></TD>
</TR></P>"
fi ) &
done < "${TMPLIST}"
rm -f "${TMPLIST}"
####
#### The retrieval of the remote system time is performed as
#### one or more background jobs. Test to see if any
#### of these background jobs are still running and if so,
#### sleep for a couple of seconds then test again. Keep
#### testing until the number of background jobs is zero.
JOBCNT="1"
while (( JOBCNT > 0 ))
do
JOBCNT=$( jobs | wc -l )
(( VERBOSE == TRUE )) && print -u 2 -- "# Processing Jobs........................: ${JOBCNT}"
sleep 2
done
#### Output a legend, in HTML format, that describes the
#### colors used to identify each type of output record.
print -u 3 -- "</TABLE>
</P>
<P><H4>Legend</H4></P>
<FONT Size=\"2\">
<UL>
<LI> <FONT Color=\"lightgreen\"><STRONG>GREEN</STRONG></FONT>: No difference from standard time</LI>
<LI> <FONT Color=\"lightgrey\"><STRONG>GREY</STRONG></FONT>: Less than ${MAXDIFF} seconds difference from standard time</LI>
<LI> <FONT Color=\"yellow\"><STRONG>YELLOW</STRONG></FONT>: Unable to determine difference from standard time</LI>
<LI> <FONT Color=\"red\"><STRONG>RED</STRONG></FONT>: More than ${MAXDIFF} seconds difference from standard time</LI>
<LI> <STRONG>Last updated</STRONG>: $( printf '%(%c)T\n' )</LI>
</UL>
</P>
</FONT>
</BODY>
</HTML>"
exec 3>&-
####
#### Check to see if the web user name, web server host name,
#### web server directory, and HTML output file was
#### specified. If so, then copy the output to the web
#### server. Remove the output file when complete.
if [[ "_${WEBUSER}" != "_" ]] &&
[[ "_${WEBHOST}" != "_" ]] &&
[[ "_${WEBDIR}" != "_" ]] &&
[[ "_${HTMLFILE}" != "_" ]] &&
[[ -s "${TMPFILE}" ]]
then
scp "${TMPFILE}" "${WEBUSER}@${WEBHOST}:${WEBDIR}/${HTMLFILE}"
else
[[ "_${HTMLFILE}" != "_" ]] && cp -f "${TMPFILE}" "${HTMLFILE}"
fi
rm -f "${TMPFILE}"
return 0
}
################################################################
cmptime_k93 "${@}"