my $force_update = 0;
my $log_failed_filename = 'failed-summary.log';
my $log_summary_filename = 'run-summary.log';
-my $more = 'less -XF';
+my @more = qw'less -XF';
my $optargs = '';
my $save_output = 0;
my $server_opts = '';
$ENV{USER} = getpwuid($>) if not exists $ENV{USER};
my ($parm_configure_owner, $parm_configure_group);
-my ($parm_ipv4, $parm_ipv6);
+my ($parm_ipv4, $parm_ipv6, $parm_ipv6_stripped);
my $parm_hostname;
###############################################################################
# Replace the Exim version number (may appear in various places)
# patchexim should have fixed this for us
- #s/(Exim) \d+\.\d+[\w_-]*/$1 x.yz/i;
+ #s/Exim \K\d+[._]\d+[\w_-]*/x.yz/i;
# Replace Exim message ids by a unique series
s/((?:[^\W_]{6}-){2}[^\W_]{2})
# the older (comment) style, keeping only the Auth element
# (discarding kex, cipher, mac). For TLS 1.3 there is no kex
# element (and no _WITH); insert a spurious "RSA".
+ # Also in $tls_X_cipher_std reporting.
- s/^\s+by .+ with .+ \K tls TLS_.*?([^_]+)_WITH.+$/(TLS1.x:ke-$1-AES256-SHAnnn:xxx)/;
- s/^\s+by .+ with .+ \K tls TLS_.+$/(TLS1.x:ke-RSA-AES256-SHAnnn:xxx)/;
+ s/^\s+by \S+ with .+ \K \(TLS1(?:\.[0-3])?\) tls TLS_.*?([^_]+)_WITH.+$/(TLS1.x:ke-$1-AES256-SHAnnn:xxx)/;
+ s/^\s+by \S+ with .+ \K \(TLS1(?:\.[0-3])?\) tls TLS_.+$/(TLS1.x:ke-RSA-AES256-SHAnnn:xxx)/;
+
+ s/ cipher_ TLS_.*?([^_]+)_WITH.+$/ cipher_ TLS1.x:ke_$1_WITH_ci_mac/;
+ s/ cipher_ TLS_.*$/ cipher_ TLS1.x:ke_RSA_WITH_ci_mac/;
# Test machines might have various different TLS library versions supporting
# different protocols; can't rely upon TLS 1.2's AES256-GCM-SHA384, so we
# treat the standard algorithms the same.
#
- # TLSversion : KeyExchange? - Authentication/Signature - C_iph_er - MAC : ???
+ # TLSversion : KeyExchange? - Authentication/Signature - C_iph_er - MAC : bits
#
# So far, have seen:
# TLSv1:AES128-GCM-SHA256:128
#
# Retain the authentication algorith field as we want to test that.
- s/( (?: (?:\b|\s) [\(=] ) | \s )TLSv1(\.[123])?:/$1TLS1.x:/xg;
+ s/( (?: (?:\b|\s) [\(=] ) | \s )TLS1(\.[123])?:/$1TLS1.x:/xg;
s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA)(?!:)/ke-$3-AES256-SHAnnn/g;
s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA):(128|256)/ke-$3-AES256-SHAnnn:xxx/g;
# DHE-RSA-AES256-SHA
# picking latter as canonical simply because regex easier that way.
s/\bDHE_RSA_AES_128_CBC_SHA1:128/RSA-AES256-SHA1:256/g;
- s/TLS1.[0123](-PKIX)?: # TLS version
+ s/TLS1.[x0123](-PKIX)?: # TLS version
((EC)?DHE(_((?<psk>PSK)_)?((?<auth>RSA|ECDSA)_)?
(SECP(256|521)R1|X25519))?__?)? # key-exchange
((?<auth>RSA|ECDSA)((_PSS_RSAE)?_SHA(512|256))?__?)? # authentication
+ (?<with>WITH_)? # stdname-with
AES_(256|128)_(CBC|GCM) # cipher
(__?AEAD)? # pseudo-MAC
(__?SHA(1|256|384))? # PRF
/"TLS1.x:ke-"
. (defined($+{psk}) ? $+{psk} : "")
. (defined($+{auth}) ? $+{auth} : "")
+ . (defined($+{with}) ? $+{with} : "")
. "-AES256-SHAnnn:xxx"/gex;
s/TLS1.2:RSA__CAMELLIA_256_GCM(_SHA384)?:256/TLS1.2:RSA_CAMELLIA_256_GCM-SHAnnn:256/g;
s/\b(ECDHE-(RSA|ECDSA)-AES256-SHA|DHE-RSA-AES256-SHA256)\b/ke-$2-AES256-SHAnnn/g;
+ # Separate reporting of TLS version
+ s/ver: TLS1(\.[0-3])?$/ver: TLS1.x/;
+ s/ \(TLS1(\.[0-3])?\) / (TLS1.x) /;
+
# GnuTLS library error message changes
s/(No certificate was found|Certificate is required)/The peer did not send any certificate/g;
#(dodgy test?) s/\(certificate verification failed\): invalid/\(gnutls_handshake\): The peer did not send any certificate./g;
s/waiting for children of \d+/waiting for children of pppp/;
s/waiting for (\S+) \(\d+\)/waiting for $1 (pppp)/;
+ # Most builds are without HAVE_LOCAL_SCAN
+ next if /^calling local_scan\(\); timeout=300$/;
+ next if /^local_scan\(\) returned 0 NULL$/;
+
# ======== Port numbers ========
# Incoming port numbers may vary, but not in daemon startup line.
# Also, the length of space at the end of the host line is dependent
# on the length of the longest line, so strip it also on otherwise
# un-rewritten lines like localhost
+ #
+ # host 127.0.0.1 [127.0.0.1]
+ # host 10.0.0.1 [10.0.0.1]-
+ #
+ # host 127.0.0.1 [127.0.0.1]--
+ # host 169.16.16.16 [169.16.16.10]
s/^\s+host\s(\S+)\s+(\S+)/ host $1 $2/;
s/^\s+(host\s\S+\s\S+)\s+(port=.*)/ host $1 $2/;
s/host\s\Q$parm_ipv6\E\s\[\Q$parm_ipv6\E\]/host ip6:ip6:ip6:ip6:ip6:ip6:ip6:ip6 [ip6:ip6:ip6:ip6:ip6:ip6:ip6:ip6]/;
s/\b\Q$parm_ipv4\E\b/ip4.ip4.ip4.ip4/g;
s/(^|\W)\K\Q$parm_ipv6\E/ip6:ip6:ip6:ip6:ip6:ip6:ip6:ip6/g;
+ s/(^|\W)\K\Q$parm_ipv6_stripped\E/ip6:ip6:ip6:ip6:ip6:ip6:ip6:ip6/g;
s/\b\Q$parm_ipv4r\E\b/ip4-reverse/g;
s/(^|\W)\K\Q$parm_ipv6r\E/ip6-reverse/g;
- s/^(\s+host\s\S+\s+\[\S+\]) +$/$1 /;
+ s/^\s+host\s\S+\s+\[\S+\]\K +$//; # strip, not collapse the trailing whitespace
# ======== Test network IP addresses ========
# ======== IP error numbers and messages ========
# These vary between operating systems
- s/Can't assign requested address/Network Error/;
- s/Cannot assign requested address/Network Error/;
+ s/Can(no|')t assign requested address/Network Error/;
s/Operation timed out/Connection timed out/;
s/Address family not supported by protocol family/Network Error/;
- s/Network is unreachable/Network Error/;
+ s/Network( is)? unreachable/Network Error/;
s/Invalid argument/Network Error/;
s/\(\d+\): Network/(dd): Network/;
# The sizes of filter files may vary because of the substitution of local
# filenames, logins, etc.
- s/^\d+(?= bytes read from )/ssss/;
+ s/^\d+(?= (\(tainted\) )?bytes read from )/ssss/;
# ======== OpenSSL error messages ========
s/renamed tmp\/\d+\.[^.]+\.(\S+) as new\/\d+\.[^.]+\.(\S+)/renamed tmp\/MAILDIR.$1 as new\/MAILDIR.$1/;
# Maildir file names in general
- s/\b\d+\.H\d+P\d+\b/dddddddddd.HddddddPddddd/;
+ s/\b\d+\.M\d+P\d+\b/dddddddddd.HddddddPddddd/;
# Maildirsize data
while (/^\d+S,\d+C\s*$/)
last if !defined $_;
+ # SRS timestamps and signatures vary by hostname and from run to run
+
+ s/(?i)SRS0=....=.[^=]?=([^=]+)=([^@]+)\@([^ ]+)/SRS0=ZZZZ=YY=$1=$2\@$3/g;
+
+
# ======== Output from the "fd" program about open descriptors ========
# The statuses seem to be different on different operating systems, but
# at least we'll still be checking the number of open fd's.
s/max fd = \d+/max fd = dddd/;
- s/status=0 RDONLY/STATUS/g;
- s/status=1 WRONLY/STATUS/g;
- s/status=2 RDWR/STATUS/g;
+ s/status=[0-9a-f]+ (?:RDONLY|WRONLY|RDWR)/STATUS/g;
# ======== Contents of spool files ========
s/^\d\d\d(?=[PFS*])/ddd/;
- # ========= Exim lookups ==================
- # Lookups have a char which depends on the number of lookup types compiled in,
- # in stderr output. Replace with a "0". Recognising this while avoiding
- # other output is fragile; perhaps the debug output should be revised instead.
- s%(?<!sqlite)(?<!lsearch\*@)(?<!lsearch\*)(?<!lsearch)[0-?]TESTSUITE/aux-fixed/%0TESTSUITE/aux-fixed/%g;
-
# ==========================================================
# MIME boundaries in RFC3461 DSN messages
s/\d{8,10}-eximdsn-\d+/NNNNNNNNNN-eximdsn-MMMMMMMMMM/;
# TLS resumption is not always supported by the build
next if /^tls_resumption_hosts =/;
next if /^-tls_resumption/;
+
+ # gsasl library version may not support some methods
+ s/250-AUTH ANONYMOUS PLAIN SCRAM-SHA-1\K SCRAM-SHA-256//;
}
# ======== stderr ========
s/(?<=^>>>>>>>>>>>>>>>> Exim pid=)\d+(?= terminating)/pppp/;
s/^(proxy-proc \w{5}-pid) \d+$/$1 pppp/;
+ s/^(?:\s*\d+ )(exec .* -oPX)$/pppp $1/;
+ next if /(?:postfork: | fork(?:ing|ed) for )/;
# IP address lookups use gethostbyname() when IPv6 is not supported,
# and gethostbyname2() or getipnodebyname() when it is.
s/\b(gethostbyname2?|\bgetipnodebyname)(\(af=inet\))?/get[host|ipnode]byname[2]/;
+ # Extra lookups done when ipv6 is supported
+ next if /^host_fake_gethostbyname\(af=inet6\) returned 1 \(HOST_NOT_FOUND\)$/;
+
# we don't care what TZ enviroment the testhost was running
next if /^Reset TZ to/;
+ # ========= Exim lookups ==================
+ # Lookups have a char which depends on the number of lookup types compiled in,
+ # in stderr output. Replace with a "0". Recognising this while avoiding
+ # other output is fragile; perhaps the debug output should be revised instead.
+ s%^\s+(:?closing )?\K[0-?]TESTSUITE/aux-fixed/%0TESTSUITE/aux-fixed/%g;
+
# drop gnutls version strings
next if /GnuTLS compile-time version: \d+[\.\d]+$/;
next if /GnuTLS runtime version: \d+[\.\d]+$/;
next if /OpenSSL compile-time version: OpenSSL \d+[\.\da-z]+/;
next if /OpenSSL runtime version: OpenSSL \d+[\.\da-z]+/;
+ # this is timing-dependent
+ next if /^OpenSSL: creating STEK$/;
+
+ # TLS preload
+ # only OpenSSL speaks of these
+ next if /^TLS: preloading DH params for server/;
+ next if /^Diffie-Hellman initialized from default/;
+ next if /^TLS: preloading ECDH curve for server/;
+ next if /^ECDH OpenSSL [< ]?[\d.+]+ temp key parameter settings:/;
+ next if /^ECDH: .'*prime256v1'/;
+ next if /^watch dir/;
+
+ # TLS preload
+ # only GnuTLS speaks of these
+ next if /^GnuTLS global init required$/;
+ next if /^TLS: basic cred init, server/;
+ next if /^TLS: preloading cipher list for server: NULL$/;
+ s/^GnuTLS using default session cipher\/priority "NORMAL"$/TLS: not preloading cipher list for server/;
+ next if /^GnuTLS<2>: added \d+ protocols, \d+ ciphersuites, \d+ sig algos and \d+ groups into priority list$/;
+
+ # TLS preload
+ # there happen in different orders for OpenSSL/GnuTLS/noTLS
+ next if /^TLS: not preloading (CA bundle|cipher list) for server$/;
+ next if /^TLS: not preloading server certs$/;
+
# drop lookups
next if /^Lookups \(built-in\):/;
next if /^Loading lookup modules from/;
next if /name=localhost address=::1/;
# drop pdkim debugging header
- next if /^PDKIM( <<<<<<<<<<<<<<<<<<<<<<<<<<<<<+|: no signatures)$/;
+ next if /^DKIM( <<<<<<<<<<<<<<<<<<<<<<<<<<<<<+|: no signatures)$/;
# Various other IPv6 lines must be omitted too
next if /DNS lookup of \S+ \(AAAA\) using fakens/;
next if / in dns_ipv4_lookup?/;
next if / writing neg-cache entry for .*AAAA/;
+ next if /^faking res_search\(AAAA\) response length as 65535/;
if (/DNS lookup of \S+ \(AAAA\) gave NO_DATA/)
{
next;
}
+ # Non-TLS bulds have a different Recieved: header expansion
+ s/^((.*)\t}}}}by \$primary_hostname \$\{if def:received_protocol \{with \$received_protocol }})\(Exim \$version_number\)$/$1\${if def:tls_in_cipher_std { tls \$tls_in_cipher_std\n$2\t}}(Exim \$version_number)/;
+ s/^((\s*).*considering: with \$received_protocol }})\(Exim \$version_number\)$/$1\${if def:tls_in_cipher_std { tls \$tls_in_cipher_std\n$2\t}}(Exim \$version_number)/;
+ if (/condition: def:tls_in_cipher_std$/)
+ {
+ $_= <IN>; $_= <IN>; $_= <IN>; $_= <IN>;
+ $_= <IN>; $_= <IN>; $_= <IN>; $_= <IN>;
+ $_= <IN>; $_= <IN>; $_= <IN>; next;
+ }
+
+
# Skip tls_advertise_hosts and hosts_require_tls checks when the options
# are unset, because tls ain't always there.
# Platform-dependent error strings
s/Operation timed out/Connection timed out/;
+ # Platform differences on disconnect
+ s/unexpected disconnection while reading SMTP command from \[127.0.0.1\] \K\(error: Connection reset by peer\) //;
+
# Platform-dependent resolver option bits
s/^ (?:writing|update) neg-cache entry for [^,]+-\K[0-9a-f]+, ttl/xxxx, ttl/;
# timing variance, run-to-run
s/^time on queue = \K1s/0s/;
+ # content-scan: file order can vary in directory
+ s%unspool_mbox\(\): unlinking 'TESTSUITE/spool/scan/[^/]*/\K[^\']*%FFFFFFFFF%;
+
# Skip hosts_require_dane checks when the options
# are unset, because dane ain't always there.
next if /in\shosts_require_dane\?\sno\s\(option\sunset\)/x;
- # DISABLE_OCSP
+ # daemon notifier socket
+ s/^(\s*\d+|ppppp) (creating notifier socket)$/ppppp $2/;
+ s/^ \@(.*exim_daemon_notify)$/ $1/;
+ s/^(\s*\d+|ppppp) \@?(.*exim_daemon_notify)$/ppppp $2/;
+ next if /unlinking notifier socket/;
+
+ # daemon notifier socket
+ # Timing variance over runs. Collapse repeated memssages.
+ if (/notify triggered queue run/)
+ {
+ my $line = $_;
+ while (/notify triggered queue run/) { $_ = <IN>; }
+ $_ = $line . $_;
+ }
+
+ # DISABLE_OCSP
next if /in hosts_requ(est|ire)_ocsp\? (no|yes)/;
# SUPPORT_PROXY
}
# Not all platforms build with DKIM enabled
- next if /^PDKIM >> Body data for hash, canonicalized/;
+ next if /^DKIM >> Body data for hash, canonicalized/;
# Not all platforms build with SPF enabled
next if /^(spf_conn_init|SPF_dns_exim_new|spf_compile\.c)/;
# Parts of DKIM-specific debug output depend on the time/date
next if /^date:\w+,\{SP\}/;
- next if /^PDKIM \[[^[]+\] (Header hash|b) computed:/;
+ next if /^DKIM \[[^[]+\] (Header hash|b) computed:/;
# Not all platforms support TCP Fast Open, and the compile omits the check
- if (s/\S+ in hosts_try_fastopen\? (no \(option unset\)|yes \(matched "\*"\))\n$//)
+ if (s/\S+ in hosts_try_fastopen\? (no \(option unset\)|no \(end of list\)|yes \(matched "\*"\))\n$//)
{
+ chomp;
$_ .= <IN>;
s/ \.\.\. >>> / ... /;
- if (s/ non-TFO mode connection attempt to 224.0.0.0, 0 data\b$//) { $_ .= <IN>; }
+ if (s/ non-TFO mode connection attempt to 224.0.0.0, 0 data\b$//) { chomp; $_ .= <IN>; }
s/Address family not supported by protocol family/Network Error/;
s/Network is unreachable/Network Error/;
}
if (/^([0-9: ]* # possible timestamp
Connecting\ to\ [^ ]+\ [^ ]+(\ from\ [^ ]+)?)\ \.\.\.
- \ .*TFO\ mode\
+ \ .*TFO\ mode\x20
(sendto,\ no\ data:\ EINPROGRESS # Linux
|connection\ attempt\ to\ [^,]+,\ 0\ data) # MacOS & no-support
$/x)
next if /^Waiting for MySQL server to answer/;
next if /mysqladmin: CREATE DATABASE failed; .* database exists/;
+ # Postgres version-dependent differences
+ s/^initdb: warning: (enabling "trust" authentication for local connections)$/\nWARNING: $1/;
+
# Not all builds include DMARC
next if /^DMARC: no (dmarc_tld_file|sender_host_address)$/ ;
# Platform differences in errno strings
s/ SMTP\(Operation timed out\)<</ SMTP(Connection timed out)<</;
+ # Platform differences for errno values (eg. Hurd)
+ s/^errno = \d+$/errno = EEE/;
+ s/^writing error \d+: /writing error EEE: /;
+
+ # Some platforms have to flip to slow-mode taint-checking
+ next if /switching to slow-mode taint checking/;
+
# When Exim is checking the size of directories for maildir, it uses
# the check_dir_size() function to scan directories. Of course, the order
# of the files that are obtained using readdir() varies from system to
# openssl version variances
s/(TLS error on connection [^:]*: error:)[0-9A-F]{8}(:system library):(?:fopen|func\(4095\)):(No such file or directory)$/$1xxxxxxxx$2:fopen:$3/;
- s/(DANE attempt failed.*error:)[0-9A-F]{8}(:SSL routines:)(ssl3_get_server_certificate|tls_process_server_certificate|CONNECT_CR_CERT)(?=:certificate verify failed$)/$1xxxxxxxx$2ssl3_get_server_certificate/;
+ s/(DANE attempt failed.*error:)[0-9A-F]{8}(:SSL routines:)(?:(?i)ssl3_get_server_certificate|tls_process_server_certificate|CONNECT_CR_CERT)(?=:certificate verify failed$)/$1xxxxxxxx$2ssl3_get_server_certificate/;
s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
s/ARC: AMS signing: privkey PEM-block import: error:\K[0-9A-F]{8}:(PEM routines):get_name:(no start line)/0906D06C:$1:PEM_read_bio:$2/;
my ($prefix, $t_diff) = ($1, $3 - $2);
s/DKIM: d=.* t=[0-9]* x=[0-9]* /${prefix} t=T x=T+${t_diff} /;
}
+ # GnuTLS reports a different keysize vs. OpenSSL, for ed25519 keys
+ s/signer: [^ ]* bits:\K 256/ 253/;
+ s/public key too short:\K 256 bits/ 253 bits/;
# port numbers
s/(?:\[[^\]]*\]:|port )\K$parm_port_d/PORT_D/;
s/(?:\[[^\]]*\]:|port )\K$parm_port_n/PORT_N/;
s/I=\[[^\]]*\]:\K\d+/ppppp/;
+ # Platform differences for errno values (eg. Hurd). Leave 0 and negative numbers alone.
+ s/R=\w+ T=\w+ defer\K \([1-9]\d*\): / (EEE): /;
+
+ # Platform differences in errno strings
+ s/Arg list too long/Argument list too long/;
}
# ======== mail ========
log_failure($log_failed_filename, $testno, $rf);
log_test($log_summary_filename, $testno, 'F') if ($force_continue);
}
- return 1 if /^c$/i && $rf !~ /paniclog/ && $rsf !~ /paniclog/;
+ return 1 if /^c$/i && $rf !~ /paniclog/ && (!defined $rsf || $rsf !~ /paniclog/);
last if (/^[sc]$/);
}
print "\n";
print "------------ $f -----------\n"
if (defined $rf && -s $rf && defined $rsf && -s $rsf);
- system("$more '$f'");
+ system @more => $f;
}
}
}
}
- open(MUNGED, '>', $mf) || tests_exit(-1, "Failed to open $mf: $!");
- for ($i = 0; $i < @munged; $i++)
- { print MUNGED $munged[$i]; }
- close(MUNGED);
+ open(my $fh, '>', $mf) or tests_exit(-1, "Failed to open $mf: $!");
+ print $fh @munged;
}
# Deal with log sorting
if ($sortfile)
{
- my(@munged, $i, $j);
- open(MUNGED, $mf) || tests_exit(-1, "Failed to open $mf: $!");
- @munged = <MUNGED>;
- close(MUNGED);
+ my @munged = do {
+ open(my $fh, '<', $mf) or tests_exit(-1, "Failed to open $mf: $!");
+ <$fh>;
+ };
- for ($i = 0; $i < @munged; $i++)
+ for (my $i = 0; $i < @munged; $i++)
{
if ($munged[$i] =~ /^[-\d]{10}\s[:\d]{8}\s[-A-Za-z\d]{16}\s[-=*]>/)
{
+ my $j;
for ($j = $i + 1; $j < @munged; $j++)
{
last if $munged[$j] !~
}
}
- open(MUNGED, ">$mf") || tests_exit(-1, "Failed to open $mf: $!");
- print MUNGED "**NOTE: The delivery lines in this file have been sorted.\n";
- for ($i = 0; $i < @munged; $i++)
- { print MUNGED $munged[$i]; }
- close(MUNGED);
+ open(my $fh, '>', $mf) or tests_exit(-1, "Failed to open $mf: $!");
+ print $fh "**NOTE: The delivery lines in this file have been sorted.\n";
+ print $fh @munged;
}
# Do the comparison
# Handle comparison failure
print "** Comparison of $mf with $sf_current failed";
- system("$more test-cf");
+ system @more => 'test-cf';
print "\n";
for (;;)
# if we deal with a flavour file, we can't delete it, because next time the generic
# file would be used again
if ($sf_current eq $sf_flavour) {
- open(FOO, ">$sf_current");
- close(FOO);
+ open(my $fh, '>', $sf_current);
}
else {
tests_exit(-1, "Failed to unlink $sf_current") if !unlink($sf_current);
s! DN="[^,"]*\K,!/!;
',
'rejectlog' => 's/ X=TLS\S+ / X=TLS_proto_and_cipher /',
- 'mail' => 's/^\s+by .+ with .+ \K tls TLS_.+$/(TLS_proto_and_cipher)/;
- s/ \(TLS[^)]*\)/ (TLS_proto_and_cipher)/;
- ',
},
'debug_pid' =>
- { 'stderr' => 's/(^\s{0,4}|(?<=Process )|(?<=child ))\d{1,5}/ppppp/g' },
+ { 'stderr' => 's/(^\s{0,4}|(?<=Process )|(?<=child ))\d+/ppppp/g' },
'optional_dsn_info' =>
{ 'mail' => '/^(X-(Remote-MTA-(smtp-greeting|helo-response)|Exim-Diagnostic|(body|message)-linecount):|Remote-MTA: X-ip;)/'
},
'timeout_errno' => # actual errno differs Solaris vs. Linux
- { 'mainlog' => 's/(host deferral .* errno) <\d+> /$1 <EEE> /' },
+ { 'mainlog' => 's/((?:host|message) deferral .* errno) <\d+> /$1 <EEE> /' },
'peer_terminated_conn' => # actual error differs FreedBSD vs. Linux
{ 'stderr' => 's/^( SMTP\()Connection reset by peer(\)<<)$/$1closed$2/' },
if (/^dump\s+(\S+)/)
{
- my($which) = $1;
- my(@temp);
+ my $which = $1;
print ">> ./eximdir/exim_dumpdb $parm_cwd/spool $which\n" if $debug;
- open(IN, "./eximdir/exim_dumpdb $parm_cwd/spool $which |");
- open(OUT, ">>test-stdout");
- print OUT "+++++++++++++++++++++++++++\n";
+ open(my $in, "-|", './eximdir/exim_dumpdb', "$parm_cwd/spool", $which) or die "Can't run exim_dumpdb: $!";
+ open(my $out, ">>test-stdout");
+ print $out "+++++++++++++++++++++++++++\n";
if ($which eq "retry")
{
- $/ = "\n ";
- @temp = <IN>;
- $/ = "\n";
-
- @temp = sort {
- my($aa) = split(' ', $a);
- my($bb) = split(' ', $b);
- return $aa cmp $bb;
- } @temp;
-
+ # the sort key is the first part of the retry db dump line, but for
+ # sorting we (temporarly) replace the own hosts ipv4 with a munged
+ # version, which matches the munging that is done later
+ # Why? We must ensure sure, that 127.0.0.1 always sorts first
+ # map-sort-map: Schwartz's transformation
+ # test 0099
+ my @temp = map { $_->[1] }
+ sort { $a->[0] cmp $b->[0] }
+ #map { [ (split)[0] =~ s/\Q$parm_ipv4/ip4.ip4.ip4.ip4/gr, $_ ] } # this is too modern for 5.10.1
+ map {
+ (my $k = (split)[0]) =~ s/\Q$parm_ipv4/ip4.ip4.ip4.ip4/g;
+ [ $k, $_ ]
+ }
+ do { local $/ = "\n "; <$in> };
foreach $item (@temp)
{
$item =~ s/^\s*(.*)\n(.*)\n?\s*$/$1\n$2/m;
- print OUT " $item\n";
+ print $out " $item\n";
}
}
else
{
- @temp = <IN>;
+ my @temp = <$in>;
if ($which eq "callout")
{
@temp = sort {
return $aa cmp $bb;
} @temp;
}
- print OUT @temp;
+ print $out @temp;
}
-
- close(IN);
- close(OUT);
+ close($in); # close it explicitly, otherwise $? does not get set
return 1;
}
# The "killdaemon" command should ultimately follow the starting of any Exim
-# daemon with the -bd option. We kill with SIGINT rather than SIGTERM to stop
-# it outputting "Terminated" to the terminal when not in the background.
+# daemon with the -bd option.
if (/^killdaemon/)
{
print ">> killdaemon: recovered pid $pid\n" if $debug;
if ($pid)
{
- run_system("sudo /bin/kill -INT $pid");
+ run_system("sudo /bin/kill -TERM $pid");
wait;
}
} else {
$pid = `cat $parm_cwd/spool/exim-daemon.*`;
if ($pid)
{
- run_system("sudo /bin/kill -INT $pid");
+ run_system("sudo /bin/kill -TERM $pid");
close DAEMONCMD; # Waits for process
}
}
if ($args =~ /\$msg/)
{
- my @listcmd = ("$parm_cwd/eximdir/exim", '-bp',
+ my($queuespec);
+ if ($args =~ /-qG\w+/) { $queuespec = $&; }
+
+ my @listcmd;
+
+ if (defined $queuespec)
+ {
+ @listcmd = ("$parm_cwd/eximdir/exim", '-bp',
+ $queuespec,
"-DEXIM_PATH=$parm_cwd/eximdir/exim",
-C => "$parm_cwd/test-config");
+ }
+ else
+ {
+ @listcmd = ("$parm_cwd/eximdir/exim", '-bp',
+ "-DEXIM_PATH=$parm_cwd/eximdir/exim",
+ -C => "$parm_cwd/test-config");
+ }
print ">> Getting queue list from:\n>> @listcmd\n" if $debug;
# We need the message ids sorted in ascending order.
# Message id is: <timestamp>-<pid>-<fractional-time>. On some systems (*BSD) the
# Run the command, with stdin connected to a pipe, and write the stdin data
-# to it, with appropriate substitutions. If a line ends with \NONL\, chop off
-# the terminating newline (and the \NONL\). If the command contains
+# to it, with appropriate substitutions. If a starts with '>>> ', process it
+# via Perl's string eval().
+# If the command contains
# -DSERVER=server add "-server" to the command, where it will adjoin the name
# for the stderr file. See comment above about the use of -DSERVER.
open CMD, "|${cmd}${stderrsuffix}" || tests_exit(1, "Failed to run $cmd");
CMD->autoflush(1);
-while (<SCRIPT>)
+LINE: while (<SCRIPT>)
{
$lineno++;
last if /^\*{4}\s*$/;
do_substitute($testno);
- if (/^(.*)\\NONL\\\s*$/) { print CMD $1; } else { print CMD; }
+ if (my ($cmd, $line) = /^(:\S+?:)(.*)/) {
+ $_ = $line;
+ {
+ $cmd eq ':eval:' and do {
+ $_ = eval "\"$_\"";
+ last;
+ };
+ $cmd eq ':noeol:' and do {
+ s/[\r\n]*$//;
+ last;
+ };
+ $cmd eq ':sleep:' and do {
+ sleep $_;
+ next LINE;
+ };
+ }
+ }
+ print CMD;
}
# For timeout tests, wait before closing the pipe; we expect a
# Check for the "less" command #
##################################################
-$more = 'more' if system('which less >/dev/null 2>&1') != 0;
+@more = 'more' if system('which less >/dev/null 2>&1') != 0;
GetOptions(
'debug' => sub { $debug = 1; $cr = "\n" },
'diff' => sub { $cf = 'diff -u' },
- 'continue' => sub { $force_continue = 1; $more = 'cat' },
+ 'continue' => sub { $force_continue = 1; @more = 'cat' },
'update' => \$force_update,
'ipv4!' => \$have_ipv4,
'ipv6!' => \$have_ipv6,
# Find this host's IP addresses - there may be many, of course, but we keep
# one of each type (IPv4 and IPv6).
+#XXX it would be good to avoid non-UP interfaces
open(IFCONFIG, '-|', (grep { -x "$_/ip" } split /:/, $ENV{PATH}) ? 'ip address' : 'ifconfig -a')
or die "** Cannot run 'ip address' or 'ifconfig -a'\n";
while (not ($parm_ipv4 and $parm_ipv6) and defined($_ = <IFCONFIG>))
{
- if (not $parm_ipv4 and /^\s*inet(?:\saddr)?:?\s?(\d+\.\d+\.\d+\.\d+)(?:\/\d+)?\s/i)
+ if (/^(?:[0-9]+: )?([a-z0-9]+): /) { $ifname = $1; }
+
+ if (not $parm_ipv4 and /^\s*inet(?:\saddr(?:ess))?:?\s*(\d+\.\d+\.\d+\.\d+)(?:\/\d+)?\s/i)
{
- next if $1 =~ /^(?:127|10)\./;
+ # It would be nice to be able to vary the /16 used for manyhome; we could take
+ # an option to runtest used here - but we'd also have to pass it on to fakens.
+ # Possibly an environment variable?
+ next if $1 eq '0.0.0.0' or $1 =~ /^(?:127|10\.250)\./;
$parm_ipv4 = $1;
}
- if (not $parm_ipv6 and /^\s*inet6(?:\saddr)?:?\s?([abcdef\d:]+)(?:%[^ \/]+)?(?:\/\d+)?/i)
+ if ( (not $parm_ipv6 or $parm_ipv6 =~ /%/)
+ and /^\s*inet6(?:\saddr(?:ess))?:?\s*([abcdef\d:]+)(?:%[^ \/]+)?(?:\/\d+)?/i)
{
- next if $1 eq '::1' or $1 =~ /^fe80/i;
+ next if $1 eq '::' or $1 eq '::1' or $1 =~ /^ff00/i or $1 =~ /^fe80::1/i;
$parm_ipv6 = $1;
+ if ($1 =~ /^fe80/i) { $parm_ipv6 .= '%' . $ifname; }
}
}
close(IFCONFIG);
print "IPv4 address is $parm_ipv4\n";
print "IPv6 address is $parm_ipv6\n";
$parm_ipv6 =~ /^[^%\/]*/;
+# drop any %scope from the ipv6, for some uses
+($parm_ipv6_stripped = $parm_ipv6) =~ s/%.*//g;
# For munging test output, we need the reversed IP addresses.
$parm_ipv6r = $parm_ipv6; # Appropriate if not in use
if ($parm_ipv6 =~ /^[\da-f]/)
{
- my(@comps) = split /:/, $parm_ipv6;
+ my(@comps) = split /:/, $parm_ipv6_stripped;
my(@nibbles);
foreach $comp (@comps)
{
}
unlink("$parm_cwd/test-config");
}
+ elsif (/^ipv6-non-linklocal/)
+ {
+ if ($parm_ipv6 =~ /%/) { $wantthis = 0; last; }
+ }
else
{
tests_exit(-1, "Unknown line in \"scripts/$testdir/REQUIRES\": \"$_\"");
"; for queries that it cannot answer\n\n" .
"PASS ON NOT FOUND\n\n";
print OUT "$shortname A $parm_ipv4\n" if $have_ipv4;
- print OUT "$shortname AAAA $parm_ipv6\n" if $have_ipv6;
+ print OUT "$shortname AAAA $parm_ipv6_stripped\n" if $have_ipv6;
print OUT "\n; End\n";
close(OUT);
}
if ($have_ipv4 && $parm_ipv4 ne "127.0.0.1")
{
my(@components) = $parm_ipv4 =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)/;
- open(OUT, ">$parm_cwd/dnszones/db.ip4.$components[0]") ||
- tests_exit(-1,
- "Failed to open $parm_cwd/dnszones/db.ip4.$components[0]: $!");
- print OUT "; This is a dynamically constructed fake zone file.\n" .
- "; The zone is $components[0].in-addr.arpa.\n\n" .
- "$components[3].$components[2].$components[1] PTR $parm_hostname.\n\n" .
- "; End\n";
- close(OUT);
+
+ if ($components[0]=='10')
+ {
+ open(OUT, ">>$parm_cwd/dnszones/db.ip4.$components[0]") ||
+ tests_exit(-1, "Failed to open $parm_cwd/dnszones/db.ip4.$components[0]: $!");
+ print OUT "$components[3].$components[2].$components[1] PTR $parm_hostname.\n\n";
+ close(OUT);
+ }
+ else
+ {
+ open(OUT, ">$parm_cwd/dnszones/db.ip4.$components[0]") ||
+ tests_exit(-1,
+ "Failed to open $parm_cwd/dnszones/db.ip4.$components[0]: $!");
+ print OUT "; This is a dynamically constructed fake zone file.\n" .
+ "; The zone is $components[0].in-addr.arpa.\n\n" .
+ "$components[3].$components[2].$components[1] PTR $parm_hostname.\n\n" .
+ "; End\n";
+ close(OUT);
+ }
}
-if ($have_ipv6 && $parm_ipv6 ne "::1")
+if ($have_ipv6 && $parm_ipv6_stripped ne "::1")
{
- my($exp_v6) = $parm_ipv6;
+ my($exp_v6) = $parm_ipv6_stripped;
$exp_v6 =~ s/[^:]//g;
- if ( $parm_ipv6 =~ /^([^:].+)::$/ ) {
+ if ( $parm_ipv6_stripped =~ /^([^:].+)::$/ ) {
$exp_v6 = $1 . ':0' x (9-length($exp_v6));
- } elsif ( $parm_ipv6 =~ /^(.+)::(.+)$/ ) {
+ } elsif ( $parm_ipv6_stripped =~ /^(.+)::(.+)$/ ) {
$exp_v6 = $1 . ':0' x (8-length($exp_v6)) . ':' . $2;
- } elsif ( $parm_ipv6 =~ /^::(.+[^:])$/ ) {
+ } elsif ( $parm_ipv6_stripped =~ /^::(.+[^:])$/ ) {
$exp_v6 = '0:' x (9-length($exp_v6)) . $1;
} else {
- $exp_v6 = $parm_ipv6;
+ $exp_v6 = $parm_ipv6_stripped;
}
my(@components) = split /:/, $exp_v6;
my(@nibbles) = reverse (split /\s*/, shift @components);
last if /^[rc]$/i;
if (/^e$/i)
{
- system("$more test-stderr");
+ system @more => 'test-stderr';
}
elsif (/^o$/i)
{
- system("$more test-stdout");
+ system @more => 'test-stdout';
}
}