diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rwxr-xr-x | etc/bash_completion.d/20vyatta-cfg | 20 | ||||
-rwxr-xr-x | lib/Vyatta/Config.pm | 42 | ||||
-rwxr-xr-x | lib/Vyatta/ConfigLoad.pm | 48 | ||||
-rwxr-xr-x | lib/Vyatta/ConfigOutput.pm | 133 | ||||
-rw-r--r-- | scripts/vyatta-activate-config.pl | 107 | ||||
-rwxr-xr-x | scripts/vyatta-load-config.pl | 9 | ||||
-rw-r--r-- | src/commit2.c | 78 | ||||
-rw-r--r-- | src/common/defs.h | 7 | ||||
-rw-r--r-- | src/common/unionfs.c | 49 | ||||
-rw-r--r-- | src/common/unionfs.h | 1 |
11 files changed, 418 insertions, 77 deletions
diff --git a/Makefile.am b/Makefile.am index f483abe..69c10c7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,6 +50,7 @@ sbin_SCRIPTS += scripts/vyatta-cli-expand-var.pl sbin_SCRIPTS += scripts/vyatta-output-config.pl sbin_SCRIPTS += scripts/vyatta-save-config.pl sbin_SCRIPTS += scripts/vyatta-load-config.pl +sbin_SCRIPTS += scripts/vyatta-activate-config.pl sbin_SCRIPTS += scripts/vyatta-cfg-notify sbin_SCRIPTS += scripts/vyatta-irqaffin sbin_SCRIPTS += scripts/vyatta-auto-irqaffin.pl diff --git a/etc/bash_completion.d/20vyatta-cfg b/etc/bash_completion.d/20vyatta-cfg index 4463ee3..e17fd36 100755 --- a/etc/bash_completion.d/20vyatta-cfg +++ b/etc/bash_completion.d/20vyatta-cfg @@ -431,6 +431,18 @@ loadkey() eval "${vyatta_sbindir}/vyatta-load-user-key.pl $@" } +activate() +{ + #create or remove activate file + eval "${vyatta_sbindir}/vyatta-activate-config.pl activate $@" +} + +deactivate() +{ + #create or remove activate file + eval "${vyatta_sbindir}/vyatta-activate-config.pl deactivate $@" +} + vyatta_loadkey_complete() { case "$COMP_CWORD" in @@ -929,8 +941,10 @@ vyatta_config_complete () fi if (( ${#COMP_WORDS[@]} < 2 )); then - declare -a hitems=( "commit" \ + declare -a hitems=( "activate" \ + "commit" \ "copy" \ + "deactivate" \ "delete" \ "discard" \ "edit" \ @@ -944,8 +958,10 @@ vyatta_config_complete () "set" \ "show" ) declare -a hstrs=( \ + "Enable this portion of the configuration" \ "Commit the current set of changes" \ "Copy a configuration element" \ + "Inactivate this portion of the configuration" \ "Delete a configuration element" \ "Discard uncommitted changes" \ "Edit a sub-element" \ @@ -1294,6 +1310,8 @@ complete -F vyatta_loadsave_complete save complete -F vyatta_loadsave_complete load complete -F vyatta_loadsave_complete merge complete -F vyatta_loadkey_complete loadkey +complete -F vyatta_config_complete activate +complete -F vyatta_config_complete deactivate complete -F vyatta_config_complete copy complete -F vyatta_config_complete rename diff --git a/lib/Vyatta/Config.pm b/lib/Vyatta/Config.pm index 4ede95e..8de3aba 100755 --- a/lib/Vyatta/Config.pm +++ b/lib/Vyatta/Config.pm @@ -525,6 +525,48 @@ sub listDeleted { return @deleted; } +## isDeactivated("node") +# returns back whether this node is in an active (false) or +# deactivated (true) state. +sub getDeactivated { + my ($self, $node) = @_; + + if (!defined $node) { + } + + # 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 + + my @a = split(" ",$node); + $node = join("/",@a); + + while (1) { + my $filepath = "$self->{_changes_only_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); +} + ## isChanged("node") # will check the change_dir to see if the "node" has been changed from a previous # value. returns true or false. diff --git a/lib/Vyatta/ConfigLoad.pm b/lib/Vyatta/ConfigLoad.pm index 627b361..54befc6 100755 --- a/lib/Vyatta/ConfigLoad.pm +++ b/lib/Vyatta/ConfigLoad.pm @@ -86,7 +86,12 @@ sub enumerate_branch { if (defined($val)) { push @cur_path, $val; } - push @all_naked_nodes, [ @cur_path ]; + if (defined $cur_node->{'disable'}) { + push @all_naked_nodes, [ '!', @cur_path ]; + } + else { + push @all_naked_nodes, [ @cur_path ]; + } my @qpath = applySingleQuote(@cur_path); push @all_nodes, [\@qpath, 0]; } @@ -270,6 +275,7 @@ sub findDeletedNodes { } my @set_list = (); +my @disable_list = (); # find specified node's values in active config that are set # (added or changed). @@ -322,21 +328,33 @@ sub findSetNodes { return; } foreach (sort keys %{$new_ref}) { - if (scalar(keys %{$new_ref->{$_}}) == 0) { - # we are at a non-value leaf node. - # check if we need to add this node. - if (!defined($active_hash{$_})) { - my @plist = applySingleQuote(@active_path, $_); - push @set_list, [\@plist, 0]; - } else { - # node already present. do nothing. + if (scalar(keys %{$new_ref->{$_}}) == 0) { + # we are at a non-value leaf node. + # check if we need to add this node. + if (!defined($active_hash{$_})) { + my @plist = applySingleQuote(@active_path, $_); + if ($active_path[0] eq '!') { + my @tmp = @plist[1..$#plist]; + push @disable_list, [\@tmp, 0]; + push @set_list, [\@tmp, 0]; + } + else { + push @set_list, [\@plist, 0]; + } + } else { + # node already present. do nothing. + } + next; } - next; - } - # we recur regardless of whether it's in active. all changes will be - # handled when we reach leaf nodes (above). - findSetNodes($new_ref->{$_}, [ @active_path, $_ ]); + if ($active_path[0] eq '!') { + my @plist = applySingleQuote(@active_path, $_); + my @tmp = @plist[1..$#plist]; + push @disable_list, [\@tmp, 0]; + } + findSetNodes($new_ref->{$_}, [ @active_path, $_ ]); } + # we recur regardless of whether it's in active. all changes will be + # handled when we reach leaf nodes (above). } # compare the current active config with the specified hierarchy and return @@ -347,6 +365,7 @@ sub getConfigDiff { $active_cfg = new Vyatta::Config; $new_cfg_ref = shift; @set_list = (); + @disable_list = (); @delete_list = (); findDeletedNodes($new_cfg_ref, [ ]); findSetNodes($new_cfg_ref, [ ]); @@ -369,6 +388,7 @@ sub getConfigDiff { my %diff = ( 'delete' => \@new_delete_list, 'set' => \@set_list, + 'deactivate' => \@disable_list, ); return %diff; } diff --git a/lib/Vyatta/ConfigOutput.pm b/lib/Vyatta/ConfigOutput.pm index fd30049..fd377d7 100755 --- a/lib/Vyatta/ConfigOutput.pm +++ b/lib/Vyatta/ConfigOutput.pm @@ -66,9 +66,10 @@ my $config = undef; # deleted" from displayDeletedOrigChildren.) sub displayValues { my @cur_path = @{$_[0]}; - my $prefix = $_[1]; - my $name = $_[2]; - my $simple_show = $_[3]; + my $dis = $_[1]; + my $prefix = $_[2]; + my $name = $_[3]; + my $simple_show = $_[4]; my ($is_multi, $is_text, $default) = $config->parseTmpl(\@cur_path); if ($is_text) { $default =~ /^"(.*)"$/; @@ -99,7 +100,7 @@ sub displayValues { if ($is_password && $hide_password) { $oval = $HIDE_PASSWORD; } - print "$prefix$name $oval\n"; + print "$dis$prefix$name $oval\n"; } return; } @@ -108,7 +109,7 @@ sub displayValues { if ($is_password && $hide_password) { $del = $HIDE_PASSWORD; } - print "-$prefix$name $del\n"; + print "$dis-$prefix$name $del\n"; } } foreach my $nval (@nvals) { @@ -123,7 +124,7 @@ sub displayValues { if ($is_password && $hide_password) { $nval = $HIDE_PASSWORD; } - print "$diff$prefix$name $nval\n"; + print "$dis$diff$prefix$name $nval\n"; } } else { my $oval = $config->returnOrigValue(''); @@ -145,7 +146,7 @@ sub displayValues { if ($is_password && $hide_password) { $oval = $HIDE_PASSWORD; } - print "$prefix$name $oval\n"; + print "$dis$prefix$name $oval\n"; } return; } @@ -166,10 +167,10 @@ sub displayValues { if ($is_password && $hide_password) { $value = $HIDE_PASSWORD; } - print "$diff$prefix$name $value\n"; + print "$dis$diff$prefix$name $value\n"; } elsif ($cnodes{'def'} && ($diff eq '>' || $diff eq '-')) { - print "$diff$prefix$name $value\n"; + print "$dis$diff$prefix$name $value\n"; } } } @@ -180,25 +181,40 @@ sub displayValues { # deleted.) sub displayDeletedOrigChildren { my @cur_path = @{$_[0]}; - my $prefix = $_[1]; - my $dont_show_as_deleted = $_[2]; + my $dis = $_[1]; + my $prefix = $_[2]; + my $dont_show_as_deleted = $_[3]; 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 ]); + + if (!defined $is_tag) { + my $path = join(' ',( @cur_path, $child )); + my ($state, $n) = $config->getDeactivated($path); + if (defined $state) { + $dis = '! '; + } + else { + $dis = ''; + } + } + $config->setLevel(join ' ', (@cur_path, $child)); my @cnames = sort $config->listOrigNodesNoDef(); if ($cnames[0] eq 'node.val') { - displayValues([ @cur_path, $child ], $prefix, $child, + displayValues([ @cur_path, $child ], $dis, $prefix, $child, $dont_show_as_deleted); } elsif ($cnames[0] eq 'def') { #ignore @@ -210,21 +226,32 @@ sub displayDeletedOrigChildren { # should not happen next; } - print "$dprefix$prefix$child $cname {\n"; + + #need separate check here + my $path = join(' ',( @cur_path, $child, $cname )); + my ($state, $n) = $config->getDeactivated($path); + if (defined $state) { + $dis = '! '; + } + else { + $dis = ''; + } + + print "$dis$dprefix$prefix$child $cname {\n"; displayDeletedOrigChildren([ @cur_path, $child, $cname ], - "$prefix ", $dont_show_as_deleted); - print "$dprefix$prefix}\n"; + $dis,"$prefix ", $dont_show_as_deleted); + print "$dis$dprefix$prefix}\n"; } } else { - print "$dprefix$prefix$child {\n"; - displayDeletedOrigChildren([ @cur_path, $child ], "$prefix ", + print "$dis$dprefix$prefix$child {\n"; + displayDeletedOrigChildren([ @cur_path, $child ],$dis, "$prefix ", $dont_show_as_deleted); - print "$dprefix$prefix}\n"; + print "$dis$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"); + print "$dis$dprefix$prefix$child" + . ($has_tmpl_children ? " {\n$dis$dprefix$prefix}\n" : "\n"); } } } @@ -235,12 +262,18 @@ sub displayDeletedOrigChildren { sub displayChildren { my %child_hash = %{$_[0]}; my @cur_path = @{$_[1]}; - my $prefix = $_[2]; + my $dis = $_[2]; + my $prefix = $_[3]; for my $child (sort (keys %child_hash)) { + my $dis = ""; + my @tmp = @cur_path; + push (@tmp,$child); + if ($child eq 'node.val') { # should not happen! next; } + my ($diff, $vdiff) = (' ', ' '); if ($child_hash{$child} eq 'added') { $diff = '+'; @@ -252,6 +285,18 @@ sub displayChildren { $vdiff = '>'; } my $is_tag = $config->isTagNode([ @cur_path, $child ]); + + if (!defined($is_tag)) { + my $path = join(' ',( @cur_path, $child )); + my ($state, $n) = $config->getDeactivated($path); + if (defined $state) { + $dis = '! '; + } + else { + $dis = ''; + } + } + $config->setLevel(join ' ', (@cur_path, $child)); my %cnodes = $config->listNodeStatus(); my @cnames = sort keys %cnodes; @@ -269,7 +314,7 @@ sub displayChildren { } if ($leaf == 1) { - displayValues([ @cur_path, $child ], $prefix, $child); + displayValues([ @cur_path, $child ], $dis, $prefix, $child); } elsif (scalar($#cnames) >= 0) { if ($is_tag) { @cnames = sort versioncmp @cnames; @@ -278,50 +323,60 @@ sub displayChildren { # should not happen next; } + + my $path = join(' ',( @cur_path, $child, $cname )); + my ($state, $n) = $config->getDeactivated($path); + if (defined $state) { + $dis = '! '; + } + else { + $dis = ''; + } + my $tdiff = ' '; if ($cnodes{$cname} eq 'deleted') { $tdiff = '-'; } elsif ($cnodes{$cname} eq 'added') { $tdiff = '+'; } - print "$tdiff$prefix$child $cname {\n"; + print "$dis$tdiff$prefix$child $cname {\n"; if ($cnodes{$cname} eq 'deleted') { displayDeletedOrigChildren([ @cur_path, $child, $cname ], - "$prefix "); + $dis, "$prefix "); } else { $config->setLevel(join ' ', (@cur_path, $child, $cname)); my %ccnodes = $config->listNodeStatus(); displayChildren(\%ccnodes, [ @cur_path, $child, $cname ], - "$prefix "); + $dis, "$prefix "); } - print "$tdiff$prefix}\n"; + print "$dis$tdiff$prefix}\n"; } } else { - print "$diff$prefix$child {\n"; + print "$dis$diff$prefix$child {\n"; if ($child_hash{$child} eq 'deleted') { # this should not happen - displayDeletedOrigChildren([ @cur_path, $child ], "$prefix "); + displayDeletedOrigChildren([ @cur_path, $child ], $dis, "$prefix "); } else { - displayChildren(\%cnodes, [ @cur_path, $child ], "$prefix "); + displayChildren(\%cnodes, [ @cur_path, $child ], $dis, "$prefix "); } - print "$diff$prefix}\n"; + print "$dis$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); + displayValues([ @cur_path, $child ], $dis, $prefix, $child); } else { - print "$diff$prefix$child {\n"; - displayDeletedOrigChildren([ @cur_path, $child ], "$prefix "); - print "$diff$prefix}\n"; + print "$dis$diff$prefix$child {\n"; + displayDeletedOrigChildren([ @cur_path, $child ], $dis, "$prefix "); + print "$dis$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"); + print "$dis$diff$prefix$child" + . ($has_tmpl_children ? " {\n$dis$diff$prefix}\n" : "\n"); } } } @@ -350,9 +405,9 @@ sub outputNewConfig { if ($leaf == 1) { # this is a leaf value-node - displayValues([ @_ ], '', $_[$#_]); + displayValues([ @_ ], '', '', $_[$#_]); } else { - displayChildren(\%rnodes, [ @_ ], ''); + displayChildren(\%rnodes, [ @_ ], '', ''); } } else { if ($config->existsOrig() && ! $config->exists()) { @@ -371,7 +426,7 @@ sub outputNewConfig { sub outputActiveConfig { $config = new Vyatta::Config; $config->setLevel(join ' ', @_); - displayDeletedOrigChildren([ @_ ], '', 1); + displayDeletedOrigChildren([ @_ ], '','', 1); } 1; diff --git a/scripts/vyatta-activate-config.pl b/scripts/vyatta-activate-config.pl new file mode 100644 index 0000000..20f704d --- /dev/null +++ b/scripts/vyatta-activate-config.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl + +# Author: Michael Larson <mike@vyatta.com> +# Date: 2010 +# Description: Perl script for activating/deactivating portions 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, 2009, 2010 Vyatta, Inc. +# All Rights Reserved. +# **** End License **** + +use strict; +use warnings; +use File::Find; +use lib "/opt/vyatta/share/perl5"; + + +sub wanted { + return unless ( $_ eq '.disable' ); + print("Cannot set nested deactivated nodes\n"); + exit 1; +} + +sub usage() { + print "Usage: $0 <path>\n"; + exit 0; +} + +#adjust for leaf node +my $i = 0; +my @path = @ARGV[1..$#ARGV]; +foreach my $elem (@path) { + $elem =~ s/\//%2F/g; + $elem =~ s/\s+/\//g; + $path[$i++] = $elem; +} +my $path = join '/', @path; + +my $full_path = "$ENV{VYATTA_TEMP_CONFIG_DIR}/$path"; + +if (! -e $full_path) { + $path = join '/', @path[0..$#path-1]; + my $leaf = "$ENV{VYATTA_TEMP_CONFIG_DIR}/$path/node.val"; + if (-e $leaf) { + #prevent setting on leaf or multi, check for node.val +# $full_path = "$ENV{VYATTA_TEMP_CONFIG_DIR}/$path"; + printf("Cannot activate/deactivate end node\n"); + exit 1; + } + else { + printf("This command is not valid: $path\n"); + exit 1; + } +} + + +if ($ARGV[0] eq 'activate') { + $full_path .= "/.disable"; + if (-e $full_path) { + `rm -f $full_path`; + } + else { + printf("This element is not deactivated.\n"); + exit 1; + } +} +elsif ($ARGV[0] eq 'deactivate') { + #first let's check and ensure that there is not another child .disable node... + #also needs to be enforced when committing + my $active_dir = "$ENV{VYATTA_ACTIVE_CONFIGURATION_DIR}/$path"; + my $local_dir = $full_path; + if (-e $active_dir) { + find( \&wanted, $active_dir ); + } + if (-e $local_dir) { + find( \&wanted, $local_dir ); + } + `touch $full_path/.disable`; +} +elsif ($ARGV[0] eq 'complete') { + #provide match... + printf("complete\n"); +} +else { + printf("incoming arg: " . $ARGV[0] . "\n"); + usage(); +} + +#if this is activate +# make sure no activate subnodes +# create .disable file in node +#else +# ensure .disable file exists +# remove node + +print "Done\n"; +exit 0; diff --git a/scripts/vyatta-load-config.pl b/scripts/vyatta-load-config.pl index f0dbaf1..ab5a47e 100755 --- a/scripts/vyatta-load-config.pl +++ b/scripts/vyatta-load-config.pl @@ -190,6 +190,7 @@ if ( scalar( keys %cfg_hier ) == 0 ) { my %cfg_diff = Vyatta::ConfigLoad::getConfigDiff( \%cfg_hier ); my @set_list = @{ $cfg_diff{'set'} }; +my @deactivate_list = @{ $cfg_diff{'deactivate'} }; if ($merge_mode eq 'false') { my @delete_list = @{ $cfg_diff{'delete'} }; @@ -217,6 +218,14 @@ foreach (@set_list) { } } +foreach (@deactivate_list) { + my ( $cmd_ref, $rank ) = @{$_}; + my @cmd = ( "$sbindir/vyatta-activate-config.pl deactivate", @{$cmd_ref} ); + my $cmd_str = join ' ', @cmd; + system("$cmd_str 1>/dev/null"); + #ignore error on complaint re: nested nodes +} + system("$sbindir/my_commit"); if ( $? >> 8 ) { print "Load failed (commit failed)\n"; diff --git a/src/commit2.c b/src/commit2.c index 3db695f..af01598 100644 --- a/src/commit2.c +++ b/src/commit2.c @@ -363,6 +363,7 @@ process_func(GNode *node, gpointer data) gpointer gp = ((GNode*)node)->data; struct Config *c = &((struct VyattaNode*)gp)->_config; struct Data *d = &((struct VyattaNode*)gp)->_data; + NODE_OPERATION op = d->_operation; int status = 0; if (c->_def.actions && @@ -370,15 +371,32 @@ process_func(GNode *node, gpointer data) if (g_debug) { if (d->_name != NULL) { - printf("commit2::process_func(), calling process on : %s for action %d, type: %d, operation: %d, path: %s\n",d->_name,result->_action,c->_def.def_type, d->_operation, d->_path); - syslog(LOG_DEBUG,"commit2::process_func(), calling process on : %s for action %d, type: %d, operation: %d, path: %s",d->_name,result->_action,c->_def.def_type, d->_operation, d->_path); + printf("commit2::process_func(), calling process on : %s for action %d, type: %d, operation: %d, path: %s\n",d->_name,result->_action,c->_def.def_type, op, d->_path); + syslog(LOG_DEBUG,"commit2::process_func(), calling process on : %s for action %d, type: %d, operation: %d, path: %s",d->_name,result->_action,c->_def.def_type, op, d->_path); } else { - printf("commit2::process_func(), calling process on : [n/a] for action %d, operation: %d, path: %s\n",result->_action, d->_operation, d->_path); - syslog(LOG_DEBUG,"commit2::process_func(), calling process on : [n/a] for action %d, operation: %d, path: %s",result->_action, d->_operation, d->_path); + printf("commit2::process_func(), calling process on : [n/a] for action %d, operation: %d, path: %s\n",result->_action, op, d->_path); + syslog(LOG_DEBUG,"commit2::process_func(), calling process on : [n/a] for action %d, operation: %d, path: %s",result->_action, op, d->_path); } } + //FIRST LET'S COMPUTE THE DEACTIVATE->ACTIVATE OVERRIDE + if (d->_disable_op != K_NO_DISABLE_OP) { + if ((d->_disable_op & K_LOCAL_DISABLE_OP) && (d->_disable_op & K_ACTIVE_DISABLE_OP)) { + //no state change: deactivated + return FALSE; //skip operation on node + } + else if (!(d->_disable_op & K_LOCAL_DISABLE_OP) && (d->_disable_op & K_ACTIVE_DISABLE_OP)) { + //node will be activated on commit + //LET'S SPOOF the operation... convert it to CREATE + op = K_CREATE_OP; + } + else if ((d->_disable_op & K_LOCAL_DISABLE_OP) && !(d->_disable_op & K_ACTIVE_DISABLE_OP)) { + //node will be deactivated on commit + //LET'S SPOOF the operation... convert it to DELETE + op = K_DEL_OP; + } + } /* Needs to be cleaned up a bit such that this convoluted if clause is easier to read. Basically is says: @@ -388,15 +406,15 @@ process_func(GNode *node, gpointer data) or if a node is DELETE, is a DELETE ACTION or a END ACTION, or a BEGIN ACTION */ - if ((IS_SET(d->_operation) && !IS_ACTIVE(d->_operation) && (result->_action != delete_act && result->_action != create_act)) || - (IS_CREATE(d->_operation) && !IS_ACTIVE(d->_operation) && (result->_action == begin_act || result->_action == end_act || result->_action == create_act || (result->_action == update_act && !c->_def.actions[create_act].vtw_list_head))) || - (IS_ACTIVE(d->_operation) && ((result->_action == begin_act) || (result->_action == end_act))) || - (IS_DELETE(d->_operation) && ((result->_action == delete_act) || (result->_action == begin_act) || (result->_action == end_act)) )) { + if ((IS_SET(op) && !IS_ACTIVE(op) && (result->_action != delete_act && result->_action != create_act)) || + (IS_CREATE(op) && !IS_ACTIVE(op) && (result->_action == begin_act || result->_action == end_act || result->_action == create_act || (result->_action == update_act && !c->_def.actions[create_act].vtw_list_head))) || + (IS_ACTIVE(op) && ((result->_action == begin_act) || (result->_action == end_act))) || + (IS_DELETE(op) && ((result->_action == delete_act) || (result->_action == begin_act) || (result->_action == end_act)) )) { //NEED TO ADD IF CREATE, THEN CREATE OR UPDATE //IF SET THEN UPDATE //let's skip the case where this is active and it's a delete--shouldn't be done, but needs to be include in the rule set above - if (IS_DELETE(d->_operation) && IS_ACTIVE(d->_operation) && result->_action == delete_act) { + if (IS_DELETE(op) && IS_ACTIVE(op) && result->_action == delete_act && d->_disable_op == K_NO_DISABLE_OP) { //only apply this when no disable operation is set return FALSE; } @@ -475,8 +493,8 @@ process_func(GNode *node, gpointer data) } //do not set for promoted actions - if (!IS_ACTIVE(d->_operation)) { - if (IS_DELETE(d->_operation)) { + if (!IS_ACTIVE(op)) { + if (IS_DELETE(op)) { setenv(ENV_ACTION_NAME,ENV_ACTION_DELETE,1); } else { @@ -688,6 +706,7 @@ sort_func(GNode *node, gpointer data, boolean priority_mode) //change action state of node according to enclosing behavior if ((G_NODE_IS_ROOT(node) == FALSE) && + (((struct VyattaNode*)gp)->_data._disable_op != K_NO_DISABLE_OP) || //added to support enclosing behavior of activated/deactivated nodes ((IS_SET_OR_CREATE(((struct VyattaNode*)gp)->_data._operation)) || (IS_DELETE(((struct VyattaNode*)gp)->_data._operation))) && (IS_NOOP(((struct VyattaNode*)(node->parent->data))->_data._operation))) { @@ -713,7 +732,11 @@ sort_func(GNode *node, gpointer data, boolean priority_mode) while (TRUE) { n = n->parent; vtw_def def = ((struct VyattaNode*)(n->data))->_config._def; - ((struct VyattaNode*)(n->data))->_data._operation = ((struct VyattaNode*)gp)->_data._operation | K_ACTIVE_OP; + ((struct VyattaNode*)(n->data))->_data._operation = ((struct VyattaNode*)gp)->_data._operation; + //DON'T set active when only in disable state... + if (((struct VyattaNode*)gp)->_data._disable_op == K_NO_DISABLE_OP) { + ((struct VyattaNode*)(n->data))->_data._operation |= K_ACTIVE_OP; + } if (def.actions[end_act].vtw_list_head || def.actions[begin_act].vtw_list_head) { break; } @@ -890,21 +913,37 @@ dump_func(GNode *node, gpointer data) if (((struct VyattaNode*)gp)->_data._name != NULL) { int i; + char disable_op[2]; + if (((struct VyattaNode*)gp)->_data._disable_op == (K_ACTIVE_DISABLE_OP | K_LOCAL_DISABLE_OP)) { + disable_op[0] = 'c'; + } + else if (((struct VyattaNode*)gp)->_data._disable_op == K_ACTIVE_DISABLE_OP) { + disable_op[0] = 'u'; + } + else if (((struct VyattaNode*)gp)->_data._disable_op == K_LOCAL_DISABLE_OP) { + disable_op[0] = 's'; + } + else { + disable_op[0] = ' '; + } + disable_op[1] = '\0'; + if (IS_ACTIVE(((struct VyattaNode*)gp)->_data._operation)) { - fprintf(out,"*"); + fprintf(out,"%s*",disable_op); } else if (IS_DELETE(((struct VyattaNode*)gp)->_data._operation)) { - fprintf(out,"-"); + fprintf(out,"%s-",disable_op); } else if (IS_CREATE(((struct VyattaNode*)gp)->_data._operation)) { - fprintf(out,"+"); + fprintf(out,"%s+",disable_op); } else if (IS_SET(((struct VyattaNode*)gp)->_data._operation)) { - fprintf(out,">"); + fprintf(out,"%s>",disable_op); } else { - fprintf(out," "); + fprintf(out,"%s ",disable_op); } + for (i = 0; i < depth; ++i) { fprintf(out," "); } @@ -1171,6 +1210,11 @@ validate_func(GNode *node, gpointer data) } } + //don't perform validation checks on disabled nodes + if (d->_disable_op == K_LOCAL_DISABLE_OP) { + return FALSE; //SHOULD only hit the case where the node is locally disabled or globally disabled and not in a transition to active state + } + if (IS_DELETE(d->_operation) && !IS_ACTIVE(d->_operation)) { return FALSE; //will not perform validation checks on deleted nodes } diff --git a/src/common/defs.h b/src/common/defs.h index 6f97e9b..88b8441 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -35,6 +35,12 @@ typedef enum { K_DEL_OP = 0x10 } NODE_OPERATION; +typedef enum { + K_NO_DISABLE_OP = 0X00, + K_LOCAL_DISABLE_OP = 0x02, //MEANS DISABLE FLAG IS SET IN LOCAL CONFIGURATION + K_ACTIVE_DISABLE_OP = 0x04 //MEANS DISABLE FLAG IS SET IN ACTIVE CONFIGURATION +} NODE_ACTIVATE; + #define IS_SET(op) (op & K_SET_OP) #define IS_ACTIVE(op) (op & K_ACTIVE_OP) #define IS_CREATE(op) (op & K_CREATE_OP) @@ -72,6 +78,7 @@ struct Data boolean _value; //is this a value? char* _path; NODE_OPERATION _operation; //no-op, set, or delete + NODE_ACTIVATE _disable_op; //is this node currently deactivated? }; struct VyattaNode diff --git a/src/common/unionfs.c b/src/common/unionfs.c index 2be210e..151c6ce 100644 --- a/src/common/unionfs.c +++ b/src/common/unionfs.c @@ -189,6 +189,7 @@ retrieve_data(char* rel_data_path, GNode *node, char* root, NODE_OPERATION op) vn->_data._name = cp; vn->_data._value = FALSE;//TRUE; //data value vn->_data._operation = op; + vn->_data._disable_op = K_NO_DISABLE_OP; vn->_config._priority = LOWEST_PRIORITY; vn->_data._path = malloc(MAX_LENGTH_DIR_PATH*sizeof(char)); sprintf(vn->_data._path,"%s",rel_data_path); @@ -280,9 +281,7 @@ retrieve_data(char* rel_data_path, GNode *node, char* root, NODE_OPERATION op) } if (G_NODE_IS_ROOT(node) == FALSE) { - struct VyattaNode* vn_parent = (struct VyattaNode*)node->parent->data; struct VyattaNode* vn = (struct VyattaNode*)node->data; - // vn->_config._priority = vn_parent->_config._def.def_priority; if (vn->_config._def.tag && vn->_config._multi) { vn->_config._priority = LOWEST_PRIORITY; @@ -343,19 +342,49 @@ retrieve_data(char* rel_data_path, GNode *node, char* root, NODE_OPERATION op) strcmp(dirp->d_name, "..") != 0 && strcmp(dirp->d_name, MODIFIED_FILE) != 0 && strcmp(dirp->d_name, DEF_FILE) != 0 && + strcmp(dirp->d_name, DISABLE_FILE) != 0 && strcmp(dirp->d_name, WHITEOUT_FILE) != 0 && strcmp(dirp->d_name, VALUE_FILE) != 0) { processed = TRUE; + + NODE_ACTIVATE deactivated = K_NO_DISABLE_OP; + if (G_NODE_IS_ROOT(node) == FALSE && ((struct VyattaNode*)node->data)->_data._disable_op != K_NO_DISABLE_OP) { + deactivated = ((struct VyattaNode*)node->data)->_data._disable_op; + } + else { //do a lstat check in the local dir + struct stat s; + char buf[MAX_LENGTH_HELP_STR]; + sprintf(buf,"%s/%s/%s/%s",get_mdirp(),rel_data_path,dirp->d_name,DISABLE_FILE); + if (lstat(buf,&s) == 0) { + //need to check existence of file in active configuration here as well! + deactivated |= K_LOCAL_DISABLE_OP; + } + sprintf(buf,"%s/%s/%s/%s",get_adirp(),rel_data_path,dirp->d_name,DISABLE_FILE); + if (lstat(buf,&s) == 0) { + deactivated |= K_ACTIVE_DISABLE_OP; + } + } + char *data_buf = malloc(MAX_LENGTH_DIR_PATH*sizeof(char)); - if (strncmp(dirp->d_name,DELETED_NODE,4) == 0) { - strcpy(data_buf,dirp->d_name+4); //SKIP THE .WH. + if (strncmp(dirp->d_name,DELETED_NODE,4) == 0 || + deactivated != K_NO_DISABLE_OP) { + + struct VyattaNode *vn = calloc(1,sizeof(struct VyattaNode)); + + if (strncmp(dirp->d_name,DELETED_NODE,4) == 0) { + strcpy(data_buf,dirp->d_name+4); //SKIP THE .WH. + vn->_data._operation = K_DEL_OP; + } + else { + strcpy(data_buf,dirp->d_name); + vn->_data._operation = K_NO_OP; + } //create new node and insert... - struct VyattaNode *vn = calloc(1,sizeof(struct VyattaNode)); vn->_data._name = data_buf; vn->_data._value = FALSE; - vn->_data._operation = K_DEL_OP; vn->_config._priority = LOWEST_PRIORITY; + vn->_data._disable_op = deactivated; char new_data_path[MAX_LENGTH_DIR_PATH]; sprintf(new_data_path,"%s/%s",rel_data_path,data_buf); @@ -374,6 +403,7 @@ retrieve_data(char* rel_data_path, GNode *node, char* root, NODE_OPERATION op) vn->_data._name = data_buf; vn->_data._value = FALSE; vn->_config._priority = LOWEST_PRIORITY; + vn->_data._disable_op = deactivated; char new_data_path[MAX_LENGTH_DIR_PATH]; sprintf(new_data_path,"%s/%s",rel_data_path,data_buf); @@ -444,6 +474,7 @@ retrieve_data(char* rel_data_path, GNode *node, char* root, NODE_OPERATION op) vn->_data._value = FALSE; vn->_data._operation = K_DEL_OP; vn->_config._priority = LOWEST_PRIORITY; + vn->_data._disable_op = K_NO_DISABLE_OP; GNode *new_node = g_node_new(vn); new_node = insert_sibling_in_order(node,new_node); @@ -473,6 +504,7 @@ common_get_local_session_data() struct VyattaNode *vn = calloc(1,sizeof(struct VyattaNode)); vn->_data._name = NULL; //root node has null vn->_data._operation = K_NO_OP; + vn->_data._disable_op = K_NO_DISABLE_OP; vn->_config._priority = LOWEST_PRIORITY; //create first node @@ -902,6 +934,7 @@ copy_vyatta_node(struct VyattaNode* vn) strcpy(new_vn->_data._path,vn->_data._path); } new_vn->_data._operation = vn->_data._operation; + new_vn->_data._disable_op = vn->_data._disable_op; new_vn->_config._multi = vn->_config._multi; new_vn->_config._priority = vn->_config._priority; new_vn->_config._priority_extended = vn->_config._priority_extended; @@ -1070,6 +1103,10 @@ dlist_test_func(GQuark key_id,gpointer data,gpointer user_data) strcpy(new_vn->_data._name,(char*)g_quark_to_string(key_id)); new_vn->_config._path = malloc(MAX_LENGTH_DIR_PATH*sizeof(char)); sprintf(new_vn->_config._path,"%s/node.tag",vn_parent->_config._path); + + //let's set this nodes disable_op to its parent's value. + new_vn->_data._disable_op = vn_parent->_data._disable_op; + new_vn->_data._operation = ((struct ValueData*)data)->_state; new_vn->_config._def = vn_parent->_config._def; } diff --git a/src/common/unionfs.h b/src/common/unionfs.h index 098ac41..2933deb 100644 --- a/src/common/unionfs.h +++ b/src/common/unionfs.h @@ -23,6 +23,7 @@ #define NODE_TAG_FILE "node.tag" #define VALUE_FILE "node.val" #define MODIFIED_FILE ".modified" +#define DISABLE_FILE ".disable" #define DEF_FILE "def" #define WHITEOUT_FILE ".wh.__dir_opaque" #define DELETED_NODE ".wh." |