]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkctl: return error or warning when interfaces are not matched
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 12 Jan 2020 11:14:31 +0000 (12:14 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 14 Jan 2020 12:09:46 +0000 (13:09 +0100)
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

src/basic/strv.c
src/basic/strv.h
src/network/networkctl.c
src/test/test-strv.c

index 99bcfde089d7c70cdfda2fac53d6353218c2b1d1..303d979859479ea8b901d43056a30d4bd652e9ed 100644 (file)
@@ -800,12 +800,13 @@ char **strv_shell_escape(char **l, const char *bad) {
         return l;
 }
 
-bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
-        char* const* p;
-
-        STRV_FOREACH(p, patterns)
-                if (fnmatch(*p, s, flags) == 0)
+bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
+        for (size_t i = 0; patterns && patterns[i]; i++)
+                if (fnmatch(patterns[i], s, flags) == 0) {
+                        if (matched_pos)
+                                *matched_pos = i;
                         return true;
+                }
 
         return false;
 }
index f335aeee32fa74a3bf306fbff82fb631a023608a..1cae0ae09fd8453055b1e9fda8092a7b7e44ade6 100644 (file)
@@ -177,7 +177,10 @@ void strv_print(char * const *l);
 char **strv_reverse(char **l);
 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, int flags) {
+        return strv_fnmatch_full(patterns, s, flags, NULL);
+}
 
 static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
         assert(s);
index e6dc70a0e2bab64f671e1eaf7b9fc250a5247eaa..284a59bb6f4205b37afda1e04f044e515d746edc 100644 (file)
@@ -27,6 +27,7 @@
 #include "fd-util.h"
 #include "format-table.h"
 #include "format-util.h"
+#include "glob-util.h"
 #include "hwdb-util.h"
 #include "local-addresses.h"
 #include "locale-util.h"
@@ -266,7 +267,7 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
         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;
         const char *name;
         int ifindex, r;
@@ -296,20 +297,26 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
 
         if (patterns) {
                 char str[DECIMAL_STR_MAX(int)];
+                size_t pos;
+
+                assert(matched_patterns);
 
                 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;
                         char **p;
 
                         STRV_FOREACH(p, altnames)
-                                if (strv_fnmatch(patterns, *p, 0)) {
+                                if (strv_fnmatch_full(patterns, *p, 0, &pos)) {
                                         match = true;
                                         break;
                                 }
                         if (!match)
                                 return 0;
                 }
+
+                matched_patterns[pos] = true;
         }
 
         r = sd_rtnl_message_link_get_type(m, &info->iftype);
@@ -464,11 +471,18 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
         if (r < 0)
                 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)) {
                 if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */
                         return -ENOMEM;
 
-                r = decode_link(i, links + c, patterns);
+                r = decode_link(i, links + c, patterns, matched_patterns);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -486,6 +500,20 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
                 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);
 
         if (bus)
@@ -494,6 +522,9 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
 
         *ret = TAKE_PTR(links);
 
+        if (patterns && c == 0)
+                log_warning("No interfaces matched.");
+
         return (int) c;
 }
 
index f31ea6f8c61cf6b86efc4c8757ac4509029cb538..b8001dfe70aaebd113495ff73e46a35e7a50a0d8 100644 (file)
@@ -924,14 +924,16 @@ static void test_foreach_string(void) {
 
 static void test_strv_fnmatch(void) {
         _cleanup_strv_free_ char **v = NULL;
+        size_t pos;
 
         log_info("/* %s */", __func__);
 
         assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0));
 
-        v = strv_new("*\\*");
-        assert_se(!strv_fnmatch(v, "\\", 0));
-        assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE));
+        v = strv_new("xxx", "*\\*", "yyy");
+        assert_se(!strv_fnmatch_full(v, "\\", 0, NULL));
+        assert_se(strv_fnmatch_full(v, "\\", FNM_NOESCAPE, &pos));
+        assert(pos == 1);
 }
 
 int main(int argc, char *argv[]) {