Use the "modulino" pattern to facilitate unit tests
Now the `ddclient` file can be used as a script or as a module. For details, see: https://www.drdobbs.com/scripts-as-modules/184416165 Addresses #147
This commit is contained in:
parent
8cbcecba99
commit
f6f920eb39
1 changed files with 101 additions and 88 deletions
|
@ -18,6 +18,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
package ddclient;
|
||||||
require v5.10.1;
|
require v5.10.1;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
@ -25,7 +26,8 @@ use Getopt::Long;
|
||||||
use Sys::Hostname;
|
use Sys::Hostname;
|
||||||
use IO::Socket;
|
use IO::Socket;
|
||||||
|
|
||||||
my $version = "3.9.1";
|
use version 0.77; our $VERSION = version->declare('v3.9.1');
|
||||||
|
(my $version = $VERSION->stringify()) =~ s/^v//;
|
||||||
my $programd = $0;
|
my $programd = $0;
|
||||||
$programd =~ s%^.*/%%;
|
$programd =~ s%^.*/%%;
|
||||||
my $program = $programd;
|
my $program = $programd;
|
||||||
|
@ -64,6 +66,11 @@ local $lineno = '';
|
||||||
|
|
||||||
$ENV{'PATH'} = (exists($ENV{PATH}) ? "$ENV{PATH}:" : "") . "/sbin:/usr/sbin:/bin:/usr/bin:/etc:/usr/lib:";
|
$ENV{'PATH'} = (exists($ENV{PATH}) ? "$ENV{PATH}:" : "") . "/sbin:/usr/sbin:/bin:/usr/bin:/etc:/usr/lib:";
|
||||||
|
|
||||||
|
my ($result, %config, %globals, %cache);
|
||||||
|
my $saved_cache;
|
||||||
|
my %saved_opt;
|
||||||
|
my $daemon;
|
||||||
|
|
||||||
sub T_ANY { 'any' }
|
sub T_ANY { 'any' }
|
||||||
sub T_STRING { 'string' }
|
sub T_STRING { 'string' }
|
||||||
sub T_EMAIL { 'e-mail address' }
|
sub T_EMAIL { 'e-mail address' }
|
||||||
|
@ -829,105 +836,105 @@ my @opt = (
|
||||||
" project now maintained on https://github.com/ddclient/ddclient"
|
" project now maintained on https://github.com/ddclient/ddclient"
|
||||||
);
|
);
|
||||||
|
|
||||||
## process args
|
sub main {
|
||||||
my $opt_usage = process_args(@opt);
|
## process args
|
||||||
my ($result, %config, %globals, %cache);
|
my $opt_usage = process_args(@opt);
|
||||||
my $saved_cache = '';
|
$saved_cache = '';
|
||||||
my %saved_opt = %opt;
|
%saved_opt = %opt;
|
||||||
$result = 'OK';
|
$result = 'OK';
|
||||||
|
|
||||||
test_geturl(opt('geturl')) if opt('geturl');
|
test_geturl(opt('geturl')) if opt('geturl');
|
||||||
|
|
||||||
if (opt('help')) {
|
if (opt('help')) {
|
||||||
printf "%s\n", $opt_usage;
|
printf "%s\n", $opt_usage;
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
## read config file because 'daemon' mode may be defined there.
|
|
||||||
read_config($opt{'file'} // default('file'), \%config, \%globals);
|
|
||||||
init_config();
|
|
||||||
test_possible_ip() if opt('query');
|
|
||||||
|
|
||||||
my $caught_hup = 0;
|
|
||||||
my $caught_term = 0;
|
|
||||||
my $caught_int = 0;
|
|
||||||
$SIG{'HUP'} = sub { $caught_hup = 1; };
|
|
||||||
$SIG{'TERM'} = sub { $caught_term = 1; };
|
|
||||||
$SIG{'INT'} = sub { $caught_int = 1; };
|
|
||||||
# don't fork() if foreground
|
|
||||||
if (opt('foreground')) {
|
|
||||||
;
|
|
||||||
} elsif (opt('daemon')) {
|
|
||||||
$SIG{'CHLD'} = 'IGNORE';
|
|
||||||
my $pid = fork;
|
|
||||||
if ($pid < 0) {
|
|
||||||
print STDERR "${program}: can not fork ($!)\n";
|
|
||||||
exit -1;
|
|
||||||
} elsif ($pid) {
|
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
$SIG{'CHLD'} = 'DEFAULT';
|
|
||||||
open(STDOUT, ">/dev/null");
|
|
||||||
open(STDERR, ">/dev/null");
|
|
||||||
open(STDIN, "</dev/null");
|
|
||||||
write_pid();
|
|
||||||
}
|
|
||||||
|
|
||||||
umask 077;
|
|
||||||
my $daemon;
|
|
||||||
do {
|
|
||||||
$now = time;
|
|
||||||
$result = 'OK';
|
|
||||||
%opt = %saved_opt;
|
|
||||||
if (opt('help')) {
|
|
||||||
*STDERR = *STDOUT;
|
|
||||||
printf("Help found");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
## read config file because 'daemon' mode may be defined there.
|
||||||
read_config($opt{'file'} // default('file'), \%config, \%globals);
|
read_config($opt{'file'} // default('file'), \%config, \%globals);
|
||||||
init_config();
|
init_config();
|
||||||
read_cache(opt('cache'), \%cache);
|
test_possible_ip() if opt('query');
|
||||||
print_info() if opt('debug') && opt('verbose');
|
|
||||||
|
|
||||||
fatal("invalid argument '-use %s'; possible values are:\n%s", $opt{'use'}, join("\n", ip_strategies_usage()))
|
my $caught_hup = 0;
|
||||||
unless exists $ip_strategies{lc opt('use')};
|
my $caught_term = 0;
|
||||||
|
my $caught_int = 0;
|
||||||
$daemon = opt('daemon');
|
$SIG{'HUP'} = sub { $caught_hup = 1; };
|
||||||
|
$SIG{'TERM'} = sub { $caught_term = 1; };
|
||||||
update_nics();
|
$SIG{'INT'} = sub { $caught_int = 1; };
|
||||||
|
# don't fork() if foreground
|
||||||
if ($daemon) {
|
if (opt('foreground')) {
|
||||||
debug("sleep %s", $daemon);
|
;
|
||||||
sendmail();
|
} elsif (opt('daemon')) {
|
||||||
|
$SIG{'CHLD'} = 'IGNORE';
|
||||||
my $left = $daemon;
|
my $pid = fork;
|
||||||
while (($left > 0) && !$caught_hup && !$caught_term && !$caught_int) {
|
if ($pid < 0) {
|
||||||
my $delay = $left > 10 ? 10 : $left;
|
print STDERR "${program}: can not fork ($!)\n";
|
||||||
|
exit -1;
|
||||||
$0 = sprintf("%s - sleeping for %s seconds", $program, $left);
|
} elsif ($pid) {
|
||||||
$left -= sleep $delay;
|
exit 0;
|
||||||
# preventing deep sleep - see [bugs:#46]
|
|
||||||
if ($left > $daemon) {
|
|
||||||
$left = $daemon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$caught_hup = 0;
|
$SIG{'CHLD'} = 'DEFAULT';
|
||||||
$result = 0;
|
open(STDOUT, ">/dev/null");
|
||||||
|
open(STDERR, ">/dev/null");
|
||||||
} elsif (!scalar(%config)) {
|
open(STDIN, "</dev/null");
|
||||||
warning("no hosts to update.") unless !opt('quiet') || opt('verbose') || !$daemon;
|
write_pid();
|
||||||
$result = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$result = $result eq 'OK' ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
} while ($daemon && !$result && !$caught_term && !$caught_int);
|
|
||||||
|
|
||||||
warning("caught SIGINT; exiting") if $caught_int;
|
umask 077;
|
||||||
unlink_pid();
|
do {
|
||||||
sendmail();
|
$now = time;
|
||||||
|
$result = 'OK';
|
||||||
|
%opt = %saved_opt;
|
||||||
|
if (opt('help')) {
|
||||||
|
*STDERR = *STDOUT;
|
||||||
|
printf("Help found");
|
||||||
|
}
|
||||||
|
|
||||||
exit($result);
|
read_config($opt{'file'} // default('file'), \%config, \%globals);
|
||||||
|
init_config();
|
||||||
|
read_cache(opt('cache'), \%cache);
|
||||||
|
print_info() if opt('debug') && opt('verbose');
|
||||||
|
|
||||||
|
fatal("invalid argument '-use %s'; possible values are:\n%s", $opt{'use'}, join("\n", ip_strategies_usage()))
|
||||||
|
unless exists $ip_strategies{lc opt('use')};
|
||||||
|
|
||||||
|
$daemon = opt('daemon');
|
||||||
|
|
||||||
|
update_nics();
|
||||||
|
|
||||||
|
if ($daemon) {
|
||||||
|
debug("sleep %s", $daemon);
|
||||||
|
sendmail();
|
||||||
|
|
||||||
|
my $left = $daemon;
|
||||||
|
while (($left > 0) && !$caught_hup && !$caught_term && !$caught_int) {
|
||||||
|
my $delay = $left > 10 ? 10 : $left;
|
||||||
|
|
||||||
|
$0 = sprintf("%s - sleeping for %s seconds", $program, $left);
|
||||||
|
$left -= sleep $delay;
|
||||||
|
# preventing deep sleep - see [bugs:#46]
|
||||||
|
if ($left > $daemon) {
|
||||||
|
$left = $daemon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$caught_hup = 0;
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
} elsif (!scalar(%config)) {
|
||||||
|
warning("no hosts to update.") unless !opt('quiet') || opt('verbose') || !$daemon;
|
||||||
|
$result = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$result = $result eq 'OK' ? 0 : 1;
|
||||||
|
}
|
||||||
|
} while ($daemon && !$result && !$caught_term && !$caught_int);
|
||||||
|
|
||||||
|
warning("caught SIGINT; exiting") if $caught_int;
|
||||||
|
unlink_pid();
|
||||||
|
sendmail();
|
||||||
|
|
||||||
|
exit($result);
|
||||||
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
## runpostscript
|
## runpostscript
|
||||||
|
@ -5240,6 +5247,12 @@ sub nic_cloudns_update {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Execute main() if this file is run as a script or run via PAR (https://metacpan.org/pod/PAR),
|
||||||
|
# otherwise do nothing. This "modulino" pattern makes it possible to import this file as a module
|
||||||
|
# and test its functions directly; there's no need for test-only command-line arguments or stdout
|
||||||
|
# parsing.
|
||||||
|
__PACKAGE__->main() unless caller() && caller() ne 'PAR';
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# vim: ai et ts=4 sw=4 tw=78:
|
# vim: ai et ts=4 sw=4 tw=78:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue