diff options
-rwxr-xr-x | scripts/VyattaConfigLoad.pm | 1 | ||||
-rwxr-xr-x | scripts/vyatta-interfaces.pl | 85 | ||||
-rwxr-xr-x | scripts/vyatta-watchlink-exclude.pl | 16 | ||||
-rw-r--r-- | src/commit.c | 284 |
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; |