#!/usr/bin/perl -w use strict; use Fcntl qw(:DEFAULT :flock); use Symbol qw(gensym); use Getopt::Std; use IO::File; use File::Basename; use Cwd; use vars qw/$opt_a $opt_b $opt_d $opt_e $opt_h $opt_m $opt_o $opt_q/; my $zonefile_suffixi_default = "file"; my $outfile_default = "data_dns"; my $out_data_file = "nsdata.txt"; ## - hashes to store the records at all, but also ## - domains, maildomains and the defined hosts ## - my %doms = (); my %maildoms = (); my %hosts = () ; my %records = () ; ## - filehandle ## - my $fh = new IO::File ; getopts('ab:d:e:hmo:q') || &usage(); &usage if defined $opt_h ; my $i; if (! defined $opt_q) { print "\n command invoked: $0"; foreach $i (@ARGV) { print " $i"; } print "\n\n"; } my $backup = defined($opt_b) ? $opt_b : 1; if ( $backup != 1 && $backup != 0 ) { print "\n wrong value for flag -b : $opt_b"; &usage; } exit ( &main(@ARGV) ); sub main { my $infile = shift || return usage(); -f $infile or die "$infile: $!"; my $base_infile = basename($infile); my ($line, $filename); my ( @lines, @data_file_lines, @single_file_lines ); my ( @domains, @maildomains, @hostlist, @records ); my ( $extension, $outdir, $outfile, $multiple_files, $add_files ); ## - look at the programm parameters ## - $extension = defined($opt_e) ? $opt_e : $zonefile_suffixi_default; $outdir = defined($opt_d) ? $opt_d : "./"; ## - like to work with the realpath ## - $outdir = Cwd::abs_path($outdir); ## $outdir =~ s#^(.*)/$#$1#; $outfile = defined($opt_o) ? $opt_o : $outfile_default; $outfile = $outdir . "/" . $outfile; $multiple_files = defined($opt_m) ? 1 : 0; $add_files = defined($opt_a) ? 1 : 0; ## - Datei einlesen ## - if ( $fh->open($infile) ) { flock( $fh, LOCK_SH ); chomp (@lines = <$fh>); flock( $fh, LOCK_UN ); $fh->close(); } else { die "can't open $! for read"; } ## oder so.. ## - ## open( $fh ,$infile ) or die "can't open $! for read" ; ## flock( $fh, LOCK_SH ); ## @lines = <$fh>; ## flock( $fh, LOCK_UN ); ## close ( $fh ); ## - sichere original file ## - &write_file($outdir . "/" . $base_infile,@lines); ## - first we push into hashes, so we can sort ## - afterwords ## - foreach (@lines) { ## chomp ; ## - ignore emty lines ## - next if /^\s*$/o ; ## - ignore comments ## - next if /^#/o ; $records{$_} = 1 ; if ( /^([\.|\&|Z])([^:]*)(.*)$/o ) { $doms{$2} = 1 ; } ## - maildomain ? ## - if ( /^(\@)([^:]*)(.*)/o) { $maildoms{$2} = 1; } ## - host definition ? ## - if ( /^(\+)([^:]*)(.*)/o) { $hosts{$2} = 1; } } ## - Now sort and put into the considered arrays ## - @domains = sort ( keys %doms ) ; @maildomains = sort ( keys %maildoms ) ; @hostlist = sort ( keys %hosts ) ; @records = sort ( sort_records keys %records); ## - schreibe domainliste, maildomainliste, hostliste, records ## - if ( $add_files ) { &write_file($outdir . "/domains.lst",@domains); &write_file($outdir . "/maildomains.lst",@maildomains); &write_file($outdir . "/hostlist.lst",@hostlist); &write_file($outdir . "/records.lst",@records); } my $_domain =""; my $_type; my $_filename = 0; foreach ( @records ) { /(.)([^:]+).*/o ; if ( $_domain eq get_domain($2) ) { if ( $_type ne $1 ) { if ( $multiple_files ) { push ( @single_file_lines, get_record_comment($1) ); } else { push ( @data_file_lines, get_record_comment($1) ); } } if ( $multiple_files ) { push ( @single_file_lines, $_ ); } else { push ( @data_file_lines, $_ ); } } else { &write_file($filename,@single_file_lines) if ($filename); @single_file_lines = (); $_type = ""; $_domain = get_domain($2); if ( $multiple_files ) { $filename = $outdir . "/" . $_domain . ".file"; push ( @single_file_lines, "## - domain: $_domain"); push ( @single_file_lines, "## - "); push ( @single_file_lines, get_record_comment($1) ); push ( @single_file_lines, $_ ); } else { push ( @data_file_lines, "\n" ); push ( @data_file_lines, "## - domain: $_domain"); push ( @data_file_lines, "## - "); push ( @data_file_lines, get_record_comment($1) ); push ( @data_file_lines, $_ ); } } $_type = $1; } if ( $multiple_files ) { ## - letztes file muss noch geschrieben werdem ## - &write_file($filename, @single_file_lines); } else { ## - schreibe alles in ein file ## - &write_file($outfile, @data_file_lines); } exit 0 } sub get_domain { my $record = shift ; if ( $doms{$record} ) { return $record ; } else { while ( $record =~ /([^\.]*).(.*)/o ) { if ( $doms{$2} ) { return $2; } $record = $2; } } return 1 ; } sub get_record_comment { my $directive_type = shift; my $comment; SWITCH : { $1 eq "Z" and $comment = "## - SOA" , last SWITCH; $1 eq "." and $comment = "## - SOA, NS, A" , last SWITCH; $1 eq "&" and $comment = "## - NS, A" , last SWITCH; $1 eq "@" and $comment = "## - MX, A" , last SWITCH; $1 eq "=" and $comment = "## - A, PTR" , last SWITCH; $1 eq "+" and $comment = "## - A" , last SWITCH; $1 eq "C" and $comment = "## - CNAME" , last SWITCH; $1 eq "^" and $comment = "## - PTR" , last SWITCH; $1 eq "'" and $comment = "## - TEXT" , last SWITCH; $1 eq "3" and $comment = "## - AAAA" , last SWITCH; $1 eq "6" and $comment = "## - AAAA, PTR" , last SWITCH; $comment = "## - unknown record"; } return $comment; } # Datei schreiben # sub write_file { my $outfile = shift ; my @lines = @_ ; backup($outfile) if ( -f $outfile ); if (! defined $opt_q) { print "\twrite $outfile ..\n"; } $fh = new IO::File "> $outfile"; if (defined $fh) { foreach (@lines) { print $fh $_ . "\n" ; } $fh->close(); } ## - oder auch so.. ## - ## open ( $fh , "> $outfile") or die "can't open $! for write" ; ## print $fh @lines ; ## close ($fh); } # # - backup # sub backup { my $filename = shift ; # Sicherungskopie erstellen # if ($backup) { OUTER: for ( my $i = 0 ; $i < 10 ; $i++ ) { for ( my $j = 0 ; $j < 10 ; $j++ ) { my $backupfile = $filename . ".$i$j" ; if ( -f $backupfile || -d $backupfile || -l $backupfile || -p $backupfile || -c $backupfile || -b $backupfile || -S $backupfile ) { next ; } else { my $retval = system( "cp -f $filename $backupfile") ; if ($retval != 0) { die "can't store backupfile $backupfile" } if (! defined $opt_q) { print "\n\tbackupfile stored in $backupfile\n"; } last OUTER ; } } } # ende OUTER : for ( ... } # ende if } # end backup() sub sort_records { my ( $rval1, $rval2, $domain_a, $domain_b, $directive_a, $directive_b ); $a =~ /(.)([^:]+).*/; ## - get directive ## - SWITCH : { $1 eq "Z" and $directive_a = 10 , last SWITCH; $1 eq "." and $directive_a = 20 , last SWITCH; $1 eq "&" and $directive_a = 30 , last SWITCH; $1 eq "@" and $directive_a = 40 , last SWITCH; $1 eq "=" and $directive_a = 50 , last SWITCH; $1 eq "+" and $directive_a = 60 , last SWITCH; $1 eq "C" and $directive_a = 70 , last SWITCH; $1 eq "^" and $directive_a = 80 , last SWITCH; $1 eq "'" and $directive_a = 90 , last SWITCH; $1 eq "3" and $directive_a = 100, last SWITCH; $1 eq "6" and $directive_a = 110, last SWITCH; $directive_a = 999; } ## - get domain.. ## - $domain_a = get_domain($2); $b =~ /(.)([^:]+).*/; ## - get directive ## - SWITCH : { $1 eq "Z" and $directive_b = 10 , last SWITCH; $1 eq "." and $directive_b = 20 , last SWITCH; $1 eq "&" and $directive_b = 30 , last SWITCH; $1 eq "@" and $directive_b = 40 , last SWITCH; $1 eq "=" and $directive_b = 50 , last SWITCH; $1 eq "+" and $directive_b = 60 , last SWITCH; $1 eq "C" and $directive_b = 70 , last SWITCH; $1 eq "^" and $directive_b = 80 , last SWITCH; $1 eq "'" and $directive_b = 90 , last SWITCH; $1 eq "3" and $directive_b = 100, last SWITCH; $1 eq "6" and $directive_b = 110, last SWITCH; $directive_b = 999; } ## - get domain.. ## - $domain_b = get_domain($2); $rval1 = $domain_a cmp $domain_b ; if ( $rval1 == 0 ) { $rval2 = $directive_a <=> $directive_b; if ( $rval2 == 0 ) { return $a cmp $b; } else { return $rval2; } } else { return $rval1; } } # # - usage # sub usage { my $file = basename($0); $file =~ s#.*/([^/]+)$#$1# ; print < This script concatinates all zonefiles with a certain fileextension of a given directory. This script takes all directives from a given djb tinydns-data-file, sorts them and put the sortet list back into one data-file or, if option "m" is set into one file for each domain, named by the concerning domain. A copy of the (original) inputfile will be written out in . Control Options: -a The following addition files be written: /domains.lst.......: alphabetical list of domains /maildomains.lst...: alphabetical list of domains with MX entry /hostlist.lst......: alphabetical list of all hostentries (A - Record) /records.lst.......: all records sorted by domain but without any comment or emty line -b <0|1> a value of "1" means: befor writing a file backup existing one; dont backup if "0". default value is "1" -d directory where the outfile(s) are written. defaults to working directory -e write data-files with extension . defaults to "$zonefile_suffixi_default". only affected if option -m is set -h prints this helpcontents -m write one file for each domain -o name of outputfile. defaults to "$outfile_default". only affect if not -m is set -q silent output ENDE exit 1 ; }