#!/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 -- "

Time Synchronization Report

" #### #### 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/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 -- "

" 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 -- "

" 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 -- "
Server Name Base Time Server Time Delta
${NODE} ${LOCTIME} ${REMTIME} ${DELTA}
${NODE} ${LOCTIME}    

Legend

" 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 "${@}"