#!/usr/bin/perl use strict; use warnings; =head1 NAME extractDS.px - Extract a single data-source from an RRD-file =head1 SYNOPSYS extractDS.px -i input.rrd -s source_ds -o output.rrd -d destination_ds =head1 DEPENDENCIES extractDS.px requires Perl and the included L module, as well as the L module. =cut use Getopt::Long ('GetOptions'); use Data::Dumper (); our $InFile; our $InDS = []; our $OutFile; our $OutDS = []; GetOptions ("infile|i=s" => \$InFile, "inds|s=s" => sub { push (@$InDS, $_[1]); }, "outfile|o=s" => \$OutFile, "outds|d=s" => sub { push (@$OutDS, $_[1]); }) or exit (1); if (!$InFile || !$OutFile || !@$InDS || !@$OutDS) { print STDERR "Usage: $0 -i -s -o -d \n"; exit (1); } if (!-f $InFile) { print STDERR "Input file does not exist\n"; exit (1); } if (-f $OutFile) { print STDERR "Output file does exist\n"; exit (1); } if ((1 + @$InDS) != (1 + @$OutDS)) { print STDERR "You need the same amount of in- and out-DSes\n"; exit (1); } extract_ds ($InFile, $OutFile); exit (0); { my $ds_index; my $current_index; # state 0 == searching for DS index # state 1 == parse RRA header # state 2 == parse values my $state; my $out_cache; sub handle_line { my $fh = shift; my $line = shift; if (!defined ($state)) { $current_index = -1; $state = 0; $out_cache = []; # $ds_index->[new_index] = old_index $ds_index = []; for (my $i = 0; $i < @$InDS; $i++) { $ds_index->[$i] = -1; } } if ($state == 0) { if ($line =~ m//) { $current_index++; $out_cache->[$current_index] = $line; } elsif ($line =~ m#\s*([^<\s]+)\s*#) { # old_index == $current_index # new_index == $i for (my $i = 0; $i < @$InDS; $i++) { next if ($ds_index->[$i] >= 0); if ($1 eq $InDS->[$i]) { $line =~ s#\s*([^<\s]+)\s*# $OutDS->[$i] #; $ds_index->[$i] = $current_index; last; } } $out_cache->[$current_index] .= $line; } elsif ($line =~ m##) { $out_cache->[$current_index] .= $line; } elsif ($line =~ m##) { # Print out all the DS definitions we need for (my $new_index = 0; $new_index < @$InDS; $new_index++) { my $old_index = $ds_index->[$new_index]; print $fh $out_cache->[$old_index]; } # Clear the cache - it's used in state1, too. for (my $i = 0; $i <= $current_index; $i++) { $out_cache->[$i] = ''; } print $fh $line; $current_index = -1; $state = 1; } elsif ($current_index == -1) { # Print all the lines before the first DS definition print $fh $line; } else { # Something belonging to a DS-definition $out_cache->[$current_index] .= $line; } } elsif ($state == 1) { if ($line =~ m##) { $current_index++; $out_cache->[$current_index] .= $line; } elsif ($line =~ m##) { # Print out all the DS definitions we need for (my $new_index = 0; $new_index < @$InDS; $new_index++) { my $old_index = $ds_index->[$new_index]; print $fh $out_cache->[$old_index]; } # Clear the cache for (my $i = 0; $i <= $current_index; $i++) { $out_cache->[$i] = ''; } print $fh $line; $current_index = -1; } elsif ($line =~ m##) { print $fh $line; $state = 2; } elsif ($current_index == -1) { # Print all the lines before the first DS definition # and after cdp_prep print $fh $line; } else { # Something belonging to a DS-definition $out_cache->[$current_index] .= $line; } } elsif ($state == 2) { if ($line =~ m##) { print $fh $line; $current_index = -1; $state = 1; } else { my @values = (); my $i; my $output = "\t\t"; if ($line =~ m#()#) { $output .= "$1 "; } $output .= " "; $i = 0; while ($line =~ m#\s*([^<\s]+)\s*#g) { $values[$i] = $1; $i++; } for (my $new_index = 0; $new_index < @$InDS; $new_index++) { my $old_index = $ds_index->[$new_index]; $output .= ' ' . $values[$old_index] . ' '; } $output .= "\n"; print $fh $output; } } else { die; } }} # handle_line sub extract_ds { my $in_file = shift; my $out_file = shift; my $in_fh; my $out_fh; open ($in_fh, '-|', 'rrdtool', 'dump', $in_file) or die ("open (rrdtool): $!"); open ($out_fh, '|-', 'rrdtool', 'restore', '-', $out_file) or die ("open (rrdtool): $!"); while (my $line = <$in_fh>) { handle_line ($out_fh, $line); } close ($in_fh); close ($out_fh); } # extract_ds =head1 AUTHOR Florian octo Forster Eocto at verplant.orgE