File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / scripts / ntpsweep.in
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: #! @PATH_PERL@ -w
    2: #
    3: # $Id: ntpsweep.in,v 1.1.1.1 2012/05/29 12:08:38 misho Exp $
    4: #
    5: # DISCLAIMER
    6: # 
    7: # Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.
    8: # 
    9: # Permission to use, copy, modify and distribute this software and its
   10: # documentation for any purpose and without fee is hereby granted,
   11: # provided that the above copyright notice appears in all copies and
   12: # that both the copyright notice and this permission notice appear in
   13: # supporting documentation. This software is supported as is and without
   14: # any express or implied warranties, including, without limitation, the
   15: # implied warranties of merchantability and fitness for a particular
   16: # purpose. The name Origin B.V. must not be used to endorse or promote
   17: # products derived from this software without prior written permission.
   18: #
   19: # Hans Lambermont <ntpsweep@lambermont.dyndns.org>
   20: 
   21: require 5.0;		# But actually tested on 5.004 ;)
   22: use Getopt::Long;       # GetOptions()
   23: use strict;
   24: 
   25: my $version = 1.3;
   26: (my $program = $0) =~ s%.*/(.+?)(.pl)?$%$1%;
   27: 
   28: # Hardcoded paths/program names
   29: my $ntpdate = "ntpdate";
   30: my $ntpq = "ntpq";
   31: 
   32: # no STDOUT buffering
   33: $| = 1;
   34: 
   35: my ($help, $single_host, $showpeers, $maxlevel, $strip, $askversion);
   36: my $res = GetOptions("help!"      => \$help,
   37: 		     "host=s"     => \$single_host,
   38: 		     "peers!"     => \$showpeers,
   39: 		     "maxlevel=s" => \$maxlevel,
   40: 		     "strip=s"    => \$strip,
   41: 		     "version!"   => \$askversion);
   42: 
   43: if ($askversion) {
   44:     print("$version\n");
   45:     exit 0;
   46: }
   47: 
   48: if ($help || ((@ARGV != 1) && !$single_host)) {
   49:     warn <<EOF;
   50: This is $program, version $version
   51: Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.  Disclaimer inside.
   52: 
   53: Usage:
   54:   $program [--help|--peers|--strip <string>|--maxlevel <level>|--version] \\
   55:     <file>|[--host <hostname>]
   56: 
   57: Description:
   58:   $program prints per host given in <file> the NTP stratum level, the
   59:   clock offset in seconds, the daemon version, the operating system and
   60:   the processor. Optionally recursing through all peers.
   61: 
   62: Options:
   63: --help
   64:     Print this short help text and exit.
   65: --version
   66:     Print version ($version) and exit.
   67: <file>
   68:     Specify hosts file. File format is one hostname or ip number per line.
   69:     Lines beginning with # are considered as comment.
   70: --host <hostname>
   71:     Speficy a single host, bypassing the need for a hosts file.
   72: --peers
   73:     Recursively list all peers a host synchronizes to.
   74:     An '= ' before a peer means a loop. Recursion stops here.
   75: --maxlevel <level>
   76:     Traverse peers up to this level (4 is a reasonable number).
   77: --strip <string>
   78:     Strip <string> from hostnames.
   79: 
   80: Examples:
   81:     $program myhosts.txt --strip .foo.com
   82:     $program --host some.host --peers --maxlevel 4
   83: EOF
   84:     exit 1;
   85: }
   86: 
   87: my $hostsfile = shift;
   88: my (@hosts, @known_hosts);
   89: my (%known_host_info, %known_host_peers);
   90: 
   91: sub read_hosts()
   92: {
   93:     local *HOSTS;
   94:     open (HOSTS, $hostsfile) ||
   95: 	die "$program: FATAL: unable to read $hostsfile: $!\n";
   96:     while (<HOSTS>) {
   97: 	next if /^\s*(#|$)/; # comment/empty
   98: 	chomp;
   99: 	push(@hosts, $_);
  100:     }
  101:     close(HOSTS);
  102: }
  103: 
  104: # translate IP to hostname if possible
  105: sub ip2name {
  106:     my($ip) = @_;
  107:     my($addr, $name, $aliases, $addrtype, $length, @addrs);
  108:     $addr = pack('C4', split(/\./, $ip));
  109:     ($name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr($addr, 2);
  110:     if ($name) {
  111:         # return lower case name
  112: 	return("\L$name");
  113:     } else {
  114: 	return($ip);
  115:     }
  116: }
  117: 
  118: # item_in_list($item, @list): returns 1 if $item is in @list, 0 if not
  119: sub item_in_list {
  120:     my($item, @list) = @_;
  121:     my($i);
  122:     foreach $i (@list) {
  123: 	return 1 if ($item eq $i);
  124:     }
  125:     return 0;
  126: }
  127: 
  128: sub scan_host($;$;$) {
  129:     my($host, $level, @trace) = @_;
  130:     my $stratum = 0;
  131:     my $offset = 0;
  132:     my $daemonversion = "";
  133:     my $system = "";
  134:     my $processor = "";
  135:     my @peers;
  136:     my $known_host = 0;
  137: 
  138:     if (&item_in_list($host, @known_hosts)) {
  139: 	$known_host = 1;
  140:     } else {
  141: 	# ntpdate part
  142: 	open(NTPDATE, "$ntpdate -bd $host 2>/dev/null |") ||
  143:     	die "Cannot open ntpdate pipe: $!\n";
  144: 	while (<NTPDATE>) {
  145: 	    /^stratum\s+(\d+).*$/ && do {
  146: 		$stratum = $1;
  147: 	    };
  148: 	    /^offset\s+([0-9.-]+)$/ && do {
  149: 		$offset = $1;
  150: 	    };
  151: 	}
  152: 	close(NTPDATE);
  153:     
  154: 	# got answers ? If so, go on.
  155: 	if ($stratum) {
  156: 	    # ntpq part
  157: 	    my $ntpqparams = "-c 'rv 0 processor,system,daemon_version'";
  158: 	    open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
  159: 		die "Cannot open ntpq pipe: $!\n";
  160: 	    while (<NTPQ>) {
  161: 		/daemon_version="(.*)"/ && do {
  162: 		    $daemonversion = $1;
  163: 		};
  164: 		/system="([^"]*)"/ && do {
  165: 		    $system = $1;
  166: 		};
  167: 		/processor="([^"]*)"/ && do {
  168: 		    $processor = $1;
  169: 		};
  170: 	    }
  171: 	    close(NTPQ);
  172: 	    
  173: 	    # Shorten daemon_version string.
  174: 	    $daemonversion =~ s/(;|Mon|Tue|Wed|Thu|Fri|Sat|Sun).*$//;
  175: 	    $daemonversion =~ s/version=//;
  176: 	    $daemonversion =~ s/(x|)ntpd //;
  177: 	    $daemonversion =~ s/(\(|\))//g;
  178: 	    $daemonversion =~ s/beta/b/;
  179: 	    $daemonversion =~ s/multicast/mc/;
  180: 	
  181: 	    # Shorten system string
  182: 	    $system =~ s/UNIX\///;
  183: 	    $system =~ s/RELEASE/r/;
  184: 	    $system =~ s/CURRENT/c/;
  185: 
  186: 	    # Shorten processor string
  187: 	    $processor =~ s/unknown//;
  188: 	}
  189:     
  190: 	# got answers ? If so, go on.
  191: 	if ($daemonversion) {
  192: 	    # ntpq again, find out the peers this time
  193: 	    if ($showpeers) {
  194: 		my $ntpqparams = "-pn";
  195: 		open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
  196: 		    die "Cannot open ntpq pipe: $!\n";
  197: 		while (<NTPQ>) {
  198: 		    /^No association ID's returned$/ && do {
  199: 			last;
  200: 		    };
  201: 		    /^     remote/ && do {
  202: 			next;
  203: 		    };
  204: 		    /^==/ && do {
  205: 			next;
  206: 		    };
  207: 		    /^( |x|\.|-|\+|#|\*|o)([^ ]+)/ && do {
  208: 			push(@peers, ip2name($2));
  209: 			next;
  210: 		    };
  211: 		    print "ERROR: $_";
  212: 		}
  213: 		close(NTPQ);
  214: 	    }
  215: 	}
  216:     
  217: 	# Add scanned host to known_hosts array
  218: 	push(@known_hosts, $host);
  219: 	if ($stratum) {
  220: 	    $known_host_info{$host} = sprintf("%2d %9.3f %-11s %-12s %s",
  221: 		$stratum, $offset, substr($daemonversion,0,11),
  222: 		substr($system,0,12), substr($processor,0,9));
  223: 	} else {
  224: 	    # Stratum level 0 is consider invalid
  225: 	    $known_host_info{$host} = sprintf(" ?");
  226: 	}
  227: 	$known_host_peers{$host} = [@peers];
  228:     }
  229: 
  230:     if ($stratum || $known_host) { # Valid or known host
  231: 	my $printhost = ' ' x $level . $host;
  232: 	# Shorten host string
  233: 	if ($strip) {
  234: 	    $printhost =~ s/$strip//;
  235: 	}
  236: 	# append number of peers in brackets if requested and valid
  237: 	if ($showpeers && ($known_host_info{$host} ne " ?")) {
  238: 	    $printhost .= " (" . @{$known_host_peers{$host}} . ")";
  239: 	}
  240: 	# Finally print complete host line
  241: 	printf("%-32s %s\n",
  242: 	    substr($printhost,0,32), $known_host_info{$host});
  243: 	if ($showpeers && (eval($maxlevel ? $level < $maxlevel : 1))) {
  244: 	    my $peer;
  245: 	    push(@trace, $host);
  246: 	    # Loop through peers
  247: 	    foreach $peer (@{$known_host_peers{$host}}) {
  248: 		if (&item_in_list($peer, @trace)) {
  249: 		    # we've detected a loop !
  250: 		    $printhost = ' ' x ($level + 1) . "= " . $peer;
  251: 		    # Shorten host string
  252: 		    if ($strip) {
  253: 			$printhost =~ s/$strip//;
  254: 		    }
  255: 		    printf("%-32s %s\n",
  256: 			substr($printhost,0,32));
  257: 		} else {
  258: 		    if (substr($peer,0,3) ne "127") {
  259: 			&scan_host($peer, $level + 1, @trace);
  260: 		    }
  261: 		}
  262: 	    }
  263: 	}
  264:     } else { # We did not get answers from this host
  265: 	my $printhost = ' ' x $level . $host;
  266: 	# Shorten host string
  267: 	if ($strip) {
  268: 	    $printhost =~ s/$strip//;
  269: 	}
  270: 	printf("%-32s  ?\n", substr($printhost,0,32));
  271:     }
  272: }
  273: 
  274: sub scan_hosts()
  275: {
  276:     my $host;
  277:     for $host (@hosts) {
  278: 	my @trace;
  279: 	push(@trace, $host);
  280: 	scan_host($host, 0, @trace);
  281:     }
  282: }
  283: 
  284: # Main program
  285: 
  286: if ($single_host) {
  287:     push(@hosts, $single_host);
  288: } else {
  289:     &read_hosts($hostsfile);
  290: }
  291: 
  292: # Print header
  293: print <<EOF;
  294: Host                             st offset(s) version     system       processor
  295: --------------------------------+--+---------+-----------+------------+---------
  296: EOF
  297: 
  298: &scan_hosts();
  299: 
  300: exit 0;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>