diff options
Diffstat (limited to 'lib/Vyatta/Config.pm')
-rwxr-xr-x | lib/Vyatta/Config.pm | 751 |
1 files changed, 0 insertions, 751 deletions
diff --git a/lib/Vyatta/Config.pm b/lib/Vyatta/Config.pm deleted file mode 100755 index 1469994..0000000 --- a/lib/Vyatta/Config.pm +++ /dev/null @@ -1,751 +0,0 @@ -# Author: Vyatta <eng@vyatta.com> -# Date: 2007 -# Description: vyatta configuration parser - -# **** 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 **** - -package Vyatta::Config; - -use strict; - -use File::Find; - -use lib '/opt/vyatta/share/perl5'; -use Cstore; - -my %fields = ( - _level => undef, - _cstore => undef, -); - -sub new { - my ($that, $level) = @_; - my $class = ref ($that) || $that; - my $self = { - %fields, - }; - bless $self, $class; - $self->{_level} = $level if defined($level); - $self->{_cstore} = new Cstore(); - return $self; -} - -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 use the cstore library directly. -# they are either new functions or old ones that have been -# converted to use cstore. -############################################################ - -###### -# 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. -} - -## 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. -} - -## isDefault("path to node") -# Returns true if specified node is "default" in working config. -sub isDefault { - my ($self, $path) = @_; - return 1 - if ($self->{_cstore}->cfgPathDefault($self->get_path_comps($path), undef)); - return; # note: this return is needed. -} - -## isDefaultOrig("path to node") -# Returns true if specified node is "default" in active config. -sub isDefaultOrig { - my ($self, $path) = @_; - return 1 - if ($self->{_cstore}->cfgPathDefault($self->get_path_comps($path), 1)); - return; # note: this return is needed. -} - -## listNodes("level") -# return array of all child nodes at "level" in working config. -sub listNodes { - 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 child nodes at "level" in active config. -sub listOrigNodes { - 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") -# 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, $path, $include_deactivated) = @_; - die $DIE_DEACT_MSG if (defined($include_deactivated)); - return $self->{_cstore}->cfgPathGetValue($self->get_path_comps($path), - undef); -} - -## returnOrigValue("node") -# 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, $path, $include_deactivated) = @_; - die $DIE_DEACT_MSG if (defined($include_deactivated)); - return $self->{_cstore}->cfgPathGetValue($self->get_path_comps($path), 1); -} - -## returnValues("node") -# 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 ($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}; -} - -## 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}; -} - -## sessionChanged() -# return whether the config session has uncommitted changes -sub sessionChanged { - my ($self) = @_; - return $self->{_cstore}->sessionChanged(); -} - -## inSession() -# returns whether in a config session -sub inSession { - my ($self) = @_; - return $self->{_cstore}->inSession(); -} - -## loadFile() -# "load" the specified file -sub loadFile { - my ($self, $file) = @_; - return $self->{_cstore}->loadFile($file); -} - -###### -# 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. -} - -## 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); -} - -## 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)); -} - -## 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); -} - -## 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}; -} - -## 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") -# whether specified node has been deleted in working config -sub isDeleted { - 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 at specified "level" -sub listDeleted { - 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}; -} - -## returnDeletedValues("level") -# return array of deleted values of specified "multi node" -sub returnDeletedValues { - my ($self, $path) = @_; - my $ref = $self->{_cstore}->cfgPathGetDeletedValues( - $self->get_path_comps($path)); - return @{$ref}; -} - -## 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") -# 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, $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 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". -sub listNodeStatus { - 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}; -} - -## 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}; -} - -## 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. -} - -## 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 (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}); - } - } - return $href; -} - -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}; -} - -## returnComment("node") -# return comment of "node" in working config or undef if comment doesn't exist -sub returnComment { - my ($self, $path) = @_; - return $self->{_cstore}->cfgPathGetComment($self->get_path_comps($path), - undef); -} - -## returnOrigComment("node") -# return comment of "node" in active config or undef if comment doesn't exist -sub returnOrigComment { - my ($self, $path) = @_; - return $self->{_cstore}->cfgPathGetComment($self->get_path_comps($path), 1); -} - - -############################################################ -# high-level API functions (not using the cstore library directly) -############################################################ - -## 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}; -} - -## 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, $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); -} - -## 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}); -} - -## isMultiNode("path") -# whether specified path is a "multi leaf node", i.e., multi-value node. -sub isMultiNode { - my ($self, $path) = @_; - my $href = $self->parseTmplAll($path, 1); - return (defined($href) and !$href->{is_value} and $href->{type} - and $href->{multi}); -} - -## 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}); -} - -## 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 -# ordering changed, it is deleted then added). -# $0: \@orig_values -# $1: \@new_values -sub compareValueLists { - my $self = shift; - my @ovals = @{$_[0]}; - my @nvals = @{$_[1]}; - my %comp_hash = ( - 'deleted' => [], - 'added' => [], - ); - my $idx = 0; - my %ohash = map { $_ => ($idx++) } @ovals; - $idx = 0; - my %nhash = map { $_ => ($idx++) } @nvals; - my $min_changed_idx = 2**31; - my %dhash = (); - foreach (@ovals) { - if (!defined($nhash{$_})) { - push @{$comp_hash{'deleted'}}, $_; - $dhash{$_} = 1; - if ($ohash{$_} < $min_changed_idx) { - $min_changed_idx = $ohash{$_}; - } - } - } - foreach (@nvals) { - if (defined($ohash{$_})) { - if ($ohash{$_} != $nhash{$_}) { - if ($ohash{$_} < $min_changed_idx) { - $min_changed_idx = $ohash{$_}; - } - } - } - } - foreach (@nvals) { - if (defined($ohash{$_})) { - if ($ohash{$_} != $nhash{$_}) { - if (!defined($dhash{$_})) { - push @{$comp_hash{'deleted'}}, $_; - $dhash{$_} = 1; - } - push @{$comp_hash{'added'}}, $_; - } elsif ($ohash{$_} >= $min_changed_idx) { - # ordering unchanged, but something before it is changed. - if (!defined($dhash{$_})) { - push @{$comp_hash{'deleted'}}, $_; - $dhash{$_} = 1; - } - push @{$comp_hash{'added'}}, $_; - } else { - # this is before any changed value. do nothing. - } - } else { - push @{$comp_hash{'added'}}, $_; - } - } - return %comp_hash; -} - - -sub outputError { - my ($location,$msg) = @_; - print STDERR "_errloc_:[ " . join(" ",@{$location}) . " ]\n"; - print STDERR $msg . "\n\n"; -} - -############################################################ -# 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; - |