📄 bind8-lib.pl
字号:
# bind8-lib.pl# Common functions for bind8 config filesdo '../web-lib.pl';&init_config();do './records-lib.pl';# get_config()# Returns an array of references to assocs, each containing the details of# one directivesub get_config{if (!@get_config_cache) { @get_config_cache = &read_config_file($config{'named_conf'}); }return \@get_config_cache;}# get_config_parent()# Returns a structure containing the top-level config as memberssub get_config_parent{return { 'file' => $config{'named_conf'}, 'type' => 1, 'line' => 0, 'eline' => $lines_count{$config{'named_conf'}}-1, 'members' => &get_config() };}# read_config_file(file, [expand includes])# Reads a config file and returns an array of valuessub read_config_file{local($lnum, $line, $cmode, @ltok, @lnum, @tok, @rv, $i, $t, $j, $ifile, @inc, $str);$lnum = 0;open(FILE, $_[0]);while($line = <FILE>) { # strip comments $line =~ s/\r|\n//g; $line =~ s/#.*$//g; $line =~ s/\/\/.*$//g; $line =~ s/\/\*.*\*\///g; while(1) { if (!$cmode && $line =~ /\/\*/) { # start of a C-style comment $cmode = 1; $line =~ s/\/\*.*$//g; } elsif ($cmode) { if ($line =~ /\*\//) { # end of comment $cmode = 0; $line =~ s/^.*\*\///g; } else { $line = ""; last; } } else { last; } } # split line into tokens undef(@ltok); while(1) { if ($line =~ /^\s*"([^"]*)"(.*)$/) { push(@ltok, $1); $line = $2; } elsif ($line =~ /^\s*([{};])(.*)$/) { push(@ltok, $1); $line = $2; } elsif ($line =~ /^\s*([^{}; \t]+)(.*)$/) { push(@ltok, $1); $line = $2; } else { last; } } foreach $t (@ltok) { push(@tok, $t); push(@lnum, $lnum); } $lnum++; }close(FILE);$lines_count{$_[0]} = $lnum;# parse tokens into data structures$i = 0; $j = 0;while($i < @tok) { $str = &parse_struct(\@tok, \@lnum, \$i, $j++, $_[0]); if ($str) { push(@rv, $str); } }# expand include directivesfor($i=0; $i<@rv; $i++) { if (lc($rv[$i]->{'name'}) eq "include" && !$_[1]) { # found one.. replace the include directive with it $ifile = $rv[$i]->{'value'}; if ($ifile !~ /^\//) { $ifile = &base_directory(\@rv)."/$ifile"; } @inc = &read_config_file($ifile, 1); # update index of included structures for($j=0; $j<@inc; $j++) { $inc[$j]->{'index'} += $rv[$i]->{'index'}; } # update index of structures after include for($j=$i+1; $j<@rv; $j++) { $rv[$j]->{'index'} += scalar(@inc) - 1; } splice(@rv, $i--, 1, @inc); } }return @rv;}# parse_struct(&tokens, &lines, &line_num, index, file)# A structure can either have one value, or a list of values.# Pos will end up at the start of the next structuresub parse_struct{local(%str, $i, $t, @vals, $str);$i = ${$_[2]};$str{'name'} = lc($_[0]->[$i]);$str{'line'} = $_[1]->[$i];while(1) { $t = $_[0]->[++$i]; if ($t eq "{" || $t eq ";" || $t eq "}") { last; } elsif (!defined($t)) { ${$_[2]} = $i; return undef; } else { push(@vals, $t); } }$str{'values'} = \@vals;$str{'value'} = $vals[0];$str{'index'} = $_[3];$str{'file'} = $_[4];if ($t eq "{") { # contains sub-structures.. parse them local(@mems, $j); $i++; # skip { $str{'type'} = 1; $j = 0; while($_[0]->[$i] ne "}") { if (!defined($_[0]->[$i])) { ${$_[2]} = $i; return undef; } $str = &parse_struct($_[0], $_[1], \$i, $j++, $_[4]); if ($str) { push(@mems, $str); } } $str{'members'} = \@mems; $i += 2; # skip trailing } and ; }else { # only a single value.. $str{'type'} = 0; if ($t eq ";") { $i++; # skip trailing ; } }$str{'eline'} = $_[1]->[$i-1]; # ending line is the line number the trailing # ; is on${$_[2]} = $i;return \%str;}# find(name, &array)sub find{local($c, @rv);foreach $c (@{$_[1]}) { if ($c->{'name'} eq $_[0]) { push(@rv, $c); } }return @rv ? wantarray ? @rv : $rv[0] : wantarray ? () : undef;}# find_value(name, &array)sub find_value{local(@v);@v = &find($_[0], $_[1]);if (!@v) { return undef; }elsif (wantarray) { return map { $_->{'value'} } @v; }else { return $v[0]->{'value'}; }}# base_directory([&config])# Returns the base directory for named filessub base_directory{local($opts, $dir, $conf);$conf = $_[0] ? $_[0] : &get_config();if (($opts = &find("options", $conf)) && ($dir = &find("directory", $opts->{'members'}))) { return $dir->{'value'}; }$config{'named_conf'} =~ /^(.*)\/[^\/]+$/;return $1;}# save_directive(&parent, name, &values, indent, [structonly])# Given a structure containing a directive name, type, values and members# add, update or remove that directive in config structure and data files.# Updating of files assumes that there is no overlap between directives -# each line in the config file must contain part or all of only one directive.sub save_directive{local(@oldv, @newv, $pm, $i, $o, $n, $lref, @nl);$pm = $_[0]->{'members'};@oldv = &find($_[1], $pm);@newv = @{$_[2]};for($i=0; $i<@oldv || $i<@newv; $i++) { if ($i >= @oldv) { # a new directive is being added.. put it at the end of # the parent if (!$_[4]) { $lref = &read_file_lines($_[0]->{'file'}); @nl = &directive_lines($newv[$i], $_[3]); splice(@$lref, $_[0]->{'eline'}, 0, @nl); $newv[$i]->{'file'} = $_[0]->{'file'}; $newv[$i]->{'line'} = $_[0]->{'eline'}; $newv[$i]->{'eline'} = $_[0]->{'eline'} + scalar(@nl) - 1; &renumber(&get_config(), $_[0]->{'eline'}, $_[0]->{'file'}, scalar(@nl)); } push(@$pm, $newv[$i]); } elsif ($i >= @newv) { # a directive was deleted if (!$_[4]) { $lref = &read_file_lines($oldv[$i]->{'file'}); $ol = $oldv[$i]->{'eline'} - $oldv[$i]->{'line'} + 1; splice(@$lref, $oldv[$i]->{'line'}, $ol); &renumber(&get_config(), $oldv[$i]->{'eline'}, $oldv[$i]->{'file'}, -$ol); } splice(@$pm, &indexof($oldv[$i], @$pm), 1); } else { # updating some directive if (!$_[4]) { $lref = &read_file_lines($oldv[$i]->{'file'}); @nl = &directive_lines($newv[$i], $_[3]); $ol = $oldv[$i]->{'eline'} - $oldv[$i]->{'line'} + 1; splice(@$lref, $oldv[$i]->{'line'}, $ol, @nl); $newv[$i]->{'file'} = $_[0]->{'file'}; $newv[$i]->{'line'} = $oldv[$i]->{'line'}; $newv[$i]->{'eline'} = $oldv[$i]->{'line'} + scalar(@nl) - 1; &renumber(&get_config(), $oldv[$i]->{'eline'}, $oldv[$i]->{'file'}, scalar(@nl) - $ol); } $pm->[&indexof($oldv[$i], @$pm)] = $newv[$i]; } }}# directive_lines(&directive, tabs)# Renders some directive into a number of lines of textsub directive_lines{local(@rv, $v, $m, $i);$rv[0] = "\t" x $_[1];$rv[0] .= "$_[0]->{'name'}";foreach $v (@{$_[0]->{'values'}}) { if ($need_quote{$_[0]->{'name'}} && !$i) { $rv[0] .= " \"$v\""; } else { $rv[0] .= " $v"; } $i++; }if ($_[0]->{'type'}) { # multiple values.. include them as well $rv[0] .= " {"; foreach $m (@{$_[0]->{'members'}}) { push(@rv, &directive_lines($m, $_[1]+1)); } push(@rv, ("\t" x ($_[1]+1))."}"); }$rv[$#rv] .= ";";return @rv;}# renumber(&directives, line, file, count)# Runs through the given array of directives and increases the line numbers# of all those greater than some line by the given countsub renumber{local($d);foreach $d (@{$_[0]}) { if ($d->{'file'} eq $_[2]) { if ($d->{'line'} > $_[1]) { $d->{'line'} += $_[3]; } if ($d->{'eline'} > $_[1]) { $d->{'eline'} += $_[3]; } } if ($d->{'type'}) { &renumber($d->{'members'}, $_[1], $_[2], $_[3]); } }}# choice_input(text, name, &config, [display, option]+)sub choice_input{local($rv, $v, $i, @ops);$rv = "<td><b>$_[0]</b></td> <td valign=top>";$v = &find_value($_[1], $_[2]);for($i=3; $i<@_; $i+=2) { $rv .= sprintf "<input type=radio name=%s value='%s' %s> %s\n", $_[1], $_[$i+1], $v eq $_[$i+1] ? "checked" : "", $_[$i]; }return $rv."</td>\n";}# save_choice(name, &parent, indent)sub save_choice{local($nd);if ($in{$_[0]}) { $nd = { 'name' => $_[0], 'values' => [ $in{$_[0]} ] }; }&save_directive($_[1], $_[0], $nd ? [ $nd ] : [ ], $_[2]);}# addr_match_input(text, name, &config)# A field for editing a list of addresses, ACLs and partial IP addressessub addr_match_input{local($v, $rv, $av, @av);$v = &find($_[1], $_[2]);$rv = "<td valign=top><b>$_[0]</b></td> <td valign=top>";$rv .= "<input type=radio name=$_[1]_def value=1 ". ($v ? "" : "checked")."> $text{'default'}";$rv .= "<input type=radio name=$_[1]_def value=0 ". ($v ? "checked" : "")."> $text{'listed'}<br>";foreach $av (@{$v->{'members'}}) { push(@av, $av->{'name'}); }$rv .= "<textarea name=$_[1] rows=3 cols=15>". join("\n", @av)."</textarea></td>\n";}sub save_addr_match{local($addr, @vals, $dir);if ($in{"$_[0]_def"}) { &save_directive($_[1], $_[0], [ ], $_[2]); }else { foreach $addr (split(/\s+/, $in{$_[0]})) { push(@vals, { 'name' => $addr }); } $dir = { 'name' => $_[0], 'type' => 1, 'members' => \@vals }; &save_directive($_[1], $_[0], [ $dir ], $_[2]); }}# address_input(text, name, &config, type)sub address_input{local($v, $rv, $av, @av);$v = &find($_[1], $_[2]);foreach $av (@{$v->{'members'}}) { push(@av, $av->{'name'}); }if ($_[3] == 0) { # text area $rv = "<td valign=top><b>$_[0]</b></td> <td valign=top>"; $rv .= "<textarea name=$_[1] rows=3 cols=15>". join("\n", @av)."</textarea></td>\n"; }else { $rv = "<td valign=top><b>$_[0]</b></td> <td colspan=3 valign=top>"; $rv .= "<input name=$_[1] size=50 value=\"".join(' ',@av)."\"></td>\n"; }return $rv;}sub save_address{local($addr, @vals, $dir);foreach $addr (split(/\s+/, $in{$_[0]})) { &check_ipaddress($addr) || &error(&text('eip', $addr)); push(@vals, { 'name' => $addr }); }$dir = { 'name' => $_[0], 'type' => 1, 'members' => \@vals };&save_directive($_[1], $_[0], @vals ? [ $dir ] : [ ], $_[2]);}# opt_input(text, name, &config, default, size, units)sub opt_input{local($v, $rv);$v = &find($_[1], $_[2]);$rv = "<td valign=top><b>$_[0]</b></td> <td nowrap valign=top";$rv .= $_[4] > 30 ? " colspan=3>\n" : ">\n";$rv .= sprintf "<input type=radio name=$_[1]_def value=1 %s> $_[3]\n", $v ? "" : "checked";$rv .= sprintf "<input type=radio name=$_[1]_def value=0 %s> ", $v ? "checked" : "";$rv .= sprintf "<input name=$_[1] size=$_[4] value=\"%s\"> $_[5]</td>\n", $v ? $v->{'value'} : "";return $rv;}sub save_opt{local($dir);if ($in{"$_[0]_def"}) { &save_directive($_[2], $_[0], [ ], $_[3]); }elsif ($err = &{$_[1]}($in{$_[0]})) { &error($err); }else { $dir = { 'name' => $_[0], 'values' => [ $in{$_[0]} ] }; &save_directive($_[2], $_[0], [ $dir ], $_[3]); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -