diff options
-rw-r--r-- | src/kerneldevice/mm-kernel-device-generic.c | 27 | ||||
-rw-r--r-- | src/kerneldevice/mm-kernel-device-helpers.c | 66 | ||||
-rw-r--r-- | src/tests/Makefile.am | 1 | ||||
-rw-r--r-- | src/tests/meson.build | 1 | ||||
-rw-r--r-- | src/tests/test-kernel-device-helpers.c | 118 |
5 files changed, 179 insertions, 34 deletions
diff --git a/src/kerneldevice/mm-kernel-device-generic.c b/src/kerneldevice/mm-kernel-device-generic.c index a8f34fed..e0ee7720 100644 --- a/src/kerneldevice/mm-kernel-device-generic.c +++ b/src/kerneldevice/mm-kernel-device-generic.c @@ -740,33 +740,6 @@ kernel_device_cmp (MMKernelDevice *a, /*****************************************************************************/ static gboolean -string_match (MMKernelDeviceGeneric *self, - const gchar *str, - const gchar *pattern) -{ - g_autoptr(GError) inner_error = NULL; - g_autoptr(GRegex) regex = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - - regex = g_regex_new (pattern, 0, 0, &inner_error); - if (!regex) { - mm_obj_warn (self, "invalid pattern in rule '%s': %s", pattern, inner_error->message); - return FALSE; - } - g_regex_match_full (regex, str, -1, 0, 0, &match_info, &inner_error); - if (inner_error) { - mm_obj_warn (self, "couldn't apply pattern match in rule '%s': %s", pattern, inner_error->message); - return FALSE; - } - - if (!g_match_info_matches (match_info)) - return FALSE; - - mm_obj_dbg (self, "pattern '%s' matched: '%s'", pattern, str); - return TRUE; -} - -static gboolean check_condition (MMKernelDeviceGeneric *self, MMUdevRuleMatch *match) { diff --git a/src/kerneldevice/mm-kernel-device-helpers.c b/src/kerneldevice/mm-kernel-device-helpers.c index 5ed25efc..af6aed7f 100644 --- a/src/kerneldevice/mm-kernel-device-helpers.c +++ b/src/kerneldevice/mm-kernel-device-helpers.c @@ -65,29 +65,81 @@ mm_kernel_device_get_lower_device_name (const gchar *sysfs_path) /******************************************************************************/ +static gchar * +build_string_match_pattern (const gchar *str) +{ + GString *regex_pattern; + const gchar *str_start; + gsize len; + gchar *aux; + gboolean prefix_match = FALSE; + gboolean suffix_match = FALSE; + + /* We allow prefix and suffix matches given as input, by means of the + * single '*' character given either at the beginning or the end of the + * string. If given in another place, it will assumed to be explicitly + * the '*' character, not a catch-all indication. */ + + regex_pattern = g_string_new (NULL); + + /* suffix match? */ + if (str[0] == '*') { + str_start = &str[1]; + suffix_match = TRUE; + } else + str_start = str; + + /* prefix match? */ + len = strlen (str_start); + if (len > 0 && str_start[len - 1] == '*') { + len--; + prefix_match = TRUE; + } + + /* match start of string */ + g_string_append (regex_pattern, "^"); + + if (suffix_match) + g_string_append (regex_pattern, ".*"); + + aux = g_regex_escape_string (str_start, len); + g_string_append (regex_pattern, aux); + + if (prefix_match) + g_string_append (regex_pattern, ".*"); + + /* match end of string */ + g_string_append (regex_pattern, "$"); + + return g_string_free (regex_pattern, FALSE); +} + gboolean mm_kernel_device_generic_string_match (const gchar *str, const gchar *pattern, gpointer log_object) { - g_autoptr(GError) inner_error = NULL; - g_autoptr(GRegex) regex = NULL; - g_autoptr(GMatchInfo) match_info = NULL; + g_autoptr(GError) inner_error = NULL; + g_autoptr(GRegex) regex = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + g_autofree gchar *regex_pattern = NULL; + + regex_pattern = build_string_match_pattern (pattern); - regex = g_regex_new (pattern, 0, 0, &inner_error); + regex = g_regex_new (regex_pattern, G_REGEX_UNGREEDY, 0, &inner_error); if (!regex) { - mm_obj_warn (log_object, "invalid pattern in rule '%s': %s", pattern, inner_error->message); + mm_obj_warn (log_object, "invalid pattern in rule '%s': %s", regex_pattern, inner_error->message); return FALSE; } g_regex_match_full (regex, str, -1, 0, 0, &match_info, &inner_error); if (inner_error) { - mm_obj_warn (log_object, "couldn't apply pattern match in rule '%s': %s", pattern, inner_error->message); + mm_obj_warn (log_object, "couldn't apply pattern match in rule '%s': %s", regex_pattern, inner_error->message); return FALSE; } if (!g_match_info_matches (match_info)) return FALSE; - mm_obj_dbg (log_object, "pattern '%s' matched: '%s'", pattern, str); + mm_obj_dbg (log_object, "pattern '%s' matched: '%s'", regex_pattern, str); return TRUE; } diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 26a05fa3..617d6128 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -58,6 +58,7 @@ noinst_PROGRAMS = \ test-sms-part-cdma \ test-udev-rules \ test-error-helpers \ + test-kernel-device-helpers \ $(NULL) if WITH_QMI diff --git a/src/tests/meson.build b/src/tests/meson.build index c059ae2d..ff4392d1 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -5,6 +5,7 @@ test_units = { 'at-serial-port': libport_dep, 'charsets': libhelpers_dep, 'error-helpers': libhelpers_dep, + 'kernel-device-helpers': libkerneldevice_dep, 'modem-helpers': libhelpers_dep, 'sms-part-3gpp': libhelpers_dep, 'sms-part-cdma': libhelpers_dep, diff --git a/src/tests/test-kernel-device-helpers.c b/src/tests/test-kernel-device-helpers.c new file mode 100644 index 00000000..3cbe1d91 --- /dev/null +++ b/src/tests/test-kernel-device-helpers.c @@ -0,0 +1,118 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es> + */ + +#include <glib.h> +#include <glib-object.h> +#include <string.h> +#include <stdlib.h> +#include <locale.h> + +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + +#include "mm-kernel-device-helpers.h" +#include "mm-log-test.h" + +/*****************************************************************************/ + +typedef struct { + const gchar *pattern; + const gchar *str; + gboolean match; +} StringMatchTest; + +static const StringMatchTest string_match_tests[] = { + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net/eno1", + .str = "/sys/devices/pci0000:00/0000:00:1f.6/net/eno1", + .match = TRUE, + }, + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net/*", + .str = "/sys/devices/pci0000:00/0000:00:1f.6/net/eno1", + .match = TRUE, + }, + { + .pattern = "*MBIM", + .str = "wwan0p1MBIM", + .match = TRUE, + }, + /* Don't match leading extra characters */ + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net", + .str = "aaaaa/sys/devices/pci0000:00/0000:00:1f.6/net", + .match = FALSE, + }, + /* Don't match trailing extra characters */ + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net", + .str = "/sys/devices/pci0000:00/0000:00:1f.6/netaaa", + .match = FALSE, + }, + /* The ASTERISK in a pattern given must be treated as a wildcard by + * itself, not as "the previous character 0-N times", as the input + * pattern is not a regex pattern. */ + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net/*", + .str = "/sys/devices/pci0000:00/0000:00:1ff6/net", + .match = FALSE, + }, + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net/*", + .str = "/sys/devices/pci0000:00/0000:00:1f.6/netaaa", + .match = FALSE, + }, + /* The DOT in a pattern given must match the exact DOT character, + * as the input pattern is not a regex pattern. */ + { + .pattern = "/sys/devices/pci0000:00/0000:00:1f.6/net/eno1", + .str = "/sys/devices/pci0000:00/0000:00:1ff6/net/eno1", + .match = FALSE, + }, +}; + +static void +test_string_match (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (string_match_tests); i++) { + gboolean match; + + match = mm_kernel_device_generic_string_match (string_match_tests[i].str, + string_match_tests[i].pattern, + NULL); + if (match != string_match_tests[i].match) + mm_obj_warn (NULL, "string match failure: pattern '%s' should%s match str '%s'", + string_match_tests[i].pattern, + string_match_tests[i].match ? "" : " NOT", + string_match_tests[i].str); + + g_assert_cmpuint (match, ==, string_match_tests[i].match); + } +} + +/*****************************************************************************/ + +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/MM/kernel-device-helpers/string-match", test_string_match); + + return g_test_run (); +} |