read the complete file and try to match with one huuuge pattern
authorHeiko Schlittermann <hs@schlittermann.de>
Thu, 04 Nov 2010 22:26:18 +0100
changeset 11 da18d670092f
parent 10 09883d94ba30
child 12 b98e281d5a09
read the complete file and try to match with one huuuge pattern
update-serial
--- a/update-serial	Thu Nov 04 22:23:10 2010 +0100
+++ b/update-serial	Thu Nov 04 22:26:18 2010 +0100
@@ -17,106 +17,99 @@
 use strict;
 use warnings;
 
+use File::Copy;
 use File::Basename;
-use File::Copy;
+use Getopt::Long;
+use Pod::Usage;
 
 #my $dnssec_sign = "../dnstools/dnssec-sign";
 my $master_dir = "/etc/bind/master";
-
-my $ME = basename $0;
-my @tmpfiles;
-my $verbose = 0;
-my $opt_yes = 0;
-my @Zones;
-my $file;
+my $opt_verbose = 0;
+my $opt_reload = 0;
+my $opt_dnssec = 0;
 
 
-sub cleanup() { unlink @tmpfiles; }
+{
+	my @cleanup;
+	sub cleanup(@) { 
+		return push @cleanup, @_ if @_;
+		unlink @cleanup; 
+	}
+}
+
 END { cleanup(); }
 
-@ARGV and $ARGV[0] eq "-y" and $opt_yes = 1, shift;
-@Zones = @ARGV ? @ARGV : glob("$master_dir/*");
-
+sub next_serial($);
 
 MAIN: {
-	my $changed;
-	my ($dd, $mm, $yy) =(localtime())[3..5];
-	my $date;
-	$mm++;
 
-	foreach ($dd, $mm) { s/^\d$/0$&/; }
-	$yy += 1900;
-	$date = "$yy$mm$dd";
+	GetOptions(
+		"verbose!" => \$opt_verbose,
+		"yes|reload!" => \$opt_reload,
+		"dnssec!" => \$opt_dnssec,
+	) or pod2usage();
 
 
-	while (my $file = shift @Zones) {
-
-		my $file_basename = basename($file);
+	-d $master_dir or die "directory $master_dir not found\n" if not @ARGV;
+	my @files = map { (-d) ? glob("$_/*") : $_ } @ARGV ? @ARGV : $master_dir;
 
-		$file =~ s#($master_dir)(/.*)#$1$2$2#;
-		local (*I, *O);
-		my $done = 0;
+	my $changed = 0;
+	foreach my $file (@files) {
+
+		$file = undef, next if basename($file) !~ /\./;
+		$file = undef, next if $file =~ /\.bak|~$/;
 
-		my $new = "$file.$$.tmp";
-		my $bak = "$file.bak";
-		my $stamp = $master_dir . "/.stamp/" . basename($file);	
+		# zone file could be
+		#	$master_dir/xxx.de
+		#    or $master_dir/xxx.de/xxx.de
+		$file = "$file/" . basename($file) if -d $file;
 
-		$file =~ /(\.bak|~)$/ and next;
-		$file !~ /\./ and next;
+		my $stamp_file = dirname($file) . "/.stamp/" . basename($file);	
+		print "$file:" if $opt_verbose;
 
-		$verbose && print "$file:";
-
-
-		if (-f $stamp && ((stat($stamp))[9] >= (stat($file))[9])) {
-			$verbose && print " fresh, skipping.\n";
+		if (stat $stamp_file and (stat _)[9] >= (stat $file)[9]) {
+			print " fresh, skipping." if $opt_verbose;
 			next;
 		}
 
-		$done = 0;
-		push @tmpfiles, $new;
-		open(*I, "<$file") or die("Can't open < $file: $!\n");
-		open(*O, ">$new") or die("Can't open > $new: $!\n");
+		$_ = dirname($stamp_file);
+		mkdir or die "mkdir $_: $!\n" if not -d;
+
+		my $now = time;
 
-		while (<I>) {
-			/^\s+((\d+)(\d{2}))\s*;\s*serial/i and do {		# PATTERN
-				my ($sdate, $scount, $serial) = ($2, $3, $1);
-				$done = 1;
-				print " [$file] serial $sdate$scount";
+		open(my $in, "+<", $file) or do {
+			print "?? $!";
+			next;
+		};
 
-				if ($date eq $sdate) { $scount++; }
-				else { $sdate = $date; $scount = "00"; }
-
-				print " bumping to $sdate$scount";
-				s/$serial/$sdate$scount/;
+		$_ = join "", <$in>;
 
-				# dnssec - new sign
-				system "cd ../dnstools && ./dnssec-sign $file_basename";
-				#die "$dnssec_sign not found ($!)" if $? == -1;
-				exit 1 if $?;
-			};
-			print O;
-		}
-
-		close(O); close(I);
-
-		if ($done) {
-			# copy($file, $bak) or die("Can't copy $file -> $bak: $!\n");
+		# this pattern is too complicated
+		s/^(?!;)(?<pre>			# skip lines starting with comment
+			 (?:\S+)?			# label
+			 (?:\s+\d+.)?		# ttl
+			 (?:\s+in)?			# class
+			 \s+soa				# everything before the SOA
+			 \s+\S+				# ns
+			 \s+\S+				# hostmaster
+			 (?:\s*\()?
+			 \s+)
+			 (?<serial>\d{10})		# serial
+		/$+{pre} . next_serial($+{serial})/exims or next;
 
-			open(I, "<$new") or die("Can't open <$new: $!\n");
-			open(O, ">$file") or die("Can't open >$file: $!\n");
-			while (<I>) { print O or die("Can't write to $file: $!\n"); }
-			close(I) or die("Can't close $new: $!\n");
-			close(O) or die("Can't close $file: $!\n");
+		print "$+{serial} ⇒ @{[next_serial($+{serial})]}" if $opt_verbose;
 
-			unlink $new;
+		copy($file => "$file~") or die("Can't copy $file -> $file~: $!\n");
+		seek($in, 0, 0) or die "Can't seek in $file: $!\n";
+		truncate($in, 0) or die "Can't truncate $file: $!\n";
+		print $in $_;
 
-			open(O, ">$stamp") or die("Can't open >$stamp: $!\n");
-			close(O);
-			$changed++;
-		} else {
-			print " $file: no serial number found: no zone file?";
-		}
-		print "\n";
+		open(my $out, ">$stamp_file");
+		close($out);
+
+		$changed++;
+	} continue {
+		print "\n" if $opt_verbose and defined $file;
 	}
 
 	if ($changed) {
@@ -127,7 +120,7 @@
 			-f $_ and $pidfile = $_ and last; }
 
 		if ($pidfile) {
-			if ($opt_yes) { $_ = "y"; print "** Nameserver will be reloaded\n"; } 
+			if ($opt_reload) { $_ = "y"; print "** Nameserver will be reloaded\n"; } 
 			else { print "** Reload now? [Y/n]: "; $_ = <STDIN>; }
 			/^y|^$/i and system "rndc reload";
 		} else {