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