summaryrefslogtreecommitdiff
path: root/lib/Vyatta/ConfigOutput.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Vyatta/ConfigOutput.pm')
-rwxr-xr-xlib/Vyatta/ConfigOutput.pm374
1 files changed, 374 insertions, 0 deletions
diff --git a/lib/Vyatta/ConfigOutput.pm b/lib/Vyatta/ConfigOutput.pm
new file mode 100755
index 0000000..c45dff9
--- /dev/null
+++ b/lib/Vyatta/ConfigOutput.pm
@@ -0,0 +1,374 @@
+#!/usr/bin/perl
+
+# Author: An-Cheng Huang <ancheng@vyatta.com>
+# Date: 2007
+# Description: Perl module for generating output of the configuration.
+
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2006, 2007, 2008 Vyatta, Inc.
+# All Rights Reserved.
+# **** End License ****
+
+
+# outputNewConfig()
+# prints the "new" config, i.e., the active config with any un-committed
+# changes. 'diff' notation is also generated to indicate the changes.
+#
+# outputActiveConfig()
+# prints the "active" config. suitable for "saving", for example.
+
+package Vyatta::ConfigOutput;
+our @EXPORT = qw(setshow_all set_hide_password outputActiveConfig outputNewConfig);
+use base qw(Exporter);
+
+use strict;
+use lib '/opt/vyatta/share/perl5';
+use Vyatta::Config;
+
+use Sort::Versions;
+
+# whether to show default values
+my $show_all = 0;
+sub set_show_all {
+ if (shift) {
+ $show_all = 1;
+ }
+}
+
+my $hide_password = 0;
+sub set_hide_password {
+ if (shift) {
+ $hide_password = 1;
+ }
+}
+
+sub txt_need_quotes {
+ $_ = shift;
+ return 1 if (/^$/ || /[\s\*}{;]/);
+ return 0;
+}
+
+my $config = undef;
+
+# $0: array ref for path
+# $1: display prefix
+# $2: node name
+# $3: simple show (if defined, don't show diff prefix. used for "don't show as
+# deleted" from displayDeletedOrigChildren.)
+sub displayValues {
+ my @cur_path = @{$_[0]};
+ my $prefix = $_[1];
+ my $name = $_[2];
+ my $simple_show = $_[3];
+ my ($is_multi, $is_text, $default) = $config->parseTmpl(\@cur_path);
+ if ($is_text) {
+ $default =~ /^"(.*)"$/;
+ my $txt = $1;
+ if (!txt_need_quotes($txt)) {
+ $default = $txt;
+ }
+ }
+ my $is_password = ($name =~ /^.*(password|pre-shared-secret)$/);
+ my $HIDE_PASSWORD = '****************';
+ $config->setLevel(join ' ', @cur_path);
+ if ($is_multi) {
+ my @ovals = $config->returnOrigValues('');
+ my @nvals = $config->returnValues('');
+ if ($is_text) {
+ @ovals = map { (txt_need_quotes($_)) ? "\"$_\"" : "$_"; } @ovals;
+ @nvals = map { (txt_need_quotes($_)) ? "\"$_\"" : "$_"; } @nvals;
+ }
+ my $idx = 0;
+ my %ohash = map { $_ => ($idx++) } @ovals;
+ $idx = 0;
+ my %nhash = map { $_ => ($idx++) } @nvals;
+ my @dlist = map { if (!defined($nhash{$_})) { $_; } else { undef; } }
+ @ovals;
+ if (defined($simple_show)) {
+ foreach my $oval (@ovals) {
+ if ($is_password && $hide_password) {
+ $oval = $HIDE_PASSWORD;
+ }
+ print "$prefix$name $oval\n";
+ }
+ return;
+ }
+ foreach my $del (@dlist) {
+ if (defined($del)) {
+ if ($is_password && $hide_password) {
+ $del = $HIDE_PASSWORD;
+ }
+ print "-$prefix$name $del\n";
+ }
+ }
+ foreach my $nval (@nvals) {
+ my $diff = '+';
+ if (defined($ohash{$nval})) {
+ if ($ohash{$nval} != $nhash{$nval}) {
+ $diff = '>';
+ } else {
+ $diff = ' ';
+ }
+ }
+ if ($is_password && $hide_password) {
+ $nval = $HIDE_PASSWORD;
+ }
+ print "$diff$prefix$name $nval\n";
+ }
+ } else {
+ my $oval = $config->returnOrigValue('');
+ my $nval = $config->returnValue('');
+ if ($is_text) {
+ if (defined($oval) && txt_need_quotes($oval)) {
+ $oval = "\"$oval\"";
+ }
+ if (defined($nval) && txt_need_quotes($nval)) {
+ $nval = "\"$nval\"";
+ }
+ }
+
+ my %cnodes = $config->listNodeStatus();
+ my @cnames = sort keys %cnodes;
+
+ if (defined($simple_show)) {
+ if (!$cnodes{'def'} || $show_all) {
+ if ($is_password && $hide_password) {
+ $oval = $HIDE_PASSWORD;
+ }
+ print "$prefix$name $oval\n";
+ }
+ return;
+ }
+ my $value = $nval;
+ my $diff = ' ';
+ if (!defined($oval) && defined($nval)) {
+ $diff = '+';
+ } elsif (!defined($nval) && defined($oval)) {
+ $diff = '-';
+ $value = $oval;
+ } else {
+ # both must be defined
+ if ($oval ne $nval) {
+ $diff = '>';
+ }
+ }
+ if (!$cnodes{'def'} || $show_all) {
+ if ($is_password && $hide_password) {
+ $value = $HIDE_PASSWORD;
+ }
+ print "$diff$prefix$name $value\n";
+ }
+ }
+}
+
+# $0: array ref for path
+# $1: display prefix
+# $2: don't show as deleted? (if defined, config is shown as normal instead of
+# deleted.)
+sub displayDeletedOrigChildren {
+ my @cur_path = @{$_[0]};
+ my $prefix = $_[1];
+ my $dont_show_as_deleted = $_[2];
+ my $dprefix = '-';
+ if (defined($dont_show_as_deleted)) {
+ $dprefix = '';
+ }
+ $config->setLevel('');
+ my @children = $config->listOrigNodes(join ' ', @cur_path);
+ for my $child (sort @children) {
+ if ($child eq 'node.val') {
+ # should not happen!
+ next;
+ }
+ my $is_tag = $config->isTagNode([ @cur_path, $child ]);
+ $config->setLevel(join ' ', (@cur_path, $child));
+ my @cnames = sort $config->listOrigNodesNoDef();
+
+ if ($cnames[0] eq 'node.val') {
+ displayValues([ @cur_path, $child ], $prefix, $child,
+ $dont_show_as_deleted);
+ } elsif ($cnames[0] eq 'def') {
+ #ignore
+ } elsif (scalar($#cnames) >= 0) {
+ if ($is_tag) {
+ @cnames = sort versioncmp @cnames;
+ foreach my $cname (@cnames) {
+ if ($cname eq 'node.val') {
+ # should not happen
+ next;
+ }
+ print "$dprefix$prefix$child $cname {\n";
+ displayDeletedOrigChildren([ @cur_path, $child, $cname ],
+ "$prefix ", $dont_show_as_deleted);
+ print "$dprefix$prefix}\n";
+ }
+ } else {
+ print "$dprefix$prefix$child {\n";
+ displayDeletedOrigChildren([ @cur_path, $child ], "$prefix ",
+ $dont_show_as_deleted);
+ print "$dprefix$prefix}\n";
+ }
+ } else {
+ my $has_tmpl_children = $config->hasTmplChildren([ @cur_path, $child ]);
+ print "$dprefix$prefix$child"
+ . ($has_tmpl_children ? " {\n$dprefix$prefix}\n" : "\n");
+ }
+ }
+}
+
+# $0: hash ref for children status
+# $1: array ref for path
+# $2: display prefix
+sub displayChildren {
+ my %child_hash = %{$_[0]};
+ my @cur_path = @{$_[1]};
+ my $prefix = $_[2];
+ for my $child (sort (keys %child_hash)) {
+ if ($child eq 'node.val') {
+ # should not happen!
+ next;
+ }
+ my ($diff, $vdiff) = (' ', ' ');
+ if ($child_hash{$child} eq 'added') {
+ $diff = '+';
+ $vdiff = '+';
+ } elsif ($child_hash{$child} eq 'deleted') {
+ $diff = '-';
+ $vdiff = '-';
+ } elsif ($child_hash{$child} eq 'changed') {
+ $vdiff = '>';
+ }
+ my $is_tag = $config->isTagNode([ @cur_path, $child ]);
+ $config->setLevel(join ' ', (@cur_path, $child));
+ my %cnodes = $config->listNodeStatus();
+ my @cnames = sort keys %cnodes;
+
+ #if node.val exists and ct == 0 w/o def or ct ==1 w/ def
+ my $leaf = 0;
+ if ($cnodes{'def'}) {
+ if ($#cnames == 1 && $cnodes{'node.val'}) {
+ $leaf = 1;
+ }
+ } else {
+ if ($#cnames == 0 && $cnodes{'node.val'}) {
+ $leaf = 1;
+ }
+ }
+
+ if ($leaf == 1) {
+ displayValues([ @cur_path, $child ], $prefix, $child);
+ } elsif (scalar($#cnames) >= 0) {
+ if ($is_tag) {
+ @cnames = sort versioncmp @cnames;
+ foreach my $cname (@cnames) {
+ if ($cname eq 'node.val') {
+ # should not happen
+ next;
+ }
+ my $tdiff = ' ';
+ if ($cnodes{$cname} eq 'deleted') {
+ $tdiff = '-';
+ } elsif ($cnodes{$cname} eq 'added') {
+ $tdiff = '+';
+ }
+ print "$tdiff$prefix$child $cname {\n";
+ if ($cnodes{$cname} eq 'deleted') {
+ displayDeletedOrigChildren([ @cur_path, $child, $cname ],
+ "$prefix ");
+ } else {
+ $config->setLevel(join ' ', (@cur_path, $child, $cname));
+ my %ccnodes = $config->listNodeStatus();
+ displayChildren(\%ccnodes, [ @cur_path, $child, $cname ],
+ "$prefix ");
+ }
+ print "$tdiff$prefix}\n";
+ }
+ } else {
+ print "$diff$prefix$child {\n";
+ if ($child_hash{$child} eq 'deleted') {
+ # this should not happen
+ displayDeletedOrigChildren([ @cur_path, $child ], "$prefix ");
+ } else {
+ displayChildren(\%cnodes, [ @cur_path, $child ], "$prefix ");
+ }
+ print "$diff$prefix}\n";
+ }
+ } else {
+ if ($child_hash{$child} eq 'deleted') {
+ $config->setLevel('');
+ my @onodes = $config->listOrigNodes(join ' ', (@cur_path, $child));
+ if ($#onodes == 0 && $onodes[0] eq 'node.val') {
+ displayValues([ @cur_path, $child ], $prefix, $child);
+ } else {
+ print "$diff$prefix$child {\n";
+ displayDeletedOrigChildren([ @cur_path, $child ], "$prefix ");
+ print "$diff$prefix}\n";
+ }
+ } else {
+ my $has_tmpl_children
+ = $config->hasTmplChildren([ @cur_path, $child ]);
+ print "$diff$prefix$child"
+ . ($has_tmpl_children ? " {\n$diff$prefix}\n" : "\n");
+ }
+ }
+ }
+}
+
+# @ARGV: represents the 'root' path. the output starts at this point under
+# the new config.
+sub outputNewConfig {
+ $config = new Vyatta::Config;
+ $config->setLevel(join ' ', @_);
+ my %rnodes = $config->listNodeStatus();
+ if (scalar(keys %rnodes) > 0) {
+ my @rn = keys %rnodes;
+
+ #if node.val exists and ct == 0 w/o def or ct ==1 w/ def
+ my $leaf = 0;
+ if ($rnodes{'def'}) {
+ if ($#rn == 1 && $rnodes{'node.val'}) {
+ $leaf = 1;
+ }
+ } else {
+ if ($#rn == 0 && $rnodes{'node.val'}) {
+ $leaf = 1;
+ }
+ }
+
+ if ($leaf == 1) {
+ # this is a leaf value-node
+ displayValues([ @_ ], '', $_[$#_]);
+ } else {
+ displayChildren(\%rnodes, [ @_ ], '');
+ }
+ } else {
+ if (defined($config->existsOrig()) && !defined($config->exists())) {
+ # this is a deleted node
+ print 'Configuration under "' . (join ' ', @_) . "\" has been deleted\n";
+ } elsif (!defined($config->getTmplPath(\@_))) {
+ print "Specified configuration path is not valid\n";
+ } else {
+ print 'Configuration under "' . (join ' ', @_) . "\" is empty\n";
+ }
+ }
+}
+
+# @ARGV: represents the 'root' path. the output starts at this point under
+# the active config.
+sub outputActiveConfig {
+ $config = new Vyatta::Config;
+ $config->setLevel(join ' ', @_);
+ displayDeletedOrigChildren([ @_ ], '', 1);
+}
+
+1;