When disabling a flag, one needs to AND with the inverse not the flag
itself. Otherwise specifying for instance 'home -nodad' will effectively
clear the flags variable.

While being at it, simplify the code a bit by merging common parts of
negated and non-negated case branches. Also allow for the "special
cases" to be inverted, too.

Fixes: f73ac674d0abf ("ip: change flag names to an array")
Signed-off-by: Phil Sutter <p...@nwl.cc>
---
 ip/ipaddress.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index cd8cc76a3473f..7b98877085878 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1211,31 +1211,35 @@ static void print_ifa_flags(FILE *fp, const struct 
ifaddrmsg *ifa,
 
 static int get_filter(const char *arg)
 {
+       bool inv = false;
        unsigned int i;
 
+       if (arg[0] == '-') {
+               inv = true;
+               arg++;
+       }
        /* Special cases */
        if (strcmp(arg, "dynamic") == 0) {
-               filter.flags &= ~IFA_F_PERMANENT;
+               if (inv)
+                       filter.flags |= IFA_F_PERMANENT;
+               else
+                       filter.flags &= ~IFA_F_PERMANENT;
                filter.flagmask |= IFA_F_PERMANENT;
        } else if (strcmp(arg, "primary") == 0) {
-               filter.flags &= ~IFA_F_SECONDARY;
+               if (inv)
+                       filter.flags |= IFA_F_SECONDARY;
+               else
+                       filter.flags &= ~IFA_F_SECONDARY;
                filter.flagmask |= IFA_F_SECONDARY;
-       } else if (*arg == '-') {
-               for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
-                       if (strcmp(arg + 1, ifa_flag_names[i].name))
-                               continue;
-
-                       filter.flags &= ifa_flag_names[i].value;
-                       filter.flagmask |= ifa_flag_names[i].value;
-                       return 0;
-               }
-
-               return -1;
        } else {
                for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
                        if (strcmp(arg, ifa_flag_names[i].name))
                                continue;
-                       filter.flags |= ifa_flag_names[i].value;
+
+                       if (inv)
+                               filter.flags &= ~ifa_flag_names[i].value;
+                       else
+                               filter.flags |= ifa_flag_names[i].value;
                        filter.flagmask |= ifa_flag_names[i].value;
                        return 0;
                }
-- 
2.19.0

Reply via email to