# HG changeset patch # User Heiko Schlittermann # Date 1288905978 -3600 # Node ID da18d670092f576ad9ff5f7473628eccabff7cde # Parent 09883d94ba30f29e3ba7b8691d4f2532193e7771 read the complete file and try to match with one huuuge pattern diff -r 09883d94ba30 -r da18d670092f 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 () { - /^\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/^(?!;)(?
			# 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+)
+			 (?\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 () { 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]: "; $_ = ; }
 			/^y|^$/i and system "rndc reload";
 		} else {