summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/VyattaConfigLoad.pm1
-rwxr-xr-xscripts/vyatta-interfaces.pl85
-rwxr-xr-xscripts/vyatta-watchlink-exclude.pl16
-rw-r--r--src/commit.c284
4 files changed, 264 insertions, 122 deletions
diff --git a/scripts/VyattaConfigLoad.pm b/scripts/VyattaConfigLoad.pm
index c4ce8bd..2efa81e 100755
--- a/scripts/VyattaConfigLoad.pm
+++ b/scripts/VyattaConfigLoad.pm
@@ -40,6 +40,7 @@ my %config_rank = (
'protocols static' => 85,
'service ssh' => 84,
'service telnet' => 83,
+ 'policy' => 82,
'vpn' => 80,
);
diff --git a/scripts/vyatta-interfaces.pl b/scripts/vyatta-interfaces.pl
index c60288a..28b1c14 100755
--- a/scripts/vyatta-interfaces.pl
+++ b/scripts/vyatta-interfaces.pl
@@ -33,9 +33,12 @@
use lib "/opt/vyatta/share/perl5/";
use VyattaConfig;
use VyattaMisc;
+
use Getopt::Long;
use POSIX;
use NetAddr::IP;
+use Tie::File;
+use Fcntl qw (:flock);
use strict;
use warnings;
@@ -325,6 +328,22 @@ sub update_eth_addrs {
exit 1;
}
+sub if_nametoindex {
+ my ($intf) = @_;
+
+ open my $sysfs, "<", "/sys/class/net/$intf/ifindex"
+ || die "Unknown interface $intf";
+ my $ifindex = <$sysfs>;
+ close($sysfs) or die "read sysfs error\n";
+ chomp $ifindex;
+
+ return $ifindex;
+}
+
+sub htonl {
+ return unpack('L',pack('N',shift));
+}
+
sub delete_eth_addrs {
my ($addr, $intf) = @_;
@@ -335,41 +354,49 @@ sub delete_eth_addrs {
exit 0;
}
my $version = is_ip_v4_or_v6($addr);
+ if ($version == 6) {
+ exec 'ip', '-6', 'addr', 'del', $addr, 'dev', $intf
+ or die "Could not exec ip?";
+ }
+
+ ($version == 4) or die "Bad ip version";
- # If interface has address than delete it
if (is_ip_configured($intf, $addr)) {
- if ($version == 4) {
- exec 'ip', 'addr', 'del', $addr, 'dev', $intf;
- } elsif ($version == 6) {
- exec 'ip', '-6', 'addr', 'del', $addr, 'dev', $intf;
- } else {
- die "Bad ip version";
- }
- die "Can't exec ip";
+ # Link is up, so just delete address
+ # Zebra is watching for netlink events and will handle it
+ exec 'ip', 'addr', 'del', $addr, 'dev', $intf
+ or die "Could not exec ip?";
}
+
- # Interface address might have been removed by quagga link going down
- # so tell quagga no to restore it on link-detect
- my $vtysh;
- if ( -x '/usr/bin/vyatta-vtysh' ) {
- $vtysh = '/usr/bin/vyatta-vtysh';
- } else {
- $vtysh = '/usr/bin/vtysh';
- }
+ # Destroy watchlink's internal status so it doesn't erronously
+ # restore the address when link is restored
+ my $statusfile = '/var/linkstatus/' . if_nametoindex($intf);
- my @cmd = ();
- if ($version == 4) {
- @cmd = ('vtysh', '-c',
- "configure terminal; interface $intf; no ip address $intf" );
- } elsif ($version == 6) {
- @cmd = ('vtysh', '-c',
- "configure terminal; interface $intf; no ip6 address $intf" );
- } else {
- die "Bad ip version";
- }
- exec $vtysh, @cmd;
+ # Use tie to treat file as array
+ my $tie = tie my @status, 'Tie::File', $statusfile
+ or die "can't open $statusfile";
+
+ $tie->flock(LOCK_EX); # Block out watchlink
+ $tie = undef; # Drop reference so untie will work
- die "Can't exec vtysh";
+ my $ip = NetAddr::IP->new($addr);
+ my $recno = 0;
+ foreach my $line (@status) {
+ chomp $line;
+
+ # The format of watchlink file is host byte order (IPV6??)
+ my ($ifindex, $raddr, $bcast, $prefix) = split (/,/, $line);
+ my $laddr = htonl($raddr);
+ my $this = NetAddr::IP->new("$laddr/$prefix");
+ if ($ip eq $this) {
+ splice @status, $recno, 1; # delete the line
+ } else {
+ $recno++;
+ }
+ }
+ untie @status;
+ exit 0;
}
sub update_mac {
diff --git a/scripts/vyatta-watchlink-exclude.pl b/scripts/vyatta-watchlink-exclude.pl
index 048946c..eb9d280 100755
--- a/scripts/vyatta-watchlink-exclude.pl
+++ b/scripts/vyatta-watchlink-exclude.pl
@@ -112,6 +112,18 @@ sub remove_exclude_line {
return @new_lines;
}
+sub is_exclude_dup {
+ my ($new_line, @lines) = @_;
+
+ my $frag = substr($new_line, 0, index($new_line, ' #'));
+ foreach my $line (@lines) {
+ if (substr($line, 0, index($line, ' #')) eq $frag) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
#
# main
@@ -148,7 +160,9 @@ if (defined $opt_id) {
}
if ($opt_action eq "add") {
- push @lines, $new_line;
+ if (! is_exclude_dup($new_line, @lines)) {
+ push @lines, $new_line;
+ }
} elsif (defined $opt_intf) {
@lines = remove_exclude_line($new_line, @lines);
} else {
diff --git a/src/commit.c b/src/commit.c
index 8fbc1d6..534757c 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -53,6 +53,23 @@ static void make_dir()
}
#endif
+static struct dirent *
+get_next_filtered_dirent(DIR *dp, int exclude_wh)
+{
+ struct dirent *dirp = NULL;
+ while ((dirp = readdir(dp)) != NULL) {
+ if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0
+ || strcmp(dirp->d_name, MOD_NAME) == 0
+ || strcmp(dirp->d_name, opaque_name) == 0
+ || (exclude_wh && strncmp(dirp->d_name, ".wh.", 4) == 0)) {
+ continue;
+ } else {
+ return dirp;
+ }
+ }
+ return dirp;
+}
+
/*************************************************
validate_dir_for_commit:
validate value.value if there is one, validate
@@ -114,16 +131,7 @@ static boolean validate_dir_for_commit()
push_path(&t_path, tag_name); /* PUSH 2a */
}
- while ((dirp = readdir(dp)) != NULL) {
-
- if (strcmp(dirp->d_name, ".") == 0 ||
- strcmp(dirp->d_name, "..") == 0 ||
- strcmp(dirp->d_name, MOD_NAME) == 0 ||
- strcmp(dirp->d_name, opaque_name) == 0 ||
- strncmp(dirp->d_name, ".wh.", 4) == 0) {
- continue; /*ignore dot and dot-dot*/
- }
-
+ while ((dirp = get_next_filtered_dirent(dp, 1)) != NULL) {
subdirs_number++;
if(uename)
@@ -916,25 +924,141 @@ static boolean commit_delete_child(vtw_def *pdefp, char *child,
return ok;
}
+/* add a value to the valstruct. struct must be initialized (memset 0).
+ * cp: pointer to value
+ * type: type of value
+ */
+static void
+valstruct_append(valstruct *mvals, char *cp, vtw_type_e type)
+{
+ if (!(mvals->free_me)) {
+ /* empty struct. add 1st value */
+ mvals->free_me = TRUE;
+ mvals->val = cp;
+ mvals->val_type = type;
+ } else {
+ if ((mvals->cnt % MULTI_ALLOC) == 0) {
+ /* convert into multivalue */
+ mvals->vals = my_realloc(mvals->vals, (mvals->cnt + MULTI_ALLOC)
+ * sizeof(char *), "add_value");
+ if (mvals->cnt == 0) { /* single value - convert */
+ mvals->vals[0] = mvals->val;
+ mvals->cnt= 1;
+ mvals->val = NULL;
+ }
+ }
+ mvals->vals[mvals->cnt] = cp;
+ ++mvals->cnt;
+ }
+}
+
+/* get the filtered directory listing and put the names in valstruct.
+ * dp: target directory
+ * mvals: structure for storing the names
+ * type: type of the names
+ * exclude_wh: exclude whiteouts
+ */
+static void
+get_filtered_directory_listing(DIR *dp, valstruct *mvals, vtw_type_e type,
+ int exclude_wh)
+{
+ struct dirent *dirp = NULL;
+ char *cp = NULL;
+
+ memset(mvals, 0, sizeof (valstruct));
+ while ((dirp = get_next_filtered_dirent(dp, exclude_wh)) != NULL) {
+ cp = clind_unescape(dirp->d_name);
+ valstruct_append(mvals, cp, type);
+ }
+}
+
+/* check if a value is one of those in a valstruct.
+ * cp: pointer to value
+ * vals: pointer to valstruct
+ *
+ * return 1 if yes, 0 otherwise.
+ * TODO: optimization
+ */
+static int
+is_val_in_valstruct(char *cp, valstruct *vals)
+{
+ int i = 0;
+ if (!(vals->free_me)) {
+ /* empty struct. */
+ return 0;
+ }
+ if (vals->cnt == 0) {
+ /* single-value struct */
+ if (strcmp(cp, vals->val) == 0) {
+ return 1;
+ }
+ return 0;
+ }
+ /* multi-value */
+ for (i = 0; i < vals->cnt; i++) {
+ if (strcmp(cp, vals->vals[i]) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* returns the value at a particular index in a valstruct.
+ * vals: pointer to the valstruct
+ * idx: index of the value
+ *
+ * return pointer to the value, NULL if idx is not valid.
+ */
+static char *
+idx_val_in_valstruct(valstruct *vals, int idx)
+{
+ if (!(vals->free_me)) {
+ /* empty struct. */
+ return NULL;
+ }
+ if (vals->cnt == 0) {
+ /* single-value struct */
+ if (idx == 0) {
+ return vals->val;
+ }
+ return NULL;
+ }
+ /* multi-value */
+ if ((idx < 0) || (idx >= vals->cnt)) {
+ return NULL;
+ }
+ return vals->vals[idx];
+}
+
+
static boolean commit_delete_children(vtw_def *defp, boolean deleting,
boolean in_txn)
{
- DIR *dp;
- int status;
- struct dirent *dirp;
+ DIR *dp, *adp = NULL, *mdp = NULL;
boolean ok = TRUE;
char *child;
vtw_type_e type;
- valstruct mvals;
- boolean first;
- char *cp;
+ valstruct mvals, valsA, valsM;
int elem, curi;
vtw_sorted cur_sorted;
- char *uename = NULL;
+
+ if (!deleting) {
+ switch_path(APATH); /* switch to active */
+ if ((adp = opendir(m_path.path)) == NULL) {
+ INTERNAL;
+ }
+ switch_path(MPATH); /* switch to modified */
+ if ((mdp = opendir(m_path.path)) == NULL) {
+ INTERNAL;
+ }
+ switch_path(CPATH); /* back to changes */
+ }
if ((dp = opendir(m_path.path)) == NULL){
- if (deleting)
+ if (deleting) {
+ /* deleting. adp & mdp are not opened so no need to close. */
return TRUE;
+ }
INTERNAL;
}
if (defp)
@@ -943,44 +1067,56 @@ static boolean commit_delete_children(vtw_def *defp, boolean deleting,
type = TEXT_TYPE;
if (type == ERROR_TYPE)
type = TEXT_TYPE;
- first = TRUE;
memset(&mvals, 0, sizeof (valstruct));
+ memset(&valsA, 0, sizeof (valstruct));
+ memset(&valsM, 0, sizeof (valstruct));
memset(&cur_sorted, 0, sizeof(vtw_sorted));
- while ((dirp = readdir(dp)) != NULL) {
- child = dirp->d_name;
- if (strcmp(child, ".") == 0 ||
- strcmp(child, "..") == 0 ||
- strcmp(child, MOD_NAME) == 0 ||
- strcmp(child, OPQ_NAME) == 0)
- continue;
- uename = clind_unescape(child);
- cp = uename;
- if (first) {
- mvals.free_me = TRUE;
- mvals.val = cp;
- mvals.val_type = type;
- first = FALSE;
- } else {
- if (mvals.cnt%MULTI_ALLOC == 0) {
- /* convert into multivalue */
- mvals.vals = my_realloc(mvals.vals,
- (mvals.cnt + MULTI_ALLOC) *
- sizeof(char *), "add_value");
- if (mvals.cnt == 0) { /* single value - convert */
- mvals.vals[0] = mvals.val;
- mvals.cnt= 1;
- mvals.val = NULL;
- }
+ /* changes directory */
+ get_filtered_directory_listing(dp, &mvals, type, 0);
+ if (closedir(dp) != 0) {
+ INTERNAL;
+ }
+
+ if (adp && mdp) {
+ /* active directory */
+ get_filtered_directory_listing(adp, &valsA, type, 0);
+ if (closedir(adp) != 0) {
+ INTERNAL;
+ }
+ /* modified directory */
+ get_filtered_directory_listing(mdp, &valsM, type, 0);
+ if (closedir(mdp) != 0) {
+ INTERNAL;
+ }
+
+ if (valsA.free_me) {
+ /* A is not empty */
+ int idx = 0;
+ char *cp = NULL;
+ for (idx = 0; (cp = idx_val_in_valstruct(&valsA, idx)); idx++) {
+ if (!is_val_in_valstruct(cp, &valsM)) {
+ /* cp is in A but not in M */
+ /* construct whiteout name */
+ char *wh_name = my_malloc(strlen(cp) + 4 + 1, "del_children");
+ strcpy(wh_name, ".wh.");
+ strcpy(wh_name + 4, cp);
+ if (!is_val_in_valstruct(wh_name, &mvals)) {
+ /* whiteout not in C */
+ /* add whiteout to mvals */
+ valstruct_append(&mvals, wh_name, type);
+ }
+ }
}
- mvals.vals[mvals.cnt] = cp;
- ++mvals.cnt;
+ free_val(&valsA);
+ }
+ if (valsM.free_me) {
+ free_val(&valsM);
}
}
- status = closedir(dp);
- if (status)
- INTERNAL;
- if (first) {
+
+ if (!(mvals.free_me)) {
+ /* empty struct. nothing to do. */
return TRUE;
}
vtw_sort(&mvals, &cur_sorted);
@@ -1006,18 +1142,12 @@ static boolean commit_update_children(vtw_def *defp, boolean creating,
boolean in_txn, boolean *parent_update)
{
DIR *dp;
- int status;
- struct dirent *dirp;
boolean ok = TRUE;
char *child;
vtw_type_e type;
valstruct mvals;
- boolean first;
- char *cp;
int elem, curi;
vtw_sorted cur_sorted;
- char *uename = NULL;
-
if ((dp = opendir(m_path.path)) == NULL){
printf("%s:%d: opendir error: path=%s\n",
@@ -1033,43 +1163,14 @@ static boolean commit_update_children(vtw_def *defp, boolean creating,
type = TEXT_TYPE;
if (type == ERROR_TYPE)
type = TEXT_TYPE;
- first = TRUE;
- while ((dirp = readdir(dp)) != NULL) {
- child = dirp->d_name;
- if (strcmp(child, ".") == 0 ||
- strcmp(child, "..") == 0 ||
- strcmp(child, MOD_NAME) == 0 ||
- strcmp(child, OPQ_NAME) == 0)
- continue;
- cp = uename = clind_unescape(child);
- if (first) {
- mvals.free_me = TRUE;
- mvals.val = cp;
- mvals.val_type = type;
- first = FALSE;
- } else {
- if (mvals.cnt%MULTI_ALLOC == 0) {
- /* convert into multivalue */
- mvals.vals = my_realloc(mvals.vals,
- (mvals.cnt + MULTI_ALLOC) *
- sizeof(char *), "add_value");
- if (mvals.cnt == 0) { /* single value - convert */
- mvals.vals[0] = mvals.val;
- mvals.cnt= 1;
- mvals.val = NULL;
- }
- }
- mvals.vals[mvals.cnt] = cp;
- ++mvals.cnt;
- }
- }
- status = closedir(dp);
- if (status)
+ get_filtered_directory_listing(dp, &mvals, type, 0);
+ if (closedir(dp) != 0) {
INTERNAL;
- if (first) {
- if (uename)
- my_free(uename);
+ }
+
+ if (!(mvals.free_me)) {
+ /* empty struct. nothing to do. */
return TRUE;
}
vtw_sort(&mvals, &cur_sorted);
@@ -1164,7 +1265,6 @@ static boolean commit_value(vtw_def *defp, char *cp,
/* act_value will be freed by freeing cur_value
do not zero out it here */
}
-
acti = 0;
curi = 0;
total = act_sorted.num + cur_sorted.num;