Annotation of embedaddon/ntp/scripts/ntpsweep.in, revision 1.1

1.1     ! misho       1: #! @PATH_PERL@ -w
        !             2: #
        !             3: # $Id$
        !             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>