Compare commits

..

3 Commits

Author SHA1 Message Date
Yu Watanabe 222a6aace7
Merge pull request #14547 from keszybz/networkctl-matching
networkctl: return error or warning when interfaces are not matched
2020-01-15 11:56:01 +09:00
Zbigniew Jędrzejewski-Szmek 191a3f1634 basic/strv: drop flags argument from strv_fnmatch() 2020-01-14 13:10:29 +01:00
Zbigniew Jędrzejewski-Szmek 0ef84b80c5 networkctl: return error or warning when interfaces are not matched
We'd just print nothing and exit with 0. If the user gave an explicit
name, we should fail. If a pattern didn't match, we should at least warn.

$ networkctl status enx54ee75cb1dc0a* --no-pager && echo $?
No interfaces matched.
0

$ networkctl status enx54ee75cb1dc0a --no-pager
Interface "enx54ee75cb1dc0a" not found.
1
2020-01-14 13:09:46 +01:00
7 changed files with 59 additions and 22 deletions

View File

@ -1160,9 +1160,9 @@ static int graph_one_property(
assert(prop); assert(prop);
assert(color); assert(color);
match_patterns = strv_fnmatch(patterns, u->id, 0); match_patterns = strv_fnmatch(patterns, u->id);
if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id, 0)) if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id))
return 0; return 0;
r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units); r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
@ -1172,9 +1172,9 @@ static int graph_one_property(
STRV_FOREACH(unit, units) { STRV_FOREACH(unit, units) {
bool match_patterns2; bool match_patterns2;
match_patterns2 = strv_fnmatch(patterns, *unit, 0); match_patterns2 = strv_fnmatch(patterns, *unit);
if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit, 0)) if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit))
continue; continue;
if (!strv_isempty(patterns) && !match_patterns && !match_patterns2) if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)

View File

@ -800,12 +800,13 @@ char **strv_shell_escape(char **l, const char *bad) {
return l; return l;
} }
bool strv_fnmatch(char* const* patterns, const char *s, int flags) { bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
char* const* p; for (size_t i = 0; patterns && patterns[i]; i++)
if (fnmatch(patterns[i], s, flags) == 0) {
STRV_FOREACH(p, patterns) if (matched_pos)
if (fnmatch(*p, s, flags) == 0) *matched_pos = i;
return true; return true;
}
return false; return false;
} }

View File

@ -177,12 +177,15 @@ void strv_print(char * const *l);
char **strv_reverse(char **l); char **strv_reverse(char **l);
char **strv_shell_escape(char **l, const char *bad); char **strv_shell_escape(char **l, const char *bad);
bool strv_fnmatch(char* const* patterns, const char *s, int flags); bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
static inline bool strv_fnmatch(char* const* patterns, const char *s) {
return strv_fnmatch_full(patterns, s, 0, NULL);
}
static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) { static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
assert(s); assert(s);
return strv_isempty(patterns) || return strv_isempty(patterns) ||
strv_fnmatch(patterns, s, flags); strv_fnmatch_full(patterns, s, flags, NULL);
} }
char ***strv_free_free(char ***l); char ***strv_free_free(char ***l);

View File

