7 my($VERSION) = q$Revision$ =~ /:\s*(\d+(?:\.\d+)?)/;
13 Usage for rvi $VERSION:
15 $0 [-r] [+] [-] filename...
17 -r Enter RCS description
18 + auto-increment SOA serial number (default)
19 - do NOT auto-increment SOA serial number.
24 $ENV{EDITOR} = "vi" unless exists $ENV{EDITOR};
26 my $autoinc = 1; # now default
30 my $egid = (split(/\s+/,$)))[0];
31 my $user = getlogin() || $ENV{USER} || getpwuid($<);
33 my $namedpath = "/usr/local/etc/named";
35 if ($ENV{RVI_AUTO_NDC_RELOAD} or $ENV{RVI_AUTO_NDC_RECONFIG}) {
36 $ndc = which("ndc") or exit 1;
38 my $ci = which("ci") or exit 1;
39 my $co = which("co") or exit 1;
40 my $cmp = which("cmp") or exit 1;
41 my $rcsdiff = which("rcsdiff") or exit 1;
44 $ARGV[0] eq "+" && do {
49 $ARGV[0] eq "-" && do {
54 $ARGV[0] eq "-r" && do {
62 my($file, %serial, %origfile, %checked, %fileinfo, %rcsinfo);
67 foreach $file ( @ARGV ) {
68 my $fullname = makefullname($wd, $file);
69 ($fileinfo{$file}, $rcsinfo{$file}) = getinfo($fullname);
70 if ($rcsinfo{$file}->{'exists'}) {
71 unless (execute_ok($rcsdiff,"-c",$file)) {
72 warn "$file would change when checking out of RCS!\n";
75 unless (execute_ok($co,"-l",$file)) {
82 # Begin magic incrementing of serial no.
83 if ( $fullname =~ m-^$namedpath-o && $fileinfo{$file}->{readable} ) {
84 checkDNS($file, $fullname, $file, 2);
88 execute_ok($ENV{EDITOR},@ARGV);
90 FILE: foreach $file ( keys %serial ) {
91 unless (execute_ok($cmp,"-s",$origfile{$file},"$origfile{$file}.tmp")) {
92 if ( ! exists $checked{$file} && $autoinc ) {
93 if (execute_ok($co,"-l",$file)) {
95 ($fileinfo{$file}, $rcsinfo{$file})
96 = getinfo(makefullname($wd,$file));
99 warn "You'll have to update the serial number yourself.\n";
104 $fileinfo{$file}->{changed} = 1;
109 my($reconfig,@zones);
110 foreach $file ( keys %checked ) {
114 execute_ok($ci,"-u",$file);
117 open(CI, "|$ci -u $file") or die("Cannot fork $ci: $!\n");
118 print CI "updated by $user on " . (localtime) . "\n";
121 warn "WARNING: $ci -u $file returned error: ", $?/256, "\n";
125 delete $checked{$file};
127 if ($rcsinfo{$file}->{'exists'}
128 and $rcsinfo{$file}->{uid} != $euid
129 || $rcsinfo{$file}->{gid} != $egid) {
130 chown $rcsinfo{$file}->{uid}, $rcsinfo{$file}->{gid},
131 $file, $rcsinfo{$file}->{file};
134 if ($ENV{RVI_AUTO_NDC_RECONFIG}) {
135 if ($fileinfo{$file}->{changed} and $fileinfo{$file}->{src}) {
139 if ($ENV{RVI_AUTO_NDC_RELOAD}) {
140 if ($fileinfo{$file}->{changed} and $fileinfo{$file}->{zone}) {
141 push @zones, $fileinfo{$file}->{zone};
147 execute_ok($ndc,"reconfig") if $reconfig;
148 foreach my $zone (@zones) {
149 warn "Reloading $zone:\n";
150 execute_ok($ndc,"reload",$zone);
155 my($file, $fullname, $origfile, $maxrecurse) = @_;
156 my($count, $dir, $which, $command, @files);
158 open(FILE, $file) or die("Cannot open $file: $!\n");
161 if ( /^\@\s+IN\s+SOA\s+\S+\s+\S+\s+\(\s*$/i ) {
166 $origfile{$file} = $origfile;
167 copy($origfile,"$origfile.tmp");
171 last if ++$count > 10;
174 if ( $maxrecurse > 0 && ! exists $serial{$file} ) {
175 # not found, try if we're included somewhere...
176 $fullname =~ s-^$namedpath/--o;
177 ($dir = $file) =~ s-[^/]*$--;
179 @files = grep { !/~$/ && -f && -T } < $dir >;
180 $command = "grep -li \'\$INCLUDE *$fullname\' " . join(" ", @files);
182 @files = split(' ', $which);
184 $fullname = makefullname($wd, $files[0]);
185 checkDNS($files[0], $fullname, $origfile, $maxrecurse - 1);
194 open(FILE, $file) or die("Cannot open $file: $!\n");
197 if ( /^\@\s+IN\s+SOA\s+\S+\s+\S+\s+\(\s*$/i ) {
202 if ( $1 < $serial{$file} ) {
203 warn "You LOWERED the serial number for $file. Why?\n";
205 elsif ( $1 > $serial{$file} ) {
207 "I see you updated the serial number yourself. Stoer!\n";
215 last if ++$count > 10;
217 warn "What did you do to the serial number?\n";
223 my($serial, $new_serial);
226 if ( $autoinc == 0 ) {
227 warn "You should update the serial number in $file.\n";
230 use POSIX 'strftime';
231 warn "Automatically updating the serial number in $file for you.\n";
232 open(FILE, $file) or die("Cannot open $file: $!\n");
233 open(NEW, ">$file.magicinc") or die("Cannot write $file.magicinc: $!\n");
236 if ( ! $hadSOA && /^\@\s+IN\s+SOA\s+\S+\s+\S+\s+\(\s*$/i ) {
239 unless ( /^(\s*)\d+([\w\W]*)$/ ) {
240 die("Aargh! internal error, stop");
242 $new_serial = strftime ("%Y%m%d", localtime()) . "01";
243 $serial = "" . $serial{$file};
244 if ($new_serial > $serial) {
245 $serial = $new_serial;
249 print NEW $1 . $serial . $2;
253 close(NEW) or die("Aargh! closing $file.magicinc: $!\n");
254 unlink($file) or die("Aargh! unlink $file: $!\n");
255 rename("$file.magicinc", $file) or die("Aargh! rename $file: $!\n");
262 if ( $file =~ m-^/- ) {
266 $fullname = "$wd/$file";
268 1 while $fullname =~ s-[^/]+/\.\./--;
274 my($fileinfo,$rcsinfo);
277 unless ( ($path, $name) = $file =~ m-^(.*)/([^/]*)$- ) {
281 $fileinfo->{name} = $name;
282 if ($path =~ m-^$namedpath/(primary|secondary)-o) {
283 $fileinfo->{zone} = $name;
285 elsif ($path =~ m-^$namedpath/reverse-o) {
286 ($fileinfo->{zone}) = $name =~ /^(\d+\.\d+\.\d+)/;
287 $fileinfo->{zone} .= ".in-addr.arpa";
289 elsif ($path =~ m-^$namedpath/src-o) {
290 $fileinfo->{src} = 1;
293 $rcsinfo->{file} = "$path/RCS/$name,v";
294 if ( -f $rcsinfo->{file} ) {
295 $rcsinfo->{'exists'} = 1;
296 $rcsinfo->{uid} = (stat(_))[4];
297 $rcsinfo->{gid} = (stat(_))[5];
299 elsif ( ! -d "$path/RCS" ) {
300 warn "WARNING: There is no $path/RCS directory!\n";
305 unless ($rcsinfo->{'exists'}) {
306 warn "WARNING: $file already exists but is not in RCS!\n";
307 warn "Manually check it in if you want it to be in RCS.\n";
310 $fileinfo->{mode} = (stat(_))[2];
311 $fileinfo->{readable} = -r _;
314 return $fileinfo, $rcsinfo;
318 if ( keys %checked ) {
319 warn "Cleaning up the mess...\n";
320 foreach my $file ( keys %checked ) {
321 if ($fileinfo{$file}->{mode}) {
322 chmod $fileinfo{$file}->{mode} & 07577, $file;
324 if ($rcsinfo{$file}->{'exists'}) {
325 execute_ok($co,"-u",$file);
326 if ($rcsinfo{$file}->{uid} != $euid
327 or $rcsinfo{$file}->{gid} != $egid) {
328 chown $rcsinfo{$file}->{uid}, $rcsinfo{$file}->{gid},
329 $file, $rcsinfo{$file}->{file};
339 my $ret = system(@command) / 256;
340 unless ($command[0] eq $cmp) {
341 warn "WARNING: @command returned $ret\n" if $ret;
348 my($fullprog) = grep { -x } (
349 "/usr/local/bin/$prog",
351 "/usr/local/sbin/$prog",
353 ) or warn "WARNING: cannot find $prog\n";