#! @PATH_PERL@ -w
-# Copyright (C) 2015 Network Time Foundation
+# Copyright (C) 2015, 2017 Network Time Foundation
# Author: Harlan Stenn
-
+#
+# General cleanup and https support: Paul McMath
+#
# Original shell version:
# Copyright (C) 2014 Timothe Litt litt at acm dot org
-
+#
# This script may be freely copied, used and modified providing that
# this notice and the copyright statement are included in all copies
# and derivative works. No warranty is offered, and use is entirely at
# your own risk. Bugfixes and improvements would be appreciated by the
# author.
+######## BEGIN #########
use strict;
+# Core modules
use Digest::SHA qw(sha1_hex);
+use File::Basename;
use File::Copy qw(move);
-use File::Fetch;
+use File::Temp qw(tempfile);
use Getopt::Long qw(:config auto_help no_ignore_case bundling);
-use Sys::Syslog;
+use Sys::Syslog qw(:standard :macros);
-my $VERSION="1.003";
+# External modules
+use HTTP::Tiny 0.056;
+use Net::SSLeay 1.49;
+use IO::Socket::SSL 1.56;
-# leap-seconds file manager/updater
+my $VERSION = '1.004';
-# ########## Default configuration ##########
-#
+my $RUN_DIR = '/tmp';
+my $RUN_UID = 0;
+my $TMP_FILE;
+my $TMP_FH;
+my $FILE_MODE = 0644;
+
+######## DEFAULT CONFIGURATION ##########
+# LEAP FILE SRC URIS
+# HTTPS - (default)
+# https://www.ietf.org/timezones/data/leap-seconds
+# HTTP - No TLS/SSL - (not recommended)
+# http://www.ietf.org/timezones/data/leap-seconds.list
-my $CRONJOB = $ENV{'CRONJOB'};
-$CRONJOB = "" unless defined($CRONJOB);
-my $LOGGER;
-my $QUIET = "";
-my $VERBOSE = "";
-
-# Where to get the file
-# Choices:
-# https://www.ietf.org/timezones/data/leap-seconds.list
-# ftp://time.nist.gov/pub/leap-seconds.list
-my $LEAPSRC="https://www.ietf.org/timezones/data/leap-seconds.list";
+my $LEAPSRC = 'https://www.ietf.org/timezones/data/leap-seconds.list';
my $LEAPFILE;
# How many times to try to download new file
-my $MAXTRIES=6;
-my $INTERVAL=10;
+my $MAXTRIES = 6;
+my $INTERVAL = 10;
-# Where to find ntp config file
-my $NTPCONF="/etc/ntp.conf";
+my $NTPCONF='/etc/ntp.conf';
# How long (in days) before expiration to get updated file
-my $PREFETCH="60";
+my $PREFETCH = 60;
+my $EXPIRES;
+my $FORCE;
+
+# Output Flags
+my $QUIET;
+my $DEBUG;
+my $SYSLOG;
+my $TOTERM;
+my $LOGFAC = 'LOG_USER';
+
+######### PARSE/SET OPTIONS #########
+my %SSL_OPTS;
+my %SSL_ATTRS = (
+ verify_SSL => 1,
+ SSL_options => \%SSL_OPTS,
+);
-# How to restart NTP - older NTP: service ntpd? try-restart | condrestart
-# Recent NTP checks for new file daily, so there's nothing to do
-my $RESTART="";
+our(%opt);
-my $EXPIRES;
-my $FORCE = "";
+GetOptions(\%opt,
+ 'C=s',
+ 'D=s',
+ 'e:60',
+ 'F',
+ 'f=s',
+ 'h',
+ 'i:10',
+ 'L=s',
+ 'l=s',
+ 'q',
+ 'r:6',
+ 's',
+ 't',
+ 'u=s',
+ 'v',
+ );
-# Where to put temporary copy before it's validated
-my $TMPFILE="/tmp/leap-seconds.$$.tmp";
+$LOGFAC = $opt{l} if defined $opt{l};
+$LEAPSRC = $opt{u} if defined $opt{u};
+$LEAPFILE = $opt{L} if defined $opt{L};
+$PREFETCH = $opt{e} if defined $opt{e};
+$NTPCONF = $opt{f} if defined $opt{f};
+$MAXTRIES = $opt{r} if defined $opt{r};
+$INTERVAL = $opt{i} if defined $opt{i};
+
+$FORCE = 1 if defined $opt{F};
+$DEBUG = 1 if defined $opt{v};
+$QUIET = 1 if defined $opt{q};
+$SYSLOG = 1 if defined $opt{s};
+$TOTERM = 1 if defined $opt{t};
+
+$SSL_OPTS{SSL_ca_file} = $opt{C} if (defined($opt{C}));
+$SSL_OPTS{SSL_ca_path} = $opt{D} if (defined($opt{D}));
+
+###############
+## START MAIN
+###############
+my $PROG = basename($0);
+
+# Logging - Default is to use syslog(3) if STDOUT isn't
+# connected to a tty.
+if ($SYSLOG || !-t STDOUT) {
+ $SYSLOG = 1;
+ openlog($PROG, 'pid', $LOGFAC);
+}
+else {
+ $TOTERM = 1;
+}
-# Syslog facility
-my $LOGFAC="daemon";
+$SIG{INT} = \&signal_catcher;
+$SIG{TERM} = \&signal_catcher;
+$SIG{QUIT} = \&signal_catcher;
-# ###########################################
+# Take some security precautions
+close STDIN;
-=item update-leap
+if ($< != $RUN_UID) {
+ log_fatal(LOG_ERR, 'User ' . getpwuid($<) . " (UID $<) tried to run $PROG");
+}
-Usage: $0 [options] [leapfile]
+chdir $RUN_DIR || log_fatal("Failed to change dir to $RUN_DIR");
-Verifies and if necessary, updates leap-second definition file
+# Show help
+if (defined $opt{h}) {
+ show_help();
+ exit 0;
+}
-All arguments are optional: Default (or current value) shown:
- -s Specify the URL of the master copy to download
- $LEAPSRC
- -d Specify the filename on the local system
- $LEAPFILE
- -e Specify how long (in days) before expiration the file is to be
- refreshed. Note that larger values imply more frequent refreshes.
- "$PREFETCH"
- -f Specify location of ntp.conf (used to make sure leapfile directive is
- present and to default leapfile)
- $NTPCONF
- -F Force update even if current file is OK and not close to expiring.
- -r Specify number of times to retry on get failure
- $MAXTRIES
- -i Specify number of minutes between retries
- $INTERVAL
- -l Use syslog for output (Implied if CRONJOB is set)
- -L Don't use syslog for output
- -P Specify the syslog facility for logging
- $LOGFAC
- -t Name of temporary file used in validation
- $TMPFILE
- -q Only report errors to stdout
- -v Verbose output
+if ($QUIET && $DEBUG) {
+ log_fatal(LOG_ERR, '-q and -d options mutually exclusive');
+}
-The following options are not (yet) implemented in the perl version:
- -4 Use only IPv4
- -6 Use only IPv6
- -c Command to restart NTP after installing a new file
- <none> - ntpd checks file daily
- -p 4|6
- Prefer IPv4 or IPv6 (as specified) addresses, but use either
- -z Specify path for utilities
- $PATHLIST
- -Z Only use system path
+if ($LEAPFILE && $NTPCONF) {
+ log_fatal(LOG_ERR, '-L and -f options mutually exclusive');
+}
-$0 will validate the file currently on the local system
+# Parse ntp.conf for path to leapfile if not set by user
+if (! $LEAPFILE) {
-Ordinarily, the file is found using the "leapfile" directive in $NTPCONF.
-However, an alternate location can be specified on the command line.
+ open my $LF, '<', $NTPCONF || log_fatal(LOG_ERR, "Can't open <$NTPCONF>: $!");
-If the file does not exist, is not valid, has expired, or is expiring soon,
-a new copy will be downloaded. If the new copy validates, it is installed and
-NTP is (optionally) restarted.
+ while (<$LF>) {
+ chomp;
+ $LEAPFILE = $1 if /^ *leapfile\s+"(\S+)"/;
+ }
+ close $LF;
-If the current file is acceptable, no download or restart occurs.
+ if (! $LEAPFILE) {
+ log_fatal(LOG_ERR, "No leapfile directive in $NTPCONF; leapfile location not known");
+ }
+}
--c can also be used to invoke another script to perform administrative
-functions, e.g. to copy the file to other local systems.
+-s $LEAPFILE || logger(LOG_DEBUG, "Leapfile $LEAPFILE is empty");
-This can be run as a cron job. As the file is rarely updated, and leap
-seconds are announced at least one month in advance (usually longer), it
-need not be run more frequently than about once every three weeks.
+# Download new file if:
+# 1. file doesn't exist
+# 2. invoked w/ force flag (-F)
+# 3. current file isn't valid
+# 4. current file expired or expires soon
-For cron-friendly behavior, define CRONJOB=1 in the crontab.
+if ( !-e $LEAPFILE || $FORCE || ! verifySHA($LEAPFILE) ||
+ ( $EXPIRES lt ( $PREFETCH * 86400 + time() ) )) {
-Version $VERSION
-=cut
+ for (my $try = 1; $try <= $MAXTRIES; $try++) {
+ logger(LOG_DEBUG, "Attempting download from $LEAPSRC, try $try..");
-# Default: Use syslog for logging if running under cron
+ ($TMP_FH, $TMP_FILE) = tempfile(UNLINK => 1, SUFFIX => '.list');
-my $SYSLOG = $CRONJOB;
+ if (retrieve_file($TMP_FH)) {
-# Parse options
+ if ( verifySHA($TMP_FILE) ) {
+ move_file($TMP_FILE, $LEAPFILE);
+ chmod $FILE_MODE, $LEAPFILE;
+ logger(LOG_INFO, "Installed new $LEAPFILE from $LEAPSRC");
+ }
+ else {
+ logger(LOG_ERR, "Downloaded file $TMP_FILE rejected -- saved for diagnosis");
+ move_file($TMP_FILE, 'leap-seconds.list_corrupt');
+ exit 1;
+ }
+ # Fall through
+ exit 0;
+ }
-our(%opt);
+ # Failure
+ logger(LOG_INFO, "Download failed. Waiting $INTERVAL minutes before retrying...");
+ sleep $INTERVAL * 60 ;
+ }
-GetOptions(\%opt,
- 'c=s',
- 'e:60',
- 'F',
- 'f=s',
- 'i:10',
- 'L',
- 'l',
- 'P=s',
- 'q',
- 'r:6',
- 's=s',
- 't=s',
- 'v'
- );
+ # Failed and out of retries
+ log_fatal(LOG_ERR, "Download from $LEAPSRC failed after $MAXTRIES attempts");
+}
+
+logger(LOG_INFO, "Not time to replace $LEAPFILE");
+
+exit 0;
-$LOGFAC=$opt{P} if (defined($opt{P}));
-$LEAPSRC=$opt{s} if (defined($opt{s}));
-$PREFETCH=$opt{e} if (defined($opt{e}));
-$NTPCONF=$opt{f} if (defined($opt{f}));
-$FORCE="Y" if (defined($opt{F}));
-$RESTART=$opt{c} if (defined($opt{c}));
-$MAXTRIES=$opt{r} if (defined($opt{r}));
-$INTERVAL=$opt{i} if (defined($opt{i}));
-$TMPFILE=$opt{t} if (defined($opt{t}));
-$SYSLOG="Y" if (defined($opt{l}));
-$SYSLOG="" if (defined($opt{L}));
-$QUIET="Y" if (defined($opt{q}));
-$VERBOSE="Y" if (defined($opt{v}));
+######## SUB ROUTINES #########
+sub move_file {
-# export PATH="$PATHLIST$PATH"
+ (my $src, my $dst) = @_;
-# Handle logging
+ if ( move($src, $dst) ) {
+ logger(LOG_DEBUG, "Moved $src to $dst");
+ }
+ else {
+ log_fatal(LOG_ERR, "Moving $src to $dst failed: $!");
+ }
+}
-openlog($0, 'pid', $LOGFAC);
+# Removes temp file if terminating signal recv'd
+sub signal_catcher {
+ my $signame = shift;
+
+ close $TMP_FH;
+ unlink $TMP_FILE;
+ log_fatal(LOG_INFO, "Recv'd SIG${signame}. Terminating.");
+}
+
+sub log_fatal {
+ my ($p, $msg) = @_;
+ logger($p, $msg);
+ exit 1;
+}
sub logger {
- my ($priority, $message) = @_;
-
- # "priority" "message"
- #
- # Stdout unless syslog specified or logger isn't available
- #
- if ($SYSLOG eq "" or $LOGGER eq "") {
- if ($QUIET ne "" and ( $priority eq "info" or $priority eq "notice" or $priority eq "debug" ) ) {
- return 0
+ my ($p, $msg) = @_;
+
+ # Suppress LOG_DEBUG msgs unless $DEBUG set
+ return if (!$DEBUG && $p eq LOG_DEBUG);
+
+ # Suppress all but LOG_ERR msgs if $QUIET set
+ return if ($QUIET && $p ne LOG_ERR);
+
+ if ($TOTERM) {
+ if ($p eq LOG_ERR) { # errors should go to STDERR
+ print STDERR "$msg\n";
+ }
+ else {
+ print STDOUT "$msg\n";
}
- printf "%s: $message\n", uc $priority;
- return 0;
}
- # Also log to stdout if cron job && notice or higher
- if (($CRONJOB ne "" and ($priority ne "info" ) and ($priority ne "debug" )) || ($VERBOSE ne "")) {
- # Log to stderr as well
- print STDERR "$0: $priority: $message\n";
+ if ($SYSLOG) {
+ syslog($p, $msg)
}
- syslog($priority, $message);
}
-# Verify interval
-# INTERVAL=$(( $INTERVAL *1 ))
+#################################
+# Connect to server and retrieve file
+#
+# Since we make as many as $MAXTRIES attempts to connect to the remote
+# server to download the file, the network socket should be closed after
+# each attempt, rather than let it be reused (because it may be in some
+# unknown state).
+#
+# HTTP::Tiny doesn't export a method to explicitly close a connected
+# socket, therefore, we instantiate the lexically scoped object in a
+# function; when the function returns, the http object goes out of
+# scope and is destroyed, closing the socket.
+sub retrieve_file {
+
+ my $fh = shift;
+ my $http;
+
+ if ($LEAPSRC =~ /^https\S+/) {
+ $http = HTTP::Tiny->new(%SSL_ATTRS);
+ (my $ok, my $why) = $http->can_ssl;
+ log_fatal(LOG_ERR, "TLS/SSL config error: $why") if ! $ok;
+ }
+ else {
+ $http = HTTP::Tiny->new();
+ }
+
+ my $reply = $http->get($LEAPSRC);
+
+ if ($reply->{success}) {
+ logger(LOG_DEBUG, "Download of $LEAPSRC succeeded");
+ print $fh $reply->{content} ||
+ log_fatal(LOG_ERR, "Couldn't write new file contents to temp file: $!");
+ close $fh;
+ return 1;
+ }
+ else {
+ close $fh;
+ return 0;
+ }
+}
+########################
# Validate a leap-seconds file checksum
#
-# File format: (full description in files)
-# # marks comments, except:
-# #$ number : the NTP date of the last update
-# #@ number : the NTP date that the file expires
-# Date (seconds since 1900) leaps : leaps is the # of seconds to add for times >= Date
+# File format: (full description in file)
+# Pound sign (#) marks comments, EXCEPT:
+# #$ number : the NTP date of the last update
+# #@ number : the NTP date that the file expires
+# #h hex hex hex hex hex : the SHA-1 checksum of the data & dates,
+# excluding whitespace w/o leading zeroes
+#
+# Date (seconds since 1900) leaps : leaps is the # of seconds to add
+# for times >= Date
# Date lines have comments.
-# #h hex hex hex hex hex is the SHA-1 checksum of the data & dates, excluding whitespace w/o leading zeroes
#
# Returns:
-# 0 File is valid
-# 1 Invalid Checksum
-# 2 Expired
+# 0 Invalid Checksum/Expired
+# 1 File is valid
sub verifySHA {
- my ($file, $verbose) = @_;
- my $raw = "";
- my $data = "";
+ my $file = shift;
+ my $fh;
+ my $data;
my $FSHA;
+ open $fh, '<', $file || log_fatal(LOG_ERR, "Can't open $file: $!");
+
# Remove comments, except those that are markers for last update,
# expires and hash
-
- unless (open(LF, $file)) {
- warn "Can't open <$file>: $!\n";
- print "Will try and create that file.\n";
- return 1;
- };
- while (<LF>) {
+ while (<$fh>) {
if (/^#\$/) {
- $raw .= $_;
- s/^..//;
- $data .= $_;
+ s/^..//;
+ $data .= $_;
}
elsif (/^#\@/) {
- $raw .= $_;
- s/^..//;
- $data .= $_;
- s/\s+//g;
- $EXPIRES = $_ - 2208988800;
+ s/^..//;
+ $data .= $_;
+ s/\s+//g;
+ $EXPIRES = $_ - 2208988800;
}
elsif (/^#h\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/) {
- chomp;
- $raw .= $_;
- $FSHA = sprintf("%08s%08s%08s%08s%08s", $1, $2, $3, $4, $5);
+ chomp;
+ $FSHA = sprintf("%08s%08s%08s%08s%08s", $1, $2, $3, $4, $5);
}
elsif (/^#/) {
- # ignore it
+ # ignore it
}
elsif (/^\d/) {
- s/#.*$//;
- $raw .= $_;
- $data .= $_;
- } else {
- chomp;
- print "Unexpected line: <$_>\n";
+ s/#.*$//;
+ $data .= $_;
+ }
+ else {
+ chomp;
+ print "Unexpected line: <$_>\n";
}
}
- close LF;
+ close $fh;
+
+ if ( $EXPIRES < time() ) {
+ logger(LOG_DEBUG, 'File expired on ' . gmtime($EXPIRES));
+ return 0;
+ }
+
+ if (! $FSHA) {
+ logger(LOG_NOTICE, "no checksum record found in file");
+ return 0;
+ }
# Remove all white space
$data =~ s/\s//g;
# Compute the SHA hash of the data, removing the marker and filename
# Computed in binary mode, which shouldn't matter since whitespace has been removed
-
my $DSHA = sha1_hex($data);
- # Extract the file's hash. Restore any leading zeroes in hash segments.
-
- if ( ( "$FSHA" ne "" ) && ( $FSHA eq $DSHA ) ) {
- if ( $verbose ne "" ) {
- logger("info", "Checksum of $file validated");
- }
- } else {
- logger("error", "Checksum of $file is invalid:");
- $FSHA="(no checksum record found in file)"
- if ( $FSHA eq "");
- logger("error", "EXPECTED: $FSHA");
- logger("error", "COMPUTED: $DSHA");
- return 1;
- }
-
- # Check the expiration date, converting NTP epoch to Unix epoch used by date
-
- if ( $EXPIRES < time() ) {
- logger("notice", "File expired on " . gmtime($EXPIRES));
- return 2;
+ if ($FSHA eq $DSHA) {
+ logger(LOG_DEBUG, "Checksum of $file validated");
+ return 1;
+ }
+ else {
+ logger(LOG_NOTICE, "Checksum of $file is invalid EXPECTED: $FSHA COMPUTED: $DSHA");
+ return 0;
}
- return 0;
}
-# Verify ntp.conf
+sub show_help {
+print <<EOF
--r $NTPCONF || die "Missing ntp configuration: $NTPCONF\n";
+Usage: $PROG [options]
-# Parse ntp.conf for leapfile directive
-
-open(LF, $NTPCONF) || die "Can't open <$NTPCONF>: $!\n";
-while (<LF>) {
- chomp;
- if (/^ *leapfile\s+"(\S+)"/) {
- $LEAPFILE = $1;
- }
-}
-close LF;
+Verifies and if necessary, updates leap-second definition file
--s $LEAPFILE || warn "$NTPCONF specifies $LEAPFILE as a leapfile, which is empty.\n";
+All arguments are optional: Default (or current value) shown:
+ -C Absolute path to CA Cert (see SSL/TLS Considerations)
+ -D Path to a CAdir (see SSL/TLS Considerations)
+ -e Specify how long (in days) before expiration the file is to be
+ refreshed. Note that larger values imply more frequent refreshes.
+ $PREFETCH
+ -F Force update even if current file is OK and not close to expiring.
+ -f Absolute path ntp.conf file (default /etc/ntp.conf)
+ $NTPCONF
+ -h show help
+ -i Specify number of minutes between retries
+ $INTERVAL
+ -L Absolute path to leapfile on the local system
+ (overrides value in ntp.conf)
+ -l Specify the syslog(3) facility for logging
+ $LOGFAC
+ -q Only report errors (cannot be used with -v)
+ -r Specify number of attempts to retrieve file
+ $MAXTRIES
+ -s Send output to syslog(3) - implied if STDOUT has no tty or redirected
+ -t Send output to terminal - implied if STDOUT attached to terminal
+ -u Specify the URL of the master copy to download
+ $LEAPSRC
+ -v Verbose - show debug messages (cannot be used with -q)
-# Allow placing the file someplace else - testing
+The following options are not (yet) implemented in the perl version:
+ -4 Use only IPv4
+ -6 Use only IPv6
+ -c Command to restart NTP after installing a new file
+ <none> - ntpd checks file daily
+ -p 4|6
+ Prefer IPv4 or IPv6 (as specified) addresses, but use either
-if ( defined $ARGV[0] ) {
- if ( $ARGV[0] ne $LEAPFILE ) {
- logger("notice", "Requested install to $ARGV[0], but $NTPCONF specifies $LEAPFILE");
- }
- $LEAPFILE = $ARGV[0];
-}
+$PROG will validate the file currently on the local system.
-# Verify the current file
-# If it is missing, doesn't validate or expired
-# Or is expiring soon
-# Download a new one
-
-if ( $FORCE ne "" || verifySHA($LEAPFILE, $VERBOSE) || ( $EXPIRES lt ( $PREFETCH * 86400 + time() ) )) {
- my $TRY = 0;
- my $ff = File::Fetch->new(uri => $LEAPSRC) || die "Fetch failed.\n";
- while (1) {
- ++$TRY;
- logger("info", "Attempting download from $LEAPSRC, try $TRY..")
- if ($VERBOSE ne "");
- my $where = $ff->fetch( to => '/tmp' );
-
- if ($where) {
- logger("info", "Download of $LEAPSRC succeeded");
-
- if ( verifySHA($where, $VERBOSE )) {
- # There is no point in retrying, as the file on the
- # server is almost certainly corrupt.
-
- logger("warning", "Downloaded file $where rejected -- saved for diagnosis");
- exit 1;
- }
+Ordinarily, the leapfile is found using the 'leapfile' directive in
+$NTPCONF. However, an alternate location can be specified on the
+command line with the -L flag.
- # While the shell script version will set correct permissions
- # on temporary file, for the perl version that's harder, so
- # for now at least one should run this script as the
- # appropriate user.
-
- # REFFILE="$LEAPFILE"
- # if [ ! -f $LEAPFILE ]; then
- # logger "notice" "$LEAPFILE was missing, creating new copy - check permissions"
- # touch $LEAPFILE
- # # Can't copy permissions from old file, copy from NTPCONF instead
- # REFFILE="$NTPCONF"
- # fi
- # chmod --reference $REFFILE $TMPFILE
- # chown --reference $REFFILE $TMPFILE
- # ( which selinuxenabled && selinuxenabled && which chcon ) >/dev/null 2>&1
- # if [ $? == 0 ] ; then
- # chcon --reference $REFFILE $TMPFILE
- # fi
-
- # Replace current file with validated new one
-
- if ( move $where, $LEAPFILE ) {
- logger("notice", "Installed new $LEAPFILE from $LEAPSRC");
- } else {
- logger("error", "Install $where => $LEAPFILE failed -- saved for diagnosis: $!");
- exit 1;
- }
+If the leapfile does not exist, is not valid, has expired, or is
+expiring soon, a new copy will be downloaded. If the new copy is
+valid, it is installed.
- # Restart NTP (or whatever else is specified)
-
- if ( $RESTART ne "" ) {
- if ( $VERBOSE ne "" ) {
- logger("info", "Attempting restart action: $RESTART");
- }
-
-# XXX
- #R="$( 2>&1 $RESTART )"
- #if [ $? -eq 0 ]; then
- # logger "notice" "Restart action succeeded"
- # if [ -n "$VERBOSE" -a -n "$R" ]; then
- # logger "info" "$R"
- # fi
- #else
- # logger "error" "Restart action failed"
- # if [ -n "$R" ]; then
- # logger "error" "$R"
- # fi
- # exit 2
- #fi
- }
- exit 0;
- }
+If the current file is acceptable, no download or restart occurs.
- # Failed to download. See about trying again
+This can be run as a cron job. As the file is rarely updated, and
+leap seconds are announced at least one month in advance (usually
+longer), it need not be run more frequently than about once every
+three weeks.
- # rm -f $TMPFILE
- if ( $TRY ge $MAXTRIES ) {
- last;
- }
- if ( $VERBOSE ne "" ) {
- logger("info", "Waiting $INTERVAL minutes before retrying...");
- }
- sleep $INTERVAL * 60 ;
- }
+SSL/TLS Considerations
+-----------------------
+The perl modules can usually locate the CA certificate used to verify
+the peer's identity.
- # Failed and out of retries
+On BSDs, the default is typically the file /etc/ssl/certs.pem. On
+Linux, the location is typically a path to a CAdir - a directory of
+symlinks named according to a hash of the certificates' subject names.
- logger("warning", "Download from $LEAPSRC failed after $TRY attempts");
- exit 1;
-}
+The -C or -D options are available to pass in a location if no CA cert
+is found in the default location.
-print "FORCE is <$FORCE>\n";
-print "verifySHA is " . verifySHA($LEAPFILE, "") . "\n";
-print "EXPIRES <$EXPIRES> vs ". ( $PREFETCH * 86400 + time() ) . "\n";
+External Dependencies
+---------------------
+The following perl modules are required:
+HTTP::Tiny - version >= 0.056
+IO::Socket::SSL - version >= 1.56
+NET::SSLeay - version >= 1.49
-logger("info", "Not time to replace $LEAPFILE");
+Version: $VERSION
-exit 0;
+EOF
+}
-# EOF