Skip to content

Commit 42195f3

Browse files
committed
reports: rewrite opendmarc-importstats as a Perl script
Converts the 25-line shell script to a proper Perl .in template, consistent with every other script in reports/. - Reads HistoryFile from opendmarc.conf using a real parser (no grep/sed), so users who configure a non-default path get correct behaviour automatically - --history-file=path overrides the config for command-line flexibility - --conf=file selects an alternate opendmarc.conf - Falls back to /var/run/opendmarc.dat when HistoryFile is not set - Uses open(pipe) instead of shell redirection to avoid injection risk - --verbose and --version consistent with other reporting tools Closes trusteddomainproject#358.
1 parent d9ce28b commit 42195f3

4 files changed

Lines changed: 138 additions & 26 deletions

File tree

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ AC_CONFIG_FILES([ Makefile
578578
reports/opendmarc-expire.8
579579
reports/opendmarc-import
580580
reports/opendmarc-import.8
581+
reports/opendmarc-importstats
581582
reports/opendmarc-importstats.8
582583
reports/opendmarc-params
583584
reports/opendmarc-params.8

reports/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ dist_doc_DATA = README
88
dist_sbin_SCRIPTS = opendmarc-expire opendmarc-import opendmarc-importstats \
99
opendmarc-params opendmarc-reports
1010

11+
CLEANFILES = opendmarc-importstats
12+
1113
dist_man_MANS = opendmarc-expire.8 opendmarc-import.8 opendmarc-params.8 \
1214
opendmarc-reports.8 opendmarc-importstats.8

reports/opendmarc-importstats

Lines changed: 0 additions & 26 deletions
This file was deleted.

reports/opendmarc-importstats.in

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/@PERL@
2+
#
3+
# Copyright (c) 2012, 2026, The Trusted Domain Project. All rights reserved.
4+
#
5+
# Script to rotate and import the opendmarc history file.
6+
# Intended to be run from cron or a systemd timer.
7+
8+
use strict;
9+
use warnings;
10+
11+
use File::Basename;
12+
use Getopt::Long;
13+
14+
my $progname = basename($0);
15+
my $version = "@VERSION@";
16+
my $helponly = 0;
17+
my $showversion = 0;
18+
my $verbose = 0;
19+
20+
my $def_conffile = '@sysconfdir@/opendmarc/opendmarc.conf';
21+
my $def_historyfile = '/var/run/opendmarc.dat';
22+
my $import = '@sbindir@/opendmarc-import';
23+
24+
my $conffile;
25+
my $historyfile;
26+
27+
sub usage
28+
{
29+
print STDERR "$progname: usage: $progname [options]\n";
30+
print STDERR "\t--conf=file opendmarc config file [$def_conffile]\n";
31+
print STDERR "\t--history-file=path history file to rotate and import\n";
32+
print STDERR "\t [HistoryFile from config, or $def_historyfile]\n";
33+
print STDERR "\t--help print help and exit\n";
34+
print STDERR "\t--verbose verbose output\n";
35+
print STDERR "\t--version print version and exit\n";
36+
}
37+
38+
my $opt_retval = GetOptions(
39+
'conf=s' => \$conffile,
40+
'history-file=s' => \$historyfile,
41+
'help!' => \$helponly,
42+
'verbose!' => \$verbose,
43+
'version!' => \$showversion,
44+
);
45+
46+
if (!$opt_retval || $helponly)
47+
{
48+
usage();
49+
exit($helponly ? 0 : 1);
50+
}
51+
52+
if ($showversion)
53+
{
54+
print STDOUT "$progname v$version\n";
55+
exit(0);
56+
}
57+
58+
# Read HistoryFile from opendmarc.conf unless overridden on the command line.
59+
if (!defined($historyfile))
60+
{
61+
my $cf = defined($conffile) ? $conffile : $def_conffile;
62+
if (open(my $fh, '<', $cf))
63+
{
64+
while (my $line = <$fh>)
65+
{
66+
chomp $line;
67+
$line =~ s/^\s+//;
68+
next if $line =~ /^#/ || $line eq '';
69+
if ($line =~ /^HistoryFile\s+(\S+)/)
70+
{
71+
$historyfile = $1;
72+
last;
73+
}
74+
}
75+
close($fh);
76+
}
77+
elsif (defined($conffile))
78+
{
79+
print STDERR "$progname: can't open config file $cf: $!\n";
80+
exit(1);
81+
}
82+
}
83+
84+
$historyfile //= $def_historyfile;
85+
86+
if ($verbose)
87+
{
88+
print STDERR "$progname: history file is $historyfile\n";
89+
}
90+
91+
# Nothing to do if the history file is absent or empty.
92+
exit(0) unless -s $historyfile;
93+
94+
my $oldfile = "$historyfile.OLD.$$";
95+
96+
if (!rename($historyfile, $oldfile))
97+
{
98+
print STDERR "$progname: can't rename $historyfile to $oldfile: $!\n";
99+
exit(1);
100+
}
101+
102+
if ($verbose)
103+
{
104+
print STDERR "$progname: importing $oldfile\n";
105+
}
106+
107+
# Pipe the rotated file to opendmarc-import without a shell.
108+
open(my $infh, '<', $oldfile) or do {
109+
print STDERR "$progname: can't open $oldfile: $!\n";
110+
exit(1);
111+
};
112+
113+
open(my $pipe, '|-', $import) or do {
114+
print STDERR "$progname: can't run $import: $!\n";
115+
close($infh);
116+
exit(1);
117+
};
118+
119+
while (read($infh, my $buf, 65536))
120+
{
121+
print $pipe $buf;
122+
}
123+
close($infh);
124+
125+
if (!close($pipe) || $? != 0)
126+
{
127+
my @st = stat($oldfile);
128+
printf STDERR "$progname: import failed; leftover file: %s (%d bytes)\n",
129+
$oldfile, defined($st[7]) ? $st[7] : 0;
130+
exit(1);
131+
}
132+
133+
unlink($oldfile);
134+
135+
print STDERR "$progname: import complete\n" if $verbose;

0 commit comments

Comments
 (0)