X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=scripts%2Fnamed-conf;h=b0374927781d120276323184c28bdbf2d082b39a;hb=d8b6b8cd878568df71395443fab7a2d93259aaa6;hp=e788f07a4251f034d08a030e13c583ff3be5eeca;hpb=4f4c11add419e120b2800a350f23091f47e7e03f;p=chiark-utils.git diff --git a/scripts/named-conf b/scripts/named-conf index e788f07..b037492 100755 --- a/scripts/named-conf +++ b/scripts/named-conf @@ -1,66 +1,178 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w -$base= "/var/named"; -$conf= "$base/conf"; -$etcfile= "/etc/named/zones-rgc"; +use IO::File; +use Data::Dumper; -$check= 1; -$progress= 1; +$etcfile= "/etc/bind/chiark-conf-gen.zones"; +$where= ''; -while ($ARGV[0] =~ m/^\-/) { +$mode= ''; +$verbosity= 1; +$fromroot= 0; + +while (@ARGV && $ARGV[0] =~ m/^\-/) { $_= shift @ARGV; - last if m/^\-\-?$/; - while (m/^\-./) { - if (s/^\-f/-/) { $usage=0; $check=0; $install++; } - elsif (s/^\-y/-/) { $usage=0; $check=1; $install++; } - elsif (s/^\-n/-/) { $usage=0; $check=1; $install=0; } - elsif (s/^\-h/-/) { $hostdelg=1; $hostzone=0; } - elsif (s/^\-z/-/) { $hostdelg=1; $hostzone=1; } - elsif (s/^\-q/-/) { $progress=0; } - else { $usage=1; break; } + if (s/^\-\-//) { + last if m/^$/; + if (m/^quiet$/) { $verbosity=0; } + elsif (m/^verbose$/) { $verbosity=2; } + elsif (m/^root$/) { $fromroot=1; } + elsif (m/^(yes|no|force)$/) { m/^./; $mode= $&; } + elsif (m/^config$/) { $etcfile= loarg(); $where= '--config option'; } + else { usageerr("unknown option --$_"); } + } else { + s/^\-//; + last if m/^$/; + while (m/^./) { + if (s/^[ynf]//) { $mode=$&; } + elsif (s/^r//) { $fromroot=1; } + elsif (s/^v//) { $verbosity=2; } + elsif (s/^q//) { $verbosity=0; } + elsif (s/^C//) { $etcfile= soarg(); $where= '-C option'; } + else { usageerr("unknown option -$&"); } + } } } -die -"usage: named-conf-regen -f|-y|-n [-h|-z]\n". +sub loarg() { usageerr("missing option value") if !@ARGV; return shift @ARGV; } +sub soarg() { my ($rv); $rv=$_; $_=''; return length $rv ? $rv : loarg(); } + +usageerr("must specify either -f|-y|-n or zones (and not both)") + if !!$mode == !!@ARGV; + +sub usageerr ($) { + die +"$_[0] +usage: named-conf-regen [-rvq] -f|-y|-n|...\n". "operation modes:\n". -" -f install without checking -ff and then ndc reload\n". -" -y check and install -yy and then ndc reload\n". -" -n check only\n". +" -f --force install without checking\n". +" -y --yes check and install\n". +" -n --no check only\n". "additional options:\n". -" -h check output from host -C\n". -" -z check output from host -C and host -val\n". - if $usage; - -beginfile('secondary.zones'); -open E, "< $etcfile" or die "$0: open $etcfile: $!\n"; -for (;;) { - $!=0; defined $_= or die "$0: read $etcfile $!\n"; - s/^\s+//; chomp; s/\s+$//; - next if m/^\#/; - last if m/^end$/; - if (m/^myname\s+(\S.*\S)/) { - @mynames= split /\s+/, $1; - } elsif (m/^(secondary|backup|unoff)\s+(\S+)\s+([0-9. \t]+)$/) { - $style= $1; - $zone= $2; - @servers= split /\s+/, $3; - $file= "slave/$zone"; - progress(); - check(); - } else { - die "$0: $etcfile:$.: syntax error in \`$_'\n"; +" -r --root check all the way back to the root\n". +" -q --quiet no output for OK zones\n". +" -v --verbose extra verbose\n"; +} + +cfg_fail("config filename $etcfile should have been absolute path of a file") + unless $etcfile =~ m,^/, && $etcfile !~ m,/$,; + +$default_dir= $etcfile; +$default_dir =~ s,/[^/]+$,,; + +$slave_dir= 'slave'; +$slave_prefix= ''; +$slave_suffix= ''; +@self_ns= @self_soa= (); +%zone_cfg= (); +@zone_cfg_list= (); +$output= ''; +$default_output= ''; +%output_contents= (); + +read_config($etcfile); + +print Dumper(@zone_cfg_list), Dumper(%zone_cfg); + +sub cfg_fail ($) { die "$0: $where:\n $_[0]\n"; } + +sub read_config ($) { + my ($if) = @_; + my ($fh,$z,@self, $dir,$prefix,$suffix,$lprefix,$lsuffix); + local ($_,$1,$2,$3); + + $fh= new IO::File $if,'r' or cfg_fail("open $if:\n $!"); + for (;;) { + if (!defined($_= <$fh>)) { + cfg_fail("read config file $if:\n $!") if $fh->error(); + last; + } + $where= "$if:$."; + s/^\s+//; chomp; s/\s+$//; + next if m/^\#/; + last if m/^end$/; + next unless m/\S/; + if (m/^self(\-ns|\-soa|)\s+(\S.*\S)/) { + @self= split /\s+/, $2; + @self_ns= @self if $1 ne '-soa'; + @self_soa= @self if $1 ne '-ns'; + } elsif (m/^primary\-dir\s+(\S+)((?:\s+(\S+))??:\s+(\S+))?$/) { + ($dir, $prefix, $suffix) = (qualify($1),$2,$3); + $suffix= '_db' if !length $suffix; + opendir D, $dir or cfg_fail("open primary-dir $dir:\n $!"); + $lprefix= length $prefix; $lsuffix= length $suffix; + while ($!=0, $_= readdir D) { + next if m/^\./ && !$lprefix; + next unless length > $lprefix+$lsuffix; + next unless substr($_,0,$lprefix) eq $prefix; + next unless substr($_,length($_)-$lsuffix) eq $suffix; + $z= substr($_,$lprefix,length($_)-($lprefix+$lsuffix)); + zone_conf($z,'primary',"$dir/$_"); + } + $! and cfg_fail("read primary-dir $dir:\n $!"); + closedir D or cfg_fail("close primary-dir $dir:\n $!"); + } elsif (m/^primary\s+(\S+)\s+(\S+)$/) { + zone_conf($1,'primary',qualify($2)); + } elsif (m/^secondary\s+(\S+)\s+([0-9.\t]+)$/) { + zone_conf($1,'secondary','',$2); + } elsif (m/^stealth\s+(\S+)\s+([0-9. \t]+)$/) { + zone_conf($1,'stealth','',split /\s+/, $2); + } elsif (m/^slave\-dir\s+(\S+)((?:\s+(\S+))??:\s+(\S+))?$/) { + ($slave_dir, $slave_prefix, $slave_suffix) = (qualify($1),$2,$3); + } elsif (m/^output\s+bind8\+(\S+)$/) { + cfg_fail("default output may not apply to only some zones") + if @zone_cfg_list && length $default_output; + set_output(qualify($1)); + } elsif (m/^include\s+(\S+)$/) { + read_config($1); + } else { + cfg_fail("unknown configuration directive". + " or incorrect syntax or arguments"); + } + } + $fh->close or cfg_fail("close config file $if:\n $!"); +} + +sub qualify ($) { + my ($i) = @_; + $i= "$default_dir/$i" unless $i =~ m,^/,; +} + +sub zone_conf ($$@) { + my ($zone,$style,$file,@servers) = @_; + $file= qualify("$slave_dir/$slave_prefix".$zone.$slave_suffix) + unless length $file; + if (!length $output) { + $default_output= qualify('chiark-conf-gen.bind8') + unless length $default_output; + set_output($default_output); } + cfg_fail("redefined zone $zone") if exists $zone_cfg{$zone}; + $zone_cfg{$zone}{'file'}= $file; + $zone_cfg{$zone}{'style'}= $style; + $zone_cfg{$zone}{'servers'}= @servers; + $zone_cfg{$zone}{'output'}= $output; + push @zone_cfg_list, $zone; +} + +sub set_output($) { + my ($newout) = @_; + $output= $newout; + $output_contents{$output}= ''; } +__DATA__ + + + sub lookup ($$) { my ($type,$domain) = @_; my ($c,@result); - defined($c=open ADH, "-|") or die "$0: fork adnshost: $!\n"; + defined($c=open ADH, "-|") or die "$0: fork adnshost:\n $!\n"; if (!$c) { exec 'adnshost','+Do','+Dt','+Dc','-Cf',"-t$type", '-',"$domain."; - die "$0: exec adnshost: $!\n"; + die "$0: exec adnshost:\n $!\n"; } @result= ; chomp @result; @@ -121,7 +233,7 @@ sub check () { for $super_ns (@super_ns) { @deleg_ns= (); open DIG, "dig @$super_ns. -t ns +norecurse $zone." - or die "$0: fork for dig: $!\n"; + or die "$0: fork for dig:\n $!\n"; while () { @@ -197,7 +309,7 @@ done endfile -chdir "$base/primary" or die "$0: chdir $base/primary: $!"; +chdir "$base/primary" or die "$0: chdir $base/primary:\n $!"; beginfile('primary.zones'); for $f (<*_db>) { @@ -221,19 +333,19 @@ endfile sub beginfile ($) { $currentfile= $_[0]; $currentfile_opened= $install ? "$conf/$currentfile.new" : "/dev/null"; - open CFF, "> $toopen" or die "$0: begin $currentfile_opened: $!\n"; + open CFF, "> $toopen" or die "$0: begin $currentfile_opened:\n $!\n"; } endfile () { - close CFF or die "$0: close $currentfile_opened: $!\n"; + close CFF or die "$0: close $currentfile_opened:\n $!\n"; push @files, $currentfile; } sub installfiles () { return unless $install; - chdir $conf or die "$0: chdir $conf: $!\n"; + chdir $conf or die "$0: chdir $conf:\n $!\n"; for $f (@files) { - rename "$f.new", $f or die "$0: install new $f: $!\n"; + rename "$f.new", $f or die "$0: install new $f:\n $!\n"; } }