@ -27,6 +27,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "format-table.h" #include "format-table.h"
#include "format-util.h" #include "format-util.h"
#include "glob-util.h"
#include "hwdb-util.h" #include "hwdb-util.h"
#include "local-addresses.h" #include "local-addresses.h"
#include "locale-util.h" #include "locale-util.h"
@ -267,7 +268,7 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
return 0; return 0;
} }
static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) { static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, bool matched_patterns[]) {
_cleanup_strv_free_ char **altnames = NULL; _cleanup_strv_free_ char **altnames = NULL;
const char *name; const char *name;
int ifindex, r; int ifindex, r;
@ -297,20 +298,26 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
if (patterns) { if (patterns) {
char str[DECIMAL_STR_MAX(int)]; char str[DECIMAL_STR_MAX(int)];
size_t pos;
assert(matched_patterns);
xsprintf(str, "%i", ifindex); xsprintf(str, "%i", ifindex);
if (!strv_fnmatch(patterns, str, 0) && !strv_fnmatch(patterns, name, 0)) { if (!strv_fnmatch_full(patterns, str, 0, &pos) &&
!strv_fnmatch_full(patterns, name, 0, &pos)) {
bool match = false; bool match = false;
char **p; char **p;
STRV_FOREACH(p, altnames) STRV_FOREACH(p, altnames)
if (strv_fnmatch(patterns, *p, 0)) { if (strv_fnmatch_full(patterns, *p, 0, &pos)) {
match = true; match = true;
break; break;
} }
if (!match) if (!match)
return 0; return 0;
} }
matched_patterns[pos] = true;
} }
r = sd_rtnl_message_link_get_type(m, &info->iftype); r = sd_rtnl_message_link_get_type(m, &info->iftype);
@ -465,11 +472,18 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m"); return log_error_errno(r, "Failed to enumerate links: %m");
_cleanup_free_ bool *matched_patterns = NULL;
if (patterns) {
matched_patterns = new0(bool, strv_length(patterns));
if (!matched_patterns)
return log_oom();
}
for (i = reply; i; i = sd_netlink_message_next(i)) { for (i = reply; i; i = sd_netlink_message_next(i)) {
if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */ if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */
return -ENOMEM; return -ENOMEM;
r = decode_link(i, links + c, patterns); r = decode_link(i, links + c, patterns, matched_patterns);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)
@ -487,6 +501,20 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
c++; c++;
} }
/* Look if we matched all our arguments that are not globs. It
* is OK for a glob to match nothing, but not for an exact argument. */
for (size_t pos = 0; pos < strv_length(patterns); pos++) {
if (matched_patterns[pos])
continue;
if (string_is_glob(patterns[pos]))
log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
patterns[pos]);
else
return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
"Interface \"%s\" not found.", patterns[pos]);
}
typesafe_qsort(links, c, link_info_compare); typesafe_qsort(links, c, link_info_compare);
if (bus) if (bus)
@ -495,6 +523,9 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
*ret = TAKE_PTR(links); *ret = TAKE_PTR(links);
if (patterns && c == 0)
log_warning("No interfaces matched.");
return (int) c; return (int) c;
} }

View File

@ -1875,7 +1875,7 @@ static int link_new_bound_by_list(Link *link) {
if (strv_isempty(carrier->network->bind_carrier)) if (strv_isempty(carrier->network->bind_carrier))
continue; continue;
if (strv_fnmatch(carrier->network->bind_carrier, link->ifname, 0)) { if (strv_fnmatch(carrier->network->bind_carrier, link->ifname)) {
r = link_put_carrier(link, carrier, &link->bound_by_links); r = link_put_carrier(link, carrier, &link->bound_by_links);
if (r < 0) if (r < 0)
return r; return r;
@ -1917,7 +1917,7 @@ static int link_new_bound_to_list(Link *link) {
m = link->manager; m = link->manager;
HASHMAP_FOREACH (carrier, m->links, i) { HASHMAP_FOREACH (carrier, m->links, i) {
if (strv_fnmatch(link->network->bind_carrier, carrier->ifname, 0)) { if (strv_fnmatch(link->network->bind_carrier, carrier->ifname)) {
r = link_put_carrier(link, carrier, &link->bound_to_links); r = link_put_carrier(link, carrier, &link->bound_to_links);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -29,7 +29,7 @@ static bool manager_ignore_link(Manager *m, Link *link) {
return true; return true;
/* ignore interfaces we explicitly are asked to ignore */ /* ignore interfaces we explicitly are asked to ignore */
return strv_fnmatch(m->ignore, link->ifname, 0); return strv_fnmatch(m->ignore, link->ifname);
} }
static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) { static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {

View File

@ -924,14 +924,16 @@ static void test_foreach_string(void) {
static void test_strv_fnmatch(void) { static void test_strv_fnmatch(void) {
_cleanup_strv_free_ char **v = NULL; _cleanup_strv_free_ char **v = NULL;
size_t pos;
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a"));
v = strv_new("*\\*"); v = strv_new("xxx", "*\\*", "yyy");
assert_se(!strv_fnmatch(v, "\\", 0)); assert_se(!strv_fnmatch_full(v, "\\", 0, NULL));
assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE)); assert_se(strv_fnmatch_full(v, "\\", FNM_NOESCAPE, &pos));
assert(pos == 1);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {