summaryrefslogtreecommitdiff
path: root/lib/Vyatta
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2010-07-28 14:30:32 -0700
committerAn-Cheng Huang <ancheng@vyatta.com>2010-07-28 14:30:32 -0700
commit639c835bc2730a4fbffd915f5b2028a68375ee7a (patch)
tree203d61e1d5e8ef422d6aba3851d2f83a1f838b6b /lib/Vyatta
parent0247864ef578ac05bbac8dc5175e674ce7b82714 (diff)
downloadvyatta-cfg-639c835bc2730a4fbffd915f5b2028a68375ee7a.tar.gz
vyatta-cfg-639c835bc2730a4fbffd915f5b2028a68375ee7a.zip
add new cstore library
Diffstat (limited to 'lib/Vyatta')
-rwxr-xr-xlib/Vyatta/Config.pm1309
-rwxr-xr-xlib/Vyatta/ConfigDOMTree.pm366
-rwxr-xr-xlib/Vyatta/ConfigLoad.pm23
-rwxr-xr-xlib/Vyatta/ConfigOutput.pm230
4 files changed, 638 insertions, 1290 deletions
diff --git a/lib/Vyatta/Config.pm b/lib/Vyatta/Config.pm
index 8bcd84f..8067e05 100755
--- a/lib/Vyatta/Config.pm
+++ b/lib/Vyatta/Config.pm
@@ -21,16 +21,14 @@ package Vyatta::Config;
use strict;
-use Vyatta::ConfigDOMTree;
use File::Find;
+use lib '/opt/vyatta/share/perl5';
+use Cstore;
+
my %fields = (
- _changes_only_dir_base => $ENV{VYATTA_CHANGES_ONLY_DIR},
- _new_config_dir_base => $ENV{VYATTA_TEMP_CONFIG_DIR},
- _active_dir_base => $ENV{VYATTA_ACTIVE_CONFIGURATION_DIR},
- _vyatta_template_dir => $ENV{VYATTA_CONFIG_TEMPLATE},
- _current_dir_level => "/",
_level => undef,
+ _cstore => undef,
);
sub new {
@@ -39,892 +37,546 @@ sub new {
my $self = {
%fields,
};
-
bless $self, $class;
+ $self->{_cstore} = new Cstore();
return $self;
}
-sub _set_current_dir_level {
- my ($self) = @_;
- my $level = $self->{_level};
-
- $level =~ s/\//%2F/g;
- $level =~ s/\s+/\//g;
-
- $self->{_current_dir_level} = "/$level";
- return $self->{_current_dir_level};
+sub get_path_comps {
+ my ($self, $pstr) = @_;
+ $pstr = '' if (!defined($pstr));
+ $pstr = "$self->{_level} $pstr" if (defined($self->{_level}));
+ $pstr =~ s/^\s+//;
+ $pstr =~ s/\s+$//;
+ my @path_comps = split /\s+/, $pstr;
+ return \@path_comps;
+}
+
+############################################################
+# low-level API functions that have been converted to use
+# the cstore library.
+############################################################
+
+######
+# observers of current working config or active config during a commit.
+# * MOST users of this API should use these functions.
+# * these functions MUST NOT worry about the "deactivated" state, i.e.,
+# deactivated nodes are equivalent to having been deleted for these
+# functions. in other words, these functions are NOT "deactivate-aware".
+# * functions that can be used to observe "active config" can be used
+# outside a commit as well (only when observing active config, of course).
+#
+# note: these functions accept a third argument "$include_deactivated", but
+# it is for error checking purposes to ensure that all legacy
+# invocations have been fixed. the functions MUST NOT be called
+# with this argument.
+my $DIE_DEACT_MSG = 'This function is NOT deactivate-aware';
+
+## exists("path to node")
+# Returns true if specified node exists in working config.
+sub exists {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return 1
+ if ($self->{_cstore}->cfgPathExists($self->get_path_comps($path), undef));
+ return; # note: this return is needed. can't just return the return value
+ # of the above function since some callers expect "undef"
+ # as false.
}
-## setLevel("level")
-# if "level" is supplied, set the current level of the hierarchy we are working on
-# return the current level
-sub setLevel {
- my ($self, $level) = @_;
-
- $self->{_level} = $level if defined($level);
- $self->_set_current_dir_level();
-
- return $self->{_level};
+## existsOrig("path to node")
+# Returns true if specified node exists in active config.
+sub existsOrig {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return 1
+ if ($self->{_cstore}->cfgPathExists($self->get_path_comps($path), 1));
+ return; # note: this return is needed.
}
## listNodes("level")
-# return array of all nodes at "level"
-# level is relative
+# return array of all child nodes at "level" in working config.
sub listNodes {
- my ($self, $path, $disable) = @_;
- my @nodes = ();
-
- my $rpath = "";
- if ($path) {
- $path =~ s/\//%2F/g;
- $path =~ s/\s+/\//g;
- $rpath = $self->{_current_dir_level} . "/" . $path;
- } else {
- $rpath = $self->{_current_dir_level};
- }
- $path = $self->{_new_config_dir_base} . $rpath;
-
- #print "DEBUG Vyatta::Config->listNodes(): path = $path\n";
- opendir my $dir, $path or return ();
- @nodes = grep !/^\./, readdir $dir;
- closedir $dir;
-
- my @nodes_modified = ();
- while (@nodes) {
- my $tmp = pop (@nodes);
- $tmp =~ s/\n//g;
- #print "DEBUG Vyatta::Config->listNodes(): node = $tmp\n";
- my $ttmp = $rpath . "/" . $tmp;
- $tmp =~ s/%2F/\//g;
- $ttmp =~ s/\// /g;
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- if (!defined($status) || $status eq 'active') {
- push @nodes_modified, $tmp;
- }
- }
- else {
- push @nodes_modified, $tmp;
- }
- }
-
- return @nodes_modified;
-}
-
-## isActive("path")
-# return true|false based on whether node path has
-# been processed or is active
-sub isActive {
- my ($self, $path, $disable) = @_;
- my @nodes = ();
-
- my @comp_node = split " ", $path;
-
- my $comp_node = pop(@comp_node);
- if (!defined $comp_node) {
- return 1;
- }
-
- my $rel_path = join(" ",@comp_node);
-
- my @nodes_modified = $self->listOrigPlusComNodes($rel_path,$disable);
- foreach my $node (@nodes_modified) {
- if ($node eq $comp_node) {
- return 0;
- }
- }
- return 1;
-}
-
-## listNodes("level")
-# return array of all nodes (active plus currently committed) at "level"
-# level is relative
-sub listOrigPlusComNodes {
- my ($self, $path, $disable) = @_;
- my @nodes = ();
-
- my @nodes_modified = $self->listNodes($path,$disable);
-
- #convert array to hash
- my %coll;
- my $coll;
- @coll{@nodes_modified} = @nodes_modified;
-
- my $level = $self->{_level};
- if (! defined $level) {
- $level = "";
- }
-
- my $dir_path = $level;
- if (defined $path) {
- $dir_path .= " " . $path;
- }
- $dir_path =~ s/ /\//g;
- $dir_path = "/".$dir_path;
-
- #now test against the inprocess file in the system
-# my $com_file = "/tmp/.changes_$$";
- my $com_file = "/tmp/.changes";
- if (-e $com_file) {
- open my $file, "<", $com_file;
- foreach my $line (<$file>) {
- my @node = split " ", $line; #split on space
- #$node[1] is of the form: system/login/blah
- #$coll is of the form: blah
-
-# print("comparing: $dir_path and $level to $node[1]\n");
-
- #first only consider $path matches against $node[1]
- if (!defined $dir_path || $node[1] =~ m/^$dir_path/) {
- #or does $node[1] match the beginning of the line for $path
-
- #if yes, then split the right side and find against the hash for the value...
- my $tmp;
- if (defined $dir_path) {
- $tmp = substr($node[1],length($dir_path));
- }
- else {
- $tmp = $node[1];
- }
-
- if (!defined $tmp || $tmp eq '') {
- next;
- }
-
- my @child = split "/",$tmp;
- my $child;
-
-# print("tmp: $tmp, $child[0], $child[1]\n");
- if ($child[0] =~ /^\s*$/ || !defined $child[0] || $child[0] eq '') {
- shift(@child);
- }
-
-# print("child value is: >$child[0]<\n");
-
- #now can we find this entry in the hash?
- #if '-' this is a delete and need to remove from hash
- if ($node[0] eq "-") {
- if (!defined $child[1]) {
- delete($coll{$child[0]});
- }
- }
- #if '+' this is a set and need to add to hash
- elsif ($node[0] eq "+" && $child[0] ne '') {
- $coll{$child[0]} = '1';
- }
- }
- }
- close $file;
- close $com_file;
- }
-
-#print "coll count: ".keys(%coll);
-
- #now convert hash to array and return
- @nodes_modified = ();
- @nodes_modified = keys(%coll);
- return @nodes_modified;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetChildNodes(
+ $self->get_path_comps($path), undef);
+ return @{$ref};
}
## listOrigNodes("level")
-# return array of all original nodes (i.e., before any current change; i.e.,
-# in "working") at "level"
-# level is relative
+# return array of all child nodes at "level" in active config.
sub listOrigNodes {
- my ($self, $path, $disable) = @_;
- my @nodes = ();
-
- my $rpath = "";
- if (defined $path) {
- $path =~ s/\//%2F/g;
- $path =~ s/\s+/\//g;
- $rpath = $self->{_current_dir_level} . "/" . $path;
- }
- else {
- $rpath = $self->{_current_dir_level};
- }
- $path = $self->{_active_dir_base} . $rpath;
-
- #print "DEBUG Vyatta::Config->listNodes(): path = $path\n";
- opendir my $dir, "$path" or return ();
- @nodes = grep !/^\./, readdir $dir;
- closedir $dir;
-
- my @nodes_modified = ();
- while (@nodes) {
- my $tmp = pop (@nodes);
- $tmp =~ s/\n//g;
- #print "DEBUG Vyatta::Config->listNodes(): node = $tmp\n";
- my $ttmp = $rpath . "/" . $tmp;
- $tmp =~ s/%2F/\//g;
- $ttmp =~ s/\// /g;
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- if (!defined($status) || $status eq 'local') {
- push @nodes_modified, $tmp;
- }
- }
- else {
- push @nodes_modified, $tmp;
- }
- }
-
- return @nodes_modified;
-}
-
-## returnParent("level")
-# return the name of parent node relative to the current hierarchy
-# in this case "level" is set to the parent dir ".. .."
-# for example
-sub returnParent {
- my ($self, $node) = @_;
- my @x, my $tmp;
-
- # split our hierarchy into vars on a stack
- my @level = split /\s+/, $self->{_level};
-
- # count the number of parents we need to lose
- # and then pop 1 less
- @x = split /\s+/, $node;
- for ($tmp = 1; $tmp < @x; $tmp++) {
- pop @level;
- }
-
- # return the parent
- $tmp = pop @level;
- return $tmp;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetChildNodes(
+ $self->get_path_comps($path), 1);
+ return @{$ref};
}
## returnValue("node")
-# returns the value of "node" or undef if the node doesn't exist .
-# node is relative
+# return value of specified single-value node in working config.
+# return undef if fail to get value (invalid node, node doesn't exist,
+# not a single-value node, etc.).
sub returnValue {
- my ( $self, $node, $disable ) = @_;
- my $tmp;
-
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
-
- #getDeactivated
- my $ttmp = $self->{_current_dir_level} . "/" . $node;
- $ttmp =~ s/\// /g;
- #only return value if status is not disabled (i.e. local or both)
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- if (!defined($status) || $status eq 'active') {
- return unless
- open my $file, '<',
- "$self->{_new_config_dir_base}$self->{_current_dir_level}/$node/node.val";
-
- read $file, $tmp, 16384;
- close $file;
-
- $tmp =~ s/\n$//;
- }
- }
- else {
- return unless
- open my $file, '<',
- "$self->{_new_config_dir_base}$self->{_current_dir_level}/$node/node.val";
-
- read $file, $tmp, 16384;
- close $file;
-
- $tmp =~ s/\n$//;
- }
- return $tmp;
-}
-
-## returnComment("node")
-# returns the value of "node" or undef if the node doesn't exist .
-# node is relative
-sub returnComment {
- my ( $self, $node ) = @_;
- my $tmp = undef;
-
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
-
- return unless
- open my $file, '<',
- "$self->{_new_config_dir_base}/$node/.comment";
-
- read $file, $tmp, 16384;
- close $file;
-
- $tmp =~ s/\n$//;
- return $tmp;
-}
-
-## returnOrigPlusComValue("node")
-# returns the value of "node" or undef if the node doesn't exist .
-# node is relative
-sub returnOrigPlusComValue {
- my ( $self, $path, $disable ) = @_;
-
- my $tmp = returnValue($self,$path,$disable);
-
- my $level = $self->{_level};
- if (! defined $level) {
- $level = "";
- }
- my $dir_path = $level;
- if (defined $path) {
- $dir_path .= " " . $path;
- }
- $dir_path =~ s/ /\//g;
- $dir_path = "/".$dir_path."/value";
-
- #now need to compare this against what I've done
- my $com_file = "/tmp/.changes";
- if (-e $com_file) {
- open my $file, "<", $com_file;
- foreach my $line (<$file>) {
- my @node = split " ", $line; #split on space
- if (index($node[1],$dir_path) != -1) {
- #found, now figure out if this a set or delete
- if ($node[0] eq '+') {
- my $pos = rindex($node[1],"/value:");
- $tmp = substr($node[1],$pos+7);
- }
- else {
- $tmp = "";
- }
- last;
- }
- }
- close $file;
- close $com_file;
- }
- return $tmp;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->{_cstore}->cfgPathGetValue($self->get_path_comps($path),
+ undef);
}
-
## returnOrigValue("node")
-# returns the original value of "node" (i.e., before the current change; i.e.,
-# in "working") or undef if the node doesn't exist.
-# node is relative
+# return value of specified single-value node in active config.
+# return undef if fail to get value (invalid node, node doesn't exist,
+# not a single-value node, etc.).
sub returnOrigValue {
- my ( $self, $node, $disable ) = @_;
- my $tmp;
-
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
-
-
- #getDeactivated
- my $ttmp = $self->{_current_dir_level} . "/" . $node;
- $ttmp =~ s/\// /g;
- #only return value if status is not disabled (i.e. local or both)
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- if (!defined($status) || $status eq 'local') {
- my $filepath = "$self->{_active_dir_base}$self->{_current_dir_level}/$node";
-
- return unless open my $file, '<', "$filepath/node.val";
-
- read $file, $tmp, 16384;
- close $file;
-
- $tmp =~ s/\n$//;
- }
- }
- else {
- my $filepath = "$self->{_active_dir_base}$self->{_current_dir_level}/$node";
-
- return unless open my $file, '<', "$filepath/node.val";
-
- read $file, $tmp, 16384;
- close $file;
-
- $tmp =~ s/\n$//;
- }
- return $tmp;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->{_cstore}->cfgPathGetValue($self->get_path_comps($path), 1);
}
## returnValues("node")
-# returns an array of all the values of "node", or an empty array if the values do not exist.
-# node is relative
+# return array of values of specified multi-value node in working config.
+# return empty array if fail to get value (invalid node, node doesn't exist,
+# not a multi-value node, etc.).
sub returnValues {
- my $val = returnValue(@_);
- my @values = ();
- if (defined($val)) {
- @values = split("\n", $val);
- }
- return @values;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetValues($self->get_path_comps($path),
+ undef);
+ return @{$ref};
}
-## returnValues("node")
-# returns an array of all the values of "node", or an empty array if the values do not exist.
-# node is relative
-sub returnOrigPlusComValues {
- my ( $self, $path, $disable ) = @_;
- my @values = returnOrigValues($self,$path,$disable);
+## returnOrigValues("node")
+# return array of values of specified multi-value node in active config.
+# return empty array if fail to get value (invalid node, node doesn't exist,
+# not a multi-value node, etc.).
+sub returnOrigValues {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetValues($self->get_path_comps($path),
+ 1);
+ return @{$ref};
+}
+
+######
+# observers of the "effective" config.
+# they can be used
+# (1) outside a config session (e.g., op mode, daemons, callbacks, etc.).
+# OR
+# (2) during a config session
+#
+# HOWEVER, NOTE that the definition of "effective" is different under these
+# two scenarios.
+# (1) when used outside a config session, "effective" == "active".
+# in other words, in such cases the effective config is the same
+# as the running config.
+#
+# (2) when used during a config session, a config path (leading to either
+# a "node" or a "value") is "effective" if it is "in effect" at the
+# time when these observers are called. more detailed info can be
+# found in the library code.
+#
+# originally, these functions are exclusively for use during config
+# sessions. however, for some usage scenarios, it is useful to have a set
+# of API functions that can be used both during and outside config
+# sessions. therefore, definition (1) is added above for convenience.
+#
+# for example, a developer can use these functions in a script that can
+# be used both during a commit action and outside config mode, as long as
+# the developer is clearly aware of the difference between the above two
+# definitions.
+#
+# note that when used outside a config session (i.e., definition (1)),
+# these functions are equivalent to the observers for the "active" config.
+#
+# to avoid any confusiton, when possible (e.g., in a script that is
+# exclusively used in op mode), developers should probably use those
+# "active" observers explicitly when outside a config session instead
+# of these "effective" observers.
+#
+# it is also important to note that when used outside a config session,
+# due to race conditions, it is possible that the "observed" active config
+# becomes out-of-sync with the config that is actually "in effect".
+# specifically, this happens when two things occur simultaneously:
+# (a) an observer function is called from outside a config session.
+# AND
+# (b) someone invokes "commit" inside a config session (any session).
+#
+# this is because "commit" only updates the active config at the end after
+# all commit actions have been executed, so before the update happens,
+# some config nodes have already become "effective" but are not yet in the
+# "active config" and therefore are not observed by these functions.
+#
+# note that this is only a problem when the caller is outside config mode.
+# in such cases, the caller (which could be an op-mode command, a daemon,
+# a callback script, etc.) already must be able to handle config changes
+# that can happen at any time. if "what's configured" is more important,
+# using the "active config" should be fine as long as it is relatively
+# up-to-date. if the actual "system state" is more important, then the
+# caller should probably just check the system state in the first place
+# (instead of using these config observers).
+
+## isEffective("path")
+# return whether "path" is in "active" config when used outside config
+# session,
+# OR
+# return whether "path" is "effective" during current commit.
+# see above discussion about the two different definitions.
+#
+# "effective" means the path is in effect, i.e., any of the following is true:
+# (1) active && working
+# path is in both active and working configs, i.e., unchanged.
+# (2) !active && working && committed
+# path is not in active, has been set in working, AND has already
+# been committed, i.e., "commit" has already processed the
+# addition/update of the path.
+# (3) active && !working && !committed
+# path is in active, has been deleted from working, AND
+# has NOT been committed yet, i.e., "commit" (per priority) has not
+# processed the deletion of the path yet (or has processed it but
+# the action failed).
+#
+# note: during commit, deactivate has the same effect as delete. so as
+# far as this function (and any other commit observer functions) is
+# concerned, deactivated nodes don't exist.
+sub isEffective {
+ my ($self, $path) = @_;
+ return 1
+ if ($self->{_cstore}->cfgPathEffective($self->get_path_comps($path)));
+ return; # note: this return is needed.
+}
- #now parse the commit accounting file.
- my $level = $self->{_level};
- if (! defined $level) {
- $level = "";
- }
- my $dir_path = $level;
- if (defined $path) {
- $dir_path .= " " . $path;
- }
- $dir_path =~ s/ /\//g;
- $dir_path = "/".$dir_path."/value";
-
- #now need to compare this against what I've done
- my $com_file = "/tmp/.changes";
- if (-e $com_file) {
- open my $file, "<", $com_file;
- foreach my $line (<$file>) {
- my @node = split " ", $line; #split on space
- if (index($node[1],$dir_path) != -1) {
- #found, now figure out if this a set or delete
- my $pos = rindex($node[1],"/value:");
- my $tmp = substr($node[1],$pos+7);
- my $i = 0;
- my $match = 0;
- foreach my $v (@values) {
- if ($v eq $tmp) {
- $match = 1;
- last;
- }
- $i = $i + 1;
- }
- if ($node[0] eq '+') {
- #add value
- if ($match == 0) {
- push(@values,$tmp);
- }
- }
- else {
- #remove value
- if ($match == 1) {
- splice(@values,$i);
- }
- }
- }
- }
- close $file;
- close $com_file;
- }
- return @values;
+## isActive("path")
+# XXX this is the original API function. name is confusing ("active" could
+# be confused with "orig") but keep it for compatibility.
+# just call isEffective().
+# also, original function accepts "$disable" flag, which doesn't make
+# sense. for commit purposes, deactivated should be equivalent to
+# deleted.
+sub isActive {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->isEffective($path);
+}
+
+## listEffectiveNodes("level")
+# return array of "effective" child nodes at "level" during current commit.
+# see isEffective() for definition of "effective".
+sub listEffectiveNodes {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetEffectiveChildNodes(
+ $self->get_path_comps($path));
+ return @{$ref};
+}
+
+## listOrigPlusComNodes("level")
+# XXX this is the original API function. name is confusing (it's neither
+# necessarily "orig" nor "plus") but keep it for compatibility.
+# just call listEffectiveNodes().
+# also, original function accepts "$disable" flag, which doesn't make
+# sense. for commit purposes, deactivated should be equivalent to
+# deleted.
+sub listOrigPlusComNodes {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->listEffectiveNodes($path);
}
-## returnOrigValues("node")
-# returns an array of all the original values of "node" (i.e., before the
-# current change; i.e., in "working"), or an empty array if the values do not
-# exist.
-# node is relative
-sub returnOrigValues {
- my $val = returnOrigValue(@_);
- my @values = ();
- if (defined($val)) {
- @values = split("\n", $val);
- }
- return @values;
+## returnEffectiveValue("node")
+# return "effective" value of specified "node" during current commit.
+sub returnEffectiveValue {
+ my ($self, $path) = @_;
+ return $self->{_cstore}->cfgPathGetEffectiveValue(
+ $self->get_path_comps($path));
}
-## exists("node")
-# Returns true if the "node" exists.
-sub exists {
- my ( $self, $node, $disable ) = @_;
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
- #getDeactivated()
- my $ttmp = $self->{_current_dir_level} . "/" . $node;
- $ttmp =~ s/\// /g;
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- #only return value if status is not disabled (i.e. local or both)
- if (defined($status) && ($status eq 'both' || $status eq 'local')) { #if a .disable is in local or active or both then return false
- return;
- }
- }
- return ( -d "$self->{_new_config_dir_base}$self->{_current_dir_level}/$node" );
+## returnOrigPlusComValue("node")
+# XXX this is the original API function. just call returnEffectiveValue().
+# also, original function accepts "$disable" flag.
+sub returnOrigPlusComValue {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->returnEffectiveValue($path);
}
-## existsOrig("node")
-# Returns true if the "original node" exists.
-sub existsOrig {
- my ( $self, $node, $disable ) = @_;
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
-
- #getDeactivated()
- my $ttmp = $self->{_current_dir_level} . "/" . $node;
- $ttmp =~ s/\// /g;
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- #only return value if status is not disabled (i.e. local or both)
- if (defined($status) && ($status eq 'both' || $status eq 'active')) { #if a .disable is in local or active or both then return false
- return;
- }
- }
+## returnEffectiveValues("node")
+# return "effective" values of specified "node" during current commit.
+sub returnEffectiveValues {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetEffectiveValues(
+ $self->get_path_comps($path));
+ return @{$ref};
+}
- return ( -d "$self->{_active_dir_base}$self->{_current_dir_level}/$node" );
+## returnOrigPlusComValues("node")
+# XXX this is the original API function. just call returnEffectiveValues().
+# also, original function accepts "$disable" flag.
+sub returnOrigPlusComValues {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return $self->returnEffectiveValues($path);
}
## isDeleted("node")
-# is the "node" deleted. node is relative. returns true or false
+# whether specified node has been deleted in working config
sub isDeleted {
- my ($self, $node, $disable) = @_;
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
-
- my $filepathAct
- = "$self->{_active_dir_base}$self->{_current_dir_level}/$node";
- my $filepathNew
- = "$self->{_new_config_dir_base}$self->{_current_dir_level}/$node";
-
- #getDeactivated()
- my $ttmp = $self->{_current_dir_level} . "/" . $node;
- $ttmp =~ s/\// /g;
- if (!defined $disable) {
- my ($status, undef) = $self->getDeactivated($ttmp);
- #only return value if status is not disabled (i.e. local or both)
- if (defined($status) && $status eq 'local') {
- return (-e $filepathAct);
- }
- }
-
- return ((-e $filepathAct) && !(-e $filepathNew));
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return 1 if ($self->{_cstore}->cfgPathDeleted($self->get_path_comps($path)));
+ return; # note: this return is needed.
}
## listDeleted("level")
-# return array of deleted nodes in the "level"
-# "level" defaults to current
+# return array of deleted nodes at specified "level"
sub listDeleted {
- my ($self, $path, $disable) = @_;
- my @new_nodes = $self->listNodes($path,$disable);
- my @orig_nodes = $self->listOrigNodes($path,$disable);
- my %new_hash = map { $_ => 1 } @new_nodes;
- my @deleted = grep { !defined($new_hash{$_}) } @orig_nodes;
- return @deleted;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetDeletedChildNodes(
+ $self->get_path_comps($path));
+ return @{$ref};
}
-## getAllDeactivated()
-# returns array of all deactivated nodes.
-#
-my @all_deactivated_nodes;
-sub getAllDeactivated {
- my ($self, $path) = @_;
- my $start_dir = $self->{_active_dir_base};
- find ( \&wanted, $start_dir );
- return @all_deactivated_nodes;
-}
-sub wanted {
- if ( $_ eq '.disable' ) {
- my $f = $File::Find::name;
- #now strip off leading path and trailing file
- $f = substr($f, length($ENV{VYATTA_ACTIVE_CONFIGURATION_DIR}));
- $f = substr($f, 0, length($f)-length("/.disable"));
- $f =~ s/\// /g;
- push @all_deactivated_nodes, $f;
- }
-}
-
-
-## isDeactivated("node")
-# returns back whether this node is in an active (false) or
-# deactivated (true) state.
-sub getDeactivated {
- my ($self, $node) = @_;
-
- if (!defined $node) {
- $node = $self->{_level};
- }
-
- # let's setup the filepath for the change_dir
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
- #now walk up parent in local and in active looking for '.disable' file
- $node =~ s/ /\//g;
-
- while (1) {
- my $filepath = "$self->{_new_config_dir_base}/$node";
- my $filepathActive = "$self->{_active_dir_base}/$node";
-
- my $local = $filepath . "/.disable";
- my $active = $filepathActive . "/.disable";
-
- if (-e $local && -e $active) {
- return ("both",$node);
- }
- elsif (-e $local && !(-e $active)) {
- return ("local",$node);
- }
- elsif (!(-e $local) && -e $active) {
- return ("active",$node);
- }
- my $pos = rindex($node, "/");
- if ($pos == -1) {
- last;
- }
- $node = substr($node,0,$pos);
- }
- return (undef,undef);
+## isAdded("node")
+# whether specified node has been added in working config
+sub isAdded {
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return 1 if ($self->{_cstore}->cfgPathAdded($self->get_path_comps($path)));
+ return; # note: this return is needed.
}
## isChanged("node")
-# will check the change_dir to see if the "node" has been changed from a previous
-# value. returns true or false.
+# whether specified node has been changed in working config
+# XXX behavior is different from original implementation, which was
+# inconsistent between deleted nodes and deactivated nodes.
+# see cstore library source for details.
+# basically, a node is "changed" if it's "added", "deleted", or
+# "marked changed" (i.e., if any descendant changed).
sub isChanged {
- my ($self, $node, $disable) = @_;
-
- # let's setup the filepath for the change_dir
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
- my $filepath = "$self->{_changes_only_dir_base}$self->{_current_dir_level}/$node";
-
- if (!defined $disable) {
- my ($status,undef) = $self->getDeactivated($self->{_level}." ".$node);
- if (defined $status && ($status eq 'active' || $status eq 'local')) {
- return (defined $status);
- }
- }
-
-
- # if the node exists in the change dir, it's modified.
- return (-e $filepath);
-}
-
-## isAdded("node")
-# will compare the new_config_dir to the active_dir to see if the "node" has
-# been added. returns true or false.
-sub isAdded {
- my ($self, $node, $disable) = @_;
-
- #print "DEBUG Vyatta::Config->isAdded(): node $node\n";
- # let's setup the filepath for the modify dir
- $node =~ s/\//%2F/g;
- $node =~ s/\s+/\//g;
- my $filepathNewConfig = "$self->{_new_config_dir_base}$self->{_current_dir_level}/$node";
-
- #print "DEBUG Vyatta::Config->isAdded(): filepath $filepathNewConfig\n";
-
- # if the node doesn't exist in the modify dir, it's not
- # been added. so short circuit and return false.
- return unless (-e $filepathNewConfig);
-
- # now let's setup the path for the working dir
- my $filepathActive = "$self->{_active_dir_base}$self->{_current_dir_level}/$node";
-
- if (!defined $disable) {
- my ($status,undef) = $self->getDeactivated($self->{_level}." ".$node);
- if (defined $status && ($status eq 'active')) {
- return (defined $status);
- }
- }
-
- # if the node is in the active_dir it's not new
- return (! -e $filepathActive);
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ return 1 if ($self->{_cstore}->cfgPathChanged($self->get_path_comps($path)));
+ return; # note: this return is needed.
}
## listNodeStatus("level")
-# return a hash of the status of nodes at the current config level
+# return a hash of status of child nodes at specified level.
# node name is the hash key. node status is the hash value.
-# node status can be one of deleted, added, changed, or static
+# node status can be one of "deleted", "added", "changed", or "static".
sub listNodeStatus {
- my ($self, $path, $disable) = @_;
- my @nodes = ();
- my %nodehash = ();
-
- # find deleted nodes first
- @nodes = $self->listDeleted($path,$disable);
- foreach my $node (@nodes) {
- if ($node =~ /.+/) { $nodehash{$node} = "deleted" };
- }
-
- @nodes = ();
- @nodes = $self->listNodes($path,$disable);
- foreach my $node (@nodes) {
- if ($node =~ /.+/) {
- my $status = undef;
- if (!defined $disable) {
- ($status,undef) = $self->getDeactivated($self->{_level}." ".$node);
- }
- my $nodepath = $node;
- $nodepath = "$path $node" if ($path);
- #print "DEBUG Vyatta::Config->listNodeStatus(): node $node\n";
- # No deleted nodes -- added, changed, ot static only.
- if (defined $status && $status eq 'local') { $nodehash{$node} = "deleted"; }
- elsif (defined $status && $status eq 'active') { $nodehash{$node} = "added"; }
- elsif ($self->isAdded($nodepath,'true')) { $nodehash{$node} = "added"; }
- elsif ($self->isChanged($nodepath,'true')) { $nodehash{$node} = "changed"; }
- else { $nodehash{$node} = "static"; }
- }
- }
-
- return %nodehash;
-}
-
-############ DOM Tree ################
-
-#Create active DOM Tree
-sub createActiveDOMTree {
-
- my $self = shift;
-
- my $tree = new Vyatta::ConfigDOMTree($self->{_active_dir_base} . $self->{_current_dir_level},"active");
-
- return $tree;
+ my ($self, $path, $include_deactivated) = @_;
+ die $DIE_DEACT_MSG if (defined($include_deactivated));
+ my $ref = $self->{_cstore}->cfgPathGetChildNodesStatus(
+ $self->get_path_comps($path));
+ return %{$ref};
}
-#Create changes only DOM Tree
-sub createChangesOnlyDOMTree {
-
- my $self = shift;
-
- my $tree = new Vyatta::ConfigDOMTree($self->{_changes_only_dir_base} . $self->{_current_dir_level},
- "changes_only");
-
- return $tree;
+## getTmplChildren("level")
+# return list of child nodes in the template hierarchy at specified level.
+sub getTmplChildren {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->tmplGetChildNodes($self->get_path_comps($path));
+ return @{$ref};
}
-#Create new config DOM Tree
-sub createNewConfigDOMTree {
-
- my $self = shift;
- my $level = $self->{_new_config_dir_base} . $self->{_current_dir_level};
-
- return new Vyatta::ConfigDOMTree($level, "new_config");
+## validateTmplPath("path")
+# return whether specified path is a valid template path
+sub validateTmplPath {
+ my ($self, $path, $validate_vals) = @_;
+ return 1 if ($self->{_cstore}->validateTmplPath($self->get_path_comps($path),
+ $validate_vals));
+ return; # note: this return is needed.
}
-
-###### functions for templates ######
-
-# $1: array representing the config node path.
-# returns the filesystem path to the template of the specified node,
-# or undef if the specified node path is not valid.
-sub getTmplPath {
- my $self = shift;
- my @cfg_path = @{$_[0]};
- my $tpath = $self->{_vyatta_template_dir};
- for my $p (@cfg_path) {
- if (-d "$tpath/$p") {
- $tpath .= "/$p";
- next;
+## parseTmplAll("path")
+# return hash ref of parsed template of specified path, undef if path is
+# invalid. note: if !allow_val, path must terminate at a "node", not "value".
+sub parseTmplAll {
+ my ($self, $path, $allow_val) = @_;
+ my $href = $self->{_cstore}->getParsedTmpl($self->get_path_comps($path),
+ $allow_val);
+ if (defined($href)) {
+ # some conversions are needed
+ if (defined($href->{is_value}) and $href->{is_value} eq '1') {
+ $href->{is_value} = 1;
}
- if (-d "$tpath/node.tag") {
- $tpath .= "/node.tag";
- next;
+ if (defined($href->{multi}) and $href->{multi} eq '1') {
+ $href->{multi} = 1;
+ }
+ if (defined($href->{tag}) and $href->{tag} eq '1') {
+ $href->{tag} = 1;
+ }
+ if (defined($href->{limit})) {
+ $href->{limit} = int($href->{limit});
}
- # the path is not valid!
- return;
}
- return $tpath;
+ return $href;
}
-sub isTagNode {
- my $self = shift;
- my $cfg_path_ref = shift;
- my $tpath = $self->getTmplPath($cfg_path_ref);
- return unless $tpath;
+sub hasTmplChildren {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->tmplGetChildNodes($self->get_path_comps($path));
+ return if (!defined($ref));
+ return (scalar(@{$ref}) > 0);
+}
+
+
+######
+# "deactivate-aware" observers of current working config or active config.
+# * MUST ONLY be used by operations that NEED to distinguish between
+# deactivated nodes and deleted nodes. below is the list of operations
+# that are allowed to use these functions:
+# * configuration output (show, save, load)
+#
+# operations that are not on the above list MUST NOT use these
+# "deactivate-aware" functions.
+
+## deactivated("node")
+# return whether specified node is deactivated in working config.
+# note that this is different from "marked deactivated". if a node is
+# "marked deactivated", then the node itself and any descendants are
+# "deactivated".
+sub deactivated {
+ my ($self, $path) = @_;
+ return 1
+ if ($self->{_cstore}->cfgPathDeactivated($self->get_path_comps($path),
+ undef));
+ return; # note: this return is needed.
+}
+
+## deactivatedOrig("node")
+# return whether specified node is deactivated in active config.
+sub deactivatedOrig {
+ my ($self, $path) = @_;
+ return 1
+ if ($self->{_cstore}->cfgPathDeactivated($self->get_path_comps($path), 1));
+ return; # note: this return is needed.
+}
+
+## returnValuesDA("node")
+# DA version of returnValues()
+sub returnValuesDA {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetValuesDA($self->get_path_comps($path),
+ undef);
+ return @{$ref};
+}
+
+## returnOrigValuesDA("node")
+# DA version of returnOrigValues()
+sub returnOrigValuesDA {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetValuesDA($self->get_path_comps($path),
+ 1);
+ return @{$ref};
+}
+
+## returnValueDA("node")
+# DA version of returnValue()
+sub returnValueDA {
+ my ($self, $path) = @_;
+ return $self->{_cstore}->cfgPathGetValueDA($self->get_path_comps($path),
+ undef);
+}
+
+## returnOrigValueDA("node")
+# DA version of returnOrigValue()
+sub returnOrigValueDA {
+ my ($self, $path) = @_;
+ return $self->{_cstore}->cfgPathGetValueDA($self->get_path_comps($path), 1);
+}
+
+## listOrigNodesDA("level")
+# DA version of listOrigNodes()
+sub listOrigNodesDA {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetChildNodesDA(
+ $self->get_path_comps($path), 1);
+ return @{$ref};
+}
+
+## listNodeStatusDA("level")
+# DA version of listNodeStatus()
+sub listNodeStatusDA {
+ my ($self, $path) = @_;
+ my $ref = $self->{_cstore}->cfgPathGetChildNodesStatusDA(
+ $self->get_path_comps($path));
+ return %{$ref};
+}
- return (-d "$tpath/node.tag");
+## returnComment("node")
+# return comment of "node" or undef if comment doesn't exist
+sub returnComment {
+ my ($self, $path) = @_;
+ return $self->{_cstore}->cfgPathGetComment($self->get_path_comps($path),
+ undef);
}
-sub hasTmplChildren {
- my $self = shift;
- my $cfg_path_ref = shift;
- my $tpath = $self->getTmplPath($cfg_path_ref);
- return unless $tpath;
- opendir (my $tdir, $tpath) or return;
- my @tchildren = grep !/^node\.def$/, (grep !/^\./, (readdir $tdir));
- closedir $tdir;
+############################################################
+# high-level API functions (not using the cstore library directly)
+############################################################
- return (scalar(@tchildren) > 0);
+## setLevel("level")
+# set the current level of config hierarchy to specified level (if defined).
+# return the current level.
+sub setLevel {
+ my ($self, $level) = @_;
+ $self->{_level} = $level if defined($level);
+ return $self->{_level};
}
-# $cfg_path_ref: ref to array containing the node path.
-# returns ($is_multi, $is_text, $default),
-# or undef if specified node is not valid.
+## returnParent("..( ..)*")
+# return the name of ancestor node relative to the current level.
+# each level up is represented by a ".." in the argument.
+sub returnParent {
+ my ($self, $ppath) = @_;
+ my @pcomps = @{$self->get_path_comps()};
+ # we could call split in scalar context but that generates a warning
+ my @dummy = split(/\s+/, $ppath);
+ my $num = scalar(@dummy);
+ return if ($num > scalar(@pcomps));
+ return $pcomps[-$num];
+}
+
+## parseTmpl("path")
+# parse template of specified path and return ($is_multi, $is_text, $default)
+# or undef if specified path is not valid.
sub parseTmpl {
- my $self = shift;
- my $cfg_path_ref = shift;
- my ($is_multi, $is_text, $default) = (0, 0, undef);
- my $tpath = $self->getTmplPath($cfg_path_ref);
- return unless $tpath;
-
- if (! -r "$tpath/node.def") {
- return ($is_multi, $is_text);
- }
-
- open (my $tmpl, '<', "$tpath/node.def")
- or return ($is_multi, $is_text);
- foreach (<$tmpl>) {
- if (/^multi:/) {
- $is_multi = 1;
- }
- if (/^type:\s+txt\s*$/) {
- $is_text = 1;
- }
- if (/^default:\s+(\S+)\s*$/) {
- $default = $1;
- }
- }
- close $tmpl;
+ my ($self, $path) = @_;
+ my $href = $self->parseTmplAll($path);
+ return if (!defined($href));
+ my $is_multi = $href->{multi};
+ my $is_text = (defined($href->{type}) and $href->{type} eq 'txt');
+ my $default = $href->{default};
return ($is_multi, $is_text, $default);
}
-# $cfg_path: config path of the node.
-# returns a hash ref containing attributes in the template
-# or undef if specified node is not valid.
-sub parseTmplAll {
- my ($self, $cfg_path) = @_;
- my @pdirs = split(/ +/, $cfg_path);
- my %ret = ();
- my $tpath = $self->getTmplPath(\@pdirs);
- return unless $tpath;
-
- open(my $tmpl, '<', "$tpath/node.def")
- or return;
- foreach (<$tmpl>) {
- if (/^multi:\s*(\S+)?$/) {
- $ret{multi} = 1;
- $ret{limit} = $1;
- } elsif (/^tag:\s*(\S+)?$/) {
- $ret{tag} = 1;
- $ret{limit} = $1;
- } elsif (/^type:\s*(\S+),\s*(\S+)\s*$/) {
- $ret{type} = $1;
- $ret{type2} = $2;
- } elsif (/^type:\s*(\S+)\s*$/) {
- $ret{type} = $1;
- } elsif (/^default:\s*(\S.*)\s*$/) {
- $ret{default} = $1;
- if ($ret{default} =~ /^"(.*)"$/) {
- $ret{default} = $1;
- }
- } elsif (/^help:\s*(\S.*)$/) {
- $ret{help} = $1;
- } elsif (/^enumeration:\s*(\S+)$/) {
- $ret{enum} = $1;
- }
- }
- close($tmpl);
- return \%ret;
+## isTagNode("path")
+# whether specified path is a tag node.
+sub isTagNode {
+ my ($self, $path) = @_;
+ my $href = $self->parseTmplAll($path);
+ return (defined($href) and $href->{tag});
}
-# $cfg_path: config path of the node.
-# returns the list of the node's children in the template hierarchy.
-sub getTmplChildren {
- my ($self, $cfg_path) = @_;
- my @pdirs = split(/ +/, $cfg_path);
- my $tpath = $self->getTmplPath(\@pdirs);
- return () unless $tpath;
-
- opendir (my $tdir, $tpath) or return;
- my @tchildren = grep !/^node\.def$/, (grep !/^\./, (readdir $tdir));
- closedir $tdir;
-
- return @tchildren;
+## isLeafNode("path")
+# whether specified path is a "leaf node", i.e., single-/multi-value node.
+sub isLeafNode {
+ my ($self, $path) = @_;
+ my $href = $self->parseTmplAll($path, 1);
+ return (defined($href) and !$href->{is_value} and $href->{type}
+ and !$href->{tag});
}
-###### misc functions ######
+## isLeafValue("path")
+# whether specified path is a "leaf value", i.e., value of a leaf node.
+sub isLeafValue {
+ my ($self, $path) = @_;
+ my $href = $self->parseTmplAll($path, 1);
+ return (defined($href) and $href->{is_value} and !$href->{tag});
+}
# compare two value lists and return "deleted" and "added" lists.
# since this is for multi-value nodes, there is no "changed" (if a value's
@@ -988,4 +640,39 @@ sub compareValueLists {
return %comp_hash;
}
+############################################################
+# API functions that have not been converted
+############################################################
+
+# XXX the following function should not be needed. the only user is
+# ConfigLoad, which uses this to get all deactivated nodes in active
+# config and then reactivates everything on load.
+#
+# this works for "load" but not for "merge", which incorrectly
+# reactivates all deactivated nodes even if they are not in the config
+# file to be merged. see bug 5746.
+#
+# how to get rid of this function depends on how bug 5746 is going
+# to be fixed.
+## getAllDeactivated()
+# returns array of all deactivated nodes.
+my @all_deactivated_nodes;
+sub getAllDeactivated {
+ my ($self, $path) = @_;
+ my $start_dir = $ENV{VYATTA_ACTIVE_CONFIGURATION_DIR};
+ find ( \&wanted, $start_dir );
+ return @all_deactivated_nodes;
+}
+sub wanted {
+ if ( $_ eq '.disable' ) {
+ my $f = $File::Find::name;
+ #now strip off leading path and trailing file
+ $f = substr($f, length($ENV{VYATTA_ACTIVE_CONFIGURATION_DIR}));
+ $f = substr($f, 0, length($f)-length("/.disable"));
+ $f =~ s/\// /g;
+ push @all_deactivated_nodes, $f;
+ }
+}
+
1;
+
diff --git a/lib/Vyatta/ConfigDOMTree.pm b/lib/Vyatta/ConfigDOMTree.pm
deleted file mode 100755
index 87fc8f2..0000000
--- a/lib/Vyatta/ConfigDOMTree.pm
+++ /dev/null
@@ -1,366 +0,0 @@
-#
-# **** 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.
-#
-# A copy of the GNU General Public License is available as
-# `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution
-# or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'.
-# You can also obtain it by writing to the Free Software Foundation,
-# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-# MA 02110-1301, USA.
-#
-# This code was originally developed by Vyatta, Inc.
-# Portions created by Vyatta are Copyright (C) 2005, 2006, 2007 Vyatta, Inc.
-# All Rights Reserved.
-#
-# Author: Oleg Moskalenko
-# Date: 2007
-# Description:
-#
-# **** End License ****
-#
-#
-
-package Vyatta::ConfigDOMTree;
-
-use strict;
-
-my %fields = (
- _dir => undef,
- _name => undef,
- _value => undef,
- _subnodes => undef
- );
-
-sub new {
-
- my $that = shift;
- my $dir = shift;
- my $name = shift;
-
- my $class = ref ($that) || $that;
-
- my $self = {
- %fields
- };
-
- bless $self, $class;
-
- $self->{_dir} = $dir;
- $self->{_name} = $name;
-
- return $self->_construct_dom_tree();
-}
-
-#Simple DOM Tree iteration and screen output
-#$1 - left screen offset (optional)
-sub print {
-
- my $self = shift;
- my $level = shift;
-
- my $tree = $self;
-
- if(!(defined $level)) {
- $level="";
- }
-
- if(defined $tree) {
-
- print("$level name=",$tree->getNodeName(),"\n");
-
- my $value = $tree->getNodeValue();
-
- if(defined $value) {
-
- print("$level value=$value\n");
-
- }
-
- my @subnodes = $tree->getSubNodes();
-
- while(@subnodes) {
-
- my $subnode = shift @subnodes;
- $subnode->print($level . " ");
- }
- }
-}
-
-#Return value of the tree node
-sub getNodeValue {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- $ret = $tree->{_value};
- }
-
- return $ret;
-}
-
-#Return value of the tree node.
-#If the value is nor defined, return empty string.
-sub getNodeValueAsString {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- $ret = $tree->getNodeValue();
- }
-
- if(!defined $ret) {
- $ret = "";
- }
-
- return $ret;
-}
-
-#Return name of the tree node
-sub getNodeName {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- $ret = $tree->{_name};
- }
-
- return $ret;
-}
-
-#Return array of subnodes of the tree node
-sub getSubNodes {
-
- my $self = shift;
- my $tree = $self;
-
- my @ret = ();
-
- if(defined $tree) {
-
- my $subnodes = $tree->{_subnodes};
-
- if(defined $subnodes) {
-
- @ret = values %{$subnodes};
-
- }
- }
-
- return @ret;
-}
-
-sub isLeafNode {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret=undef;
-
- if(defined $tree) {
-
- if(defined $tree->{_value}) {
-
- if(! defined $tree->{_subnodes}) {
-
- $ret="true";
- }
- }
- }
-
- return $ret;
-}
-
-#Return subtree of the tree according to the path list
-#$1, $2, ... - path to the subtree
-sub getSubNode {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- while(@_ && $tree) {
-
- my $subnode = shift (@_);
-
- my $subnodes = $tree->{_subnodes};
-
- if(defined $subnodes) {
-
- $tree = $subnodes->{$subnode};
-
- } else {
-
- $tree = undef;
-
- }
- }
-
- $ret=$tree;
-
- return $ret;
-}
-
-#Return value of the subnode of the tree according to the path list
-#$1, $2, ... - path to the subtree
-sub getSubNodeValue {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- my $node = $tree->getSubNode(@_);
-
- if(defined $node) {
-
- $ret=$node->getNodeValue();
- }
- }
-
- return $ret;
-}
-
-#Return value of the subnode of the tree according to the path list.
-#If the value is not defined, return empty string.
-#$1, $2, ... - path to the subtree
-sub getSubNodeValueAsString {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- my $node = $tree->getSubNode(@_);
-
- if(defined $node) {
-
- $ret=$node->getNodeValue();
- }
- }
-
- if(! defined $ret) {
- $ret = "";
- }
-
- return $ret;
-}
-
-#Check if there is a subnode with the specified path.
-#$1, $2, ... - path to the subtree
-sub subNodeExist {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = undef;
-
- if(defined $tree) {
-
- my $node = $tree->getSubNode(@_);
-
- if(defined $node) {
-
- $ret="true";
- }
- }
-
- return $ret;
-}
-
-#Return of the children of the node
-#$1, $2, ... - path to the subtree
-sub getSubNodesNumber {
-
- my $self = shift;
- my $tree = $self;
-
- my $ret = 0;
-
- if(defined $tree) {
-
- my $node = $tree->getSubNode(@_);
-
- if(defined $node) {
-
- my @subs = $node->getSubNodes();
-
- if(@subs) {
- $ret = $#subs + 1;
- }
- }
- }
-
- return $ret;
-}
-
-#private method: costruct DOM Tree according to the absolute path provided
-sub _construct_dom_tree {
-
- my $self = shift;
-
- my $subnodesNum=0;
- my $valuePresent=0;
-
- return unless defined $self;
-
- opendir my $dir, $self->{_dir} or return;
- my @entries = grep !/^\./, readdir $dir;
- closedir $dir;
-
- while(@entries) {
-
- my $entry = shift @entries;
-
- if($entry) {
- my $fn = $self->{_dir} . "/" . $entry;
- if( -f $fn) {
- if($entry eq "node.val") {
- my $value=`cat $fn`;
- while(chomp $value) {};
- $self->{_value} = $value;
- $valuePresent++;
- }
- } elsif (-d $fn) {
- my $subnode = new Vyatta::ConfigDOMTree($fn,$entry);
- if(defined $subnode) {
- if(! defined $self->{_subnodes} ) {
- $self->{_subnodes} = {};
- }
- $self->{_subnodes}->{$entry} = $subnode;
- $subnodesNum++;
- }
- }
- }
- }
-
- return if ( $valuePresent < 1 && $subnodesNum < 1 );
-
- return $self;
-}
-
-1;
diff --git a/lib/Vyatta/ConfigLoad.pm b/lib/Vyatta/ConfigLoad.pm
index c806c7f..d3d7dbb 100755
--- a/lib/Vyatta/ConfigLoad.pm
+++ b/lib/Vyatta/ConfigLoad.pm
@@ -1,4 +1,4 @@
-# Author: An-Cheng Huang <ancheng@vyatta.com>
+# Author: Vyatta <eng@vyatta.com>
# Date: 2007
# Description: Perl module for loading configuration.
@@ -261,8 +261,9 @@ my @delete_list = ();
sub findDeletedValues {
my $new_ref = $_[0];
my @active_path = @{$_[1]};
- my ($is_multi, $is_text) = $active_cfg->parseTmpl(\@active_path);
+
$active_cfg->setLevel(join ' ', @active_path);
+ my ($is_multi, $is_text) = $active_cfg->parseTmpl();
if ($is_multi) {
# for "multi:" nodes, need to sort the values by the original order.
my @nvals = getSortedMultiValues($new_ref, \@active_path);
@@ -287,10 +288,9 @@ sub findDeletedValues {
# $1: array ref representing current config path (active config)
sub findDeletedNodes {
my $new_ref = $_[0];
- my $ret_dis_flag = $_[1];
- my @active_path = @{$_[2]};
+ my @active_path = @{$_[1]};
$active_cfg->setLevel(join ' ', @active_path);
- my @active_nodes = $active_cfg->listOrigNodes(undef,$ret_dis_flag);
+ my @active_nodes = $active_cfg->listOrigNodesDA();
foreach (@active_nodes) {
if ($_ eq 'def') {
next;
@@ -303,7 +303,7 @@ sub findDeletedNodes {
my @plist = applySingleQuote(@active_path, $_);
push @delete_list, [\@plist, 0];
} else {
- findDeletedNodes($new_ref->{$_}, $ret_dis_flag, [ @active_path, $_ ]);
+ findDeletedNodes($new_ref->{$_}, [ @active_path, $_ ]);
}
}
}
@@ -317,8 +317,9 @@ my @set_list = ();
sub findSetValues {
my $new_ref = $_[0];
my @active_path = @{$_[1]};
- my ($is_multi, $is_text) = $active_cfg->parseTmpl(\@active_path);
+
$active_cfg->setLevel(join ' ', @active_path);
+ my ($is_multi, $is_text) = $active_cfg->parseTmpl();
if ($is_multi) {
# for "multi:" nodes, need to sort the values by the original order.
my @nvals = getSortedMultiValues($new_ref, \@active_path);
@@ -354,7 +355,7 @@ sub findSetNodes {
$active_cfg->setLevel(join ' ', @active_path);
my @active_nodes = $active_cfg->listOrigNodes();
my %active_hash = map { $_ => 1 } @active_nodes;
- my $nref = $active_cfg->parseTmplAll(join ' ', @active_path);
+ my $nref = $active_cfg->parseTmplAll();
if (defined($nref->{type}) and !defined($nref->{tag})) {
# we are at a leaf node.
findSetValues($new_ref, \@active_path);
@@ -385,11 +386,10 @@ sub findSetNodes {
sub getConfigDiff {
$active_cfg = new Vyatta::Config;
$new_cfg_ref = shift;
- my $ret_del_dis_nodes = shift;
@set_list = ();
# @disable_list = ();
@delete_list = ();
- findDeletedNodes($new_cfg_ref, $ret_del_dis_nodes, [ ]);
+ findDeletedNodes($new_cfg_ref, [ ]);
findSetNodes($new_cfg_ref, [ ]);
# need to filter out deletions of nodes with default values
@@ -401,7 +401,8 @@ sub getConfigDiff {
$file;
} @{${$del}[0]};
- my ($is_multi, $is_text, $default) = $active_cfg->parseTmpl(\@comps);
+ my ($is_multi, $is_text, $default)
+ = $active_cfg->parseTmpl(join ' ', @comps);
if (!defined($default)) {
push @new_delete_list, $del;
}
diff --git a/lib/Vyatta/ConfigOutput.pm b/lib/Vyatta/ConfigOutput.pm
index 1218a8d..acb2bb3 100755
--- a/lib/Vyatta/ConfigOutput.pm
+++ b/lib/Vyatta/ConfigOutput.pm
@@ -70,7 +70,9 @@ sub displayValues {
my $prefix = $_[2];
my $name = $_[3];
my $simple_show = $_[4];
- my ($is_multi, $is_text, $default) = $config->parseTmpl(\@cur_path);
+
+ $config->setLevel(join ' ', @cur_path);
+ my ($is_multi, $is_text, $default) = $config->parseTmpl();
if ($is_text) {
$default =~ /^"(.*)"$/;
my $txt = $1;
@@ -81,11 +83,10 @@ sub displayValues {
my $is_password = ($name =~ /^.*(passphrase|password|pre-shared-secret|key)$/);
my $HIDE_PASSWORD = '****************';
- $config->setLevel(join ' ', @cur_path);
if ($is_multi) {
- my @ovals = $config->returnOrigValues('','true');
- my @nvals = $config->returnValues('','true');
+ my @ovals = $config->returnOrigValuesDA();
+ my @nvals = $config->returnValuesDA();
if ($is_text) {
@ovals = map { (txt_need_quotes($_)) ? "\"$_\"" : "$_"; } @ovals;
@nvals = map { (txt_need_quotes($_)) ? "\"$_\"" : "$_"; } @nvals;
@@ -128,8 +129,8 @@ sub displayValues {
print "$dis$diff$prefix$name $nval\n";
}
} else {
- my $oval = $config->returnOrigValue('','true');
- my $nval = $config->returnValue('','true');
+ my $oval = $config->returnOrigValueDA();
+ my $nval = $config->returnValueDA();
if ($is_text) {
if (defined($oval) && txt_need_quotes($oval)) {
$oval = "\"$oval\"";
@@ -139,7 +140,7 @@ sub displayValues {
}
}
- my %cnodes = $config->listNodeStatus(undef,'true');
+ my %cnodes = $config->listNodeStatusDA();
my @cnames = sort keys %cnodes;
if (defined($simple_show)) {
@@ -189,16 +190,19 @@ sub displayDeletedOrigChildren {
if (defined($dont_show_as_deleted)) {
$dprefix = '';
}
- $config->setLevel('');
- my @children = $config->listOrigNodes(join(' ', @cur_path),'true');
+ $config->setLevel('');
+ my @children = $config->listOrigNodesDA(join(' ', @cur_path));
for my $child (sort @children) {
+ # reset level
+ $config->setLevel('');
+
if ($child eq 'node.val') {
# should not happen!
next;
}
- my $is_tag = $config->isTagNode([ @cur_path, $child ]);
+ my $is_tag = $config->isTagNode(join(' ', @cur_path, $child));
if (!defined $is_tag) {
my $path = join(' ',( @cur_path, $child ));
@@ -207,31 +211,37 @@ sub displayDeletedOrigChildren {
print "$prefix /* $comment */\n";
}
- my ($state, $n) = $config->getDeactivated($path);
- if (defined $state) {
- if ($state eq 'active') {
- $dis = '! ';
- }
- elsif ($state eq 'local') {
- if (defined($dont_show_as_deleted)) {
- $dis = ' ';
- }
- else {
- $dis = 'D ';
- }
- }
- else {
- $dis = '! ';
- }
- }
- else {
- $dis = ' ';
- }
+ # check deactivate state
+ my $de_working = $config->deactivated($path);
+ my $de_active = $config->deactivatedOrig($path);
+ if ($de_active) {
+ if ($de_working) {
+ # deactivated in both
+ $dis = '! ';
+ } else {
+ # deactivated only in active
+ $dis = '! ';
+ }
+ } else {
+ if ($de_working) {
+ # deactivated only in working
+ if (defined($dont_show_as_deleted)) {
+ $dis = ' ';
+ } else {
+ $dis = 'D ';
+ }
+ } else {
+ # deactivated in neither
+ $dis = ' ';
+ }
+ }
}
$config->setLevel(join ' ', (@cur_path, $child));
- my @cnames = grep(!/^def$/, sort($config->listOrigNodes(undef,'true')));
+ # remove listOrigNodesNoDef so it's one fewer function that uses
+ # the cstore implementation details at the perl API level.
+ my @cnames = grep(!/^def$/, sort($config->listOrigNodesDA()));
if ($cnames[0] eq 'node.val') {
displayValues([ @cur_path, $child ], $dis, $prefix, $child,
@@ -248,33 +258,37 @@ sub displayDeletedOrigChildren {
}
my $path = join(' ',( @cur_path, $child, $cname ));
+ $config->setLevel($path);
- my $comment = $config->returnComment($path);
+ my $comment = $config->returnComment();
if (defined $comment) {
print "$prefix /* $comment */\n";
}
- #need separate check here
- my ($state, $n) = $config->getDeactivated($path);
- if (defined $state) {
- if ($state eq 'active') {
- $dis = '! ';
- }
- elsif ($state eq 'local') {
- if (defined($dont_show_as_deleted)) {
- $dis = ' ';
- }
- else {
- $dis = 'D ';
- }
- }
- else {
- $dis = '! ';
- }
- }
- else {
- $dis = ' ';
- }
+ # check deactivate state
+ my $de_working = $config->deactivated();
+ my $de_active = $config->deactivatedOrig();
+ if ($de_active) {
+ if ($de_working) {
+ # deactivated in both
+ $dis = '! ';
+ } else {
+ # deactivated only in active
+ $dis = '! ';
+ }
+ } else {
+ if ($de_working) {
+ # deactivated only in working
+ if (defined($dont_show_as_deleted)) {
+ $dis = ' ';
+ } else {
+ $dis = 'D ';
+ }
+ } else {
+ # deactivated in neither
+ $dis = ' ';
+ }
+ }
print "$dis$dprefix$prefix$child $cname {\n";
displayDeletedOrigChildren([ @cur_path, $child, $cname ],
@@ -288,7 +302,7 @@ sub displayDeletedOrigChildren {
print "$dis$dprefix$prefix}\n";
}
} else {
- my $has_tmpl_children = $config->hasTmplChildren([ @cur_path, $child ]);
+ my $has_tmpl_children = $config->hasTmplChildren();
print "$dis$dprefix$prefix$child"
. ($has_tmpl_children ? " {\n$dis$dprefix$prefix}\n" : "\n");
}
@@ -323,7 +337,9 @@ sub displayChildren {
} elsif ($child_hash{$child} eq 'changed') {
$vdiff = '>';
}
- my $is_tag = $config->isTagNode([ @cur_path, $child ]);
+
+ $config->setLevel('');
+ my $is_tag = $config->isTagNode(join(' ', @cur_path, $child));
if (!defined($is_tag)) {
my $path = join(' ',( @cur_path, $child ));
@@ -332,30 +348,34 @@ sub displayChildren {
print "$prefix /* $comment */\n";
}
- my ($state, $n) = $config->getDeactivated($path);
- if (defined $state) {
- if ($state eq 'active') {
- if ($child_hash{$child} eq 'deleted') {
- $dis = '! ';
- }
- else {
- $dis = 'A ';
- }
- }
- elsif ($state eq 'local') {
- $dis = 'D ';
- }
- else {
- $dis = '! ';
- }
- }
- else {
- $dis = ' ';
- }
+ # check deactivate state
+ my $de_working = $config->deactivated($path);
+ my $de_active = $config->deactivatedOrig($path);
+ if ($de_active) {
+ if ($de_working) {
+ # deactivated in both
+ $dis = '! ';
+ } else {
+ # deactivated only in active
+ if ($child_hash{$child} eq 'deleted') {
+ $dis = '! ';
+ } else {
+ $dis = 'A ';
+ }
+ }
+ } else {
+ if ($de_working) {
+ # deactivated only in working
+ $dis = 'D ';
+ } else {
+ # deactivated in neither
+ $dis = ' ';
+ }
+ }
}
$config->setLevel(join ' ', (@cur_path, $child));
- my %cnodes = $config->listNodeStatus(undef,'true');
+ my %cnodes = $config->listNodeStatusDA();
my @cnames = sort keys %cnodes;
#if node.val exists and ct == 0 w/o def or ct ==1 w/ def
@@ -382,31 +402,36 @@ sub displayChildren {
}
my $path = join(' ',( @cur_path, $child, $cname ));
- my $comment = $config->returnComment($path);
+ $config->setLevel($path);
+ my $comment = $config->returnComment();
if (defined $comment) {
print "$prefix /* $comment */\n";
}
- my ($state, $n) = $config->getDeactivated($path);
- if (defined $state) {
- if ($state eq 'active') {
- if ($cnodes{$cname} eq 'deleted') {
- $dis = '! ';
- }
- else {
- $dis = 'A ';
- }
- }
- elsif ($state eq 'local') {
- $dis = 'D ';
- }
- else {
- $dis = '! ';
- }
- }
- else {
- $dis = ' ';
- }
+ # check deactivate state
+ my $de_working = $config->deactivated();
+ my $de_active = $config->deactivatedOrig();
+ if ($de_active) {
+ if ($de_working) {
+ # deactivated in both
+ $dis = '! ';
+ } else {
+ # deactivated only in active
+ if ($cnodes{$cname} eq 'deleted') {
+ $dis = '! ';
+ } else {
+ $dis = 'A ';
+ }
+ }
+ } else {
+ if ($de_working) {
+ # deactivated only in working
+ $dis = 'D ';
+ } else {
+ # deactivated in neither
+ $dis = ' ';
+ }
+ }
my $tdiff = ' ';
if ($cnodes{$cname} eq 'deleted') {
@@ -420,7 +445,7 @@ sub displayChildren {
$dis, "$prefix ");
} else {
$config->setLevel(join ' ', (@cur_path, $child, $cname));
- my %ccnodes = $config->listNodeStatus(undef,'true');
+ my %ccnodes = $config->listNodeStatusDA();
displayChildren(\%ccnodes, [ @cur_path, $child, $cname ],
$dis, "$prefix ");
}
@@ -439,7 +464,7 @@ sub displayChildren {
} else {
if ($child_hash{$child} eq 'deleted') {
$config->setLevel('');
- my @onodes = $config->listOrigNodes(join ' ', (@cur_path, $child), 'true');
+ my @onodes = $config->listOrigNodesDA(join ' ', (@cur_path, $child));
if ($#onodes == 0 && $onodes[0] eq 'node.val') {
displayValues([ @cur_path, $child ], $dis, $prefix, $child);
} else {
@@ -449,7 +474,7 @@ sub displayChildren {
}
} else {
my $has_tmpl_children
- = $config->hasTmplChildren([ @cur_path, $child ]);
+ = $config->hasTmplChildren();
print "$dis$diff$prefix$child"
. ($has_tmpl_children ? " {\n$dis$diff$prefix}\n" : "\n");
}
@@ -462,7 +487,7 @@ sub displayChildren {
sub outputNewConfig {
$config = new Vyatta::Config;
$config->setLevel(join ' ', @_);
- my %rnodes = $config->listNodeStatus(undef,'true');
+ my %rnodes = $config->listNodeStatusDA();
if (scalar(keys %rnodes) > 0) {
my @rn = keys %rnodes;
@@ -489,7 +514,8 @@ sub outputNewConfig {
if ($config->existsOrig() && ! $config->exists()) {
# this is a deleted node
print 'Configuration under "' . (join ' ', @_) . "\" has been deleted\n";
- } elsif (!defined($config->getTmplPath(\@_))) {
+ } elsif (!$config->validateTmplPath('', 1)) {
+ # validation of current path (including values) failed
print "Specified configuration path is not valid\n";
} else {
print 'Configuration under "' . (join ' ', @_) . "\" is empty\n";