|
|
a41c76 |
From 8b59b9dab54c094dfc9bafd9d9f2c18f25877f36 Mon Sep 17 00:00:00 2001
|
|
|
a41c76 |
Message-Id: <8b59b9dab54c094dfc9bafd9d9f2c18f25877f36@dist-git>
|
|
|
a41c76 |
From: Paulo de Rezende Pinatti <ppinatti@linux.ibm.com>
|
|
|
a41c76 |
Date: Wed, 24 Jun 2020 13:16:17 +0200
|
|
|
a41c76 |
Subject: [PATCH] util: Introduce a parser for kernel cmdline arguments
|
|
|
a41c76 |
MIME-Version: 1.0
|
|
|
a41c76 |
Content-Type: text/plain; charset=UTF-8
|
|
|
a41c76 |
Content-Transfer-Encoding: 8bit
|
|
|
a41c76 |
|
|
|
a41c76 |
Introduce two utility functions to parse a kernel command
|
|
|
a41c76 |
line string according to the kernel code parsing rules in
|
|
|
a41c76 |
order to enable the caller to perform operations such as
|
|
|
a41c76 |
verifying whether certain argument=value combinations are
|
|
|
a41c76 |
present or retrieving an argument's value.
|
|
|
a41c76 |
|
|
|
a41c76 |
Signed-off-by: Paulo de Rezende Pinatti <ppinatti@linux.ibm.com>
|
|
|
a41c76 |
Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
|
|
|
a41c76 |
Reviewed-by: Erik Skultety <eskultet@redhat.com>
|
|
|
a41c76 |
(cherry picked from commit c5fffb959d93b83d87e70b21d19424e9722700b0)
|
|
|
a41c76 |
|
|
|
a41c76 |
https://bugzilla.redhat.com/show_bug.cgi?id=1848997
|
|
|
a41c76 |
https://bugzilla.redhat.com/show_bug.cgi?id=1850351
|
|
|
a41c76 |
|
|
|
a41c76 |
Conflicts:
|
|
|
a41c76 |
src/util/virutil.c
|
|
|
a41c76 |
- unrelated commits db72866310d and ab36f729470 were not
|
|
|
a41c76 |
backported
|
|
|
a41c76 |
|
|
|
a41c76 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
a41c76 |
Message-Id: <784fbc062d41f991b6321ac051b05e6c80a470cd.1592996194.git.jdenemar@redhat.com>
|
|
|
a41c76 |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
a41c76 |
---
|
|
|
a41c76 |
src/libvirt_private.syms | 2 +
|
|
|
a41c76 |
src/util/virutil.c | 185 +++++++++++++++++++++++++++++++++++++++
|
|
|
a41c76 |
src/util/virutil.h | 34 +++++++
|
|
|
a41c76 |
tests/utiltest.c | 136 ++++++++++++++++++++++++++++
|
|
|
a41c76 |
4 files changed, 357 insertions(+)
|
|
|
a41c76 |
|
|
|
a41c76 |
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
|
|
a41c76 |
index a3fe49ae33..9e290c7bdf 100644
|
|
|
a41c76 |
--- a/src/libvirt_private.syms
|
|
|
a41c76 |
+++ b/src/libvirt_private.syms
|
|
|
a41c76 |
@@ -3395,6 +3395,8 @@ virHexToBin;
|
|
|
a41c76 |
virHostGetDRMRenderNode;
|
|
|
a41c76 |
virHostHasIOMMU;
|
|
|
a41c76 |
virIndexToDiskName;
|
|
|
a41c76 |
+virKernelCmdlineMatchParam;
|
|
|
a41c76 |
+virKernelCmdlineNextParam;
|
|
|
a41c76 |
virMemoryLimitIsSet;
|
|
|
a41c76 |
virMemoryLimitTruncate;
|
|
|
a41c76 |
virMemoryMaxValue;
|
|
|
a41c76 |
diff --git a/src/util/virutil.c b/src/util/virutil.c
|
|
|
a41c76 |
index 261b2d2af6..17fd06dbb2 100644
|
|
|
a41c76 |
--- a/src/util/virutil.c
|
|
|
a41c76 |
+++ b/src/util/virutil.c
|
|
|
a41c76 |
@@ -1673,3 +1673,188 @@ virHostGetDRMRenderNode(void)
|
|
|
a41c76 |
VIR_DIR_CLOSE(driDir);
|
|
|
a41c76 |
return ret;
|
|
|
a41c76 |
}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static const char *virKernelCmdlineSkipQuote(const char *cmdline,
|
|
|
a41c76 |
+ bool *is_quoted)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ if (cmdline[0] == '"') {
|
|
|
a41c76 |
+ *is_quoted = !(*is_quoted);
|
|
|
a41c76 |
+ cmdline++;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ return cmdline;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+/**
|
|
|
a41c76 |
+ * virKernelCmdlineFindEqual:
|
|
|
a41c76 |
+ * @cmdline: target kernel command line string
|
|
|
a41c76 |
+ * @is_quoted: indicates whether the string begins with quotes
|
|
|
a41c76 |
+ * @res: pointer to the position immediately after the parsed parameter,
|
|
|
a41c76 |
+ * can be used in subsequent calls to process further parameters until
|
|
|
a41c76 |
+ * the end of the string.
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Iterate over the provided kernel command line string while honoring
|
|
|
a41c76 |
+ * the kernel quoting rules and returns the index of the equal sign
|
|
|
a41c76 |
+ * separating argument and value.
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Returns 0 for the cases where no equal sign is found or the argument
|
|
|
a41c76 |
+ * itself begins with the equal sign (both cases indicating that the
|
|
|
a41c76 |
+ * argument has no value). Otherwise, returns the index of the equal
|
|
|
a41c76 |
+ * sign in the string.
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+static size_t virKernelCmdlineFindEqual(const char *cmdline,
|
|
|
a41c76 |
+ bool is_quoted,
|
|
|
a41c76 |
+ const char **res)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ size_t i;
|
|
|
a41c76 |
+ size_t equal_index = 0;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ for (i = 0; cmdline[i]; i++) {
|
|
|
a41c76 |
+ if (!(is_quoted) && g_ascii_isspace(cmdline[i]))
|
|
|
a41c76 |
+ break;
|
|
|
a41c76 |
+ if (equal_index == 0 && cmdline[i] == '=') {
|
|
|
a41c76 |
+ equal_index = i;
|
|
|
a41c76 |
+ continue;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ virKernelCmdlineSkipQuote(cmdline + i, &is_quoted);
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ *res = cmdline + i;
|
|
|
a41c76 |
+ return equal_index;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static char* virKernelArgNormalize(const char *arg)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ return virStringReplace(arg, "_", "-");
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+/**
|
|
|
a41c76 |
+ * virKernelCmdlineNextParam:
|
|
|
a41c76 |
+ * @cmdline: kernel command line string to be checked for next parameter
|
|
|
a41c76 |
+ * @param: pointer to hold retrieved parameter, will be NULL if none found
|
|
|
a41c76 |
+ * @val: pointer to hold retrieved value of @param
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Parse the kernel cmdline and store the next parameter in @param
|
|
|
a41c76 |
+ * and the value of @param in @val which can be NULL if @param has
|
|
|
a41c76 |
+ * no value. In addition returns the address right after @param=@value
|
|
|
a41c76 |
+ * for possible further processing.
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Returns a pointer to address right after @param=@val in the
|
|
|
a41c76 |
+ * kernel command line, will point to the string's end (NULL)
|
|
|
a41c76 |
+ * in case no next parameter is found
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+const char *virKernelCmdlineNextParam(const char *cmdline,
|
|
|
a41c76 |
+ char **param,
|
|
|
a41c76 |
+ char **val)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ const char *next;
|
|
|
a41c76 |
+ int equal_index;
|
|
|
a41c76 |
+ bool is_quoted = false;
|
|
|
a41c76 |
+ *param = NULL;
|
|
|
a41c76 |
+ *val = NULL;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ virSkipSpaces(&cmdline);
|
|
|
a41c76 |
+ cmdline = virKernelCmdlineSkipQuote(cmdline, &is_quoted);
|
|
|
a41c76 |
+ equal_index = virKernelCmdlineFindEqual(cmdline, is_quoted, &next;;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (next == cmdline)
|
|
|
a41c76 |
+ return next;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ /* param has no value */
|
|
|
a41c76 |
+ if (equal_index == 0) {
|
|
|
a41c76 |
+ if (is_quoted && next[-1] == '"')
|
|
|
a41c76 |
+ *param = g_strndup(cmdline, next - cmdline - 1);
|
|
|
a41c76 |
+ else
|
|
|
a41c76 |
+ *param = g_strndup(cmdline, next - cmdline);
|
|
|
a41c76 |
+ return next;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ *param = g_strndup(cmdline, equal_index);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (cmdline[equal_index + 1] == '"') {
|
|
|
a41c76 |
+ is_quoted = true;
|
|
|
a41c76 |
+ equal_index++;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (is_quoted && next[-1] == '"')
|
|
|
a41c76 |
+ *val = g_strndup(cmdline + equal_index + 1,
|
|
|
a41c76 |
+ next - cmdline - equal_index - 2);
|
|
|
a41c76 |
+ else
|
|
|
a41c76 |
+ *val = g_strndup(cmdline + equal_index + 1,
|
|
|
a41c76 |
+ next - cmdline - equal_index - 1);
|
|
|
a41c76 |
+ return next;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static bool virKernelCmdlineStrCmp(const char *kernel_val,
|
|
|
a41c76 |
+ const char *caller_val,
|
|
|
a41c76 |
+ virKernelCmdlineFlags flags)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ if (flags & VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX)
|
|
|
a41c76 |
+ return STRPREFIX(kernel_val, caller_val);
|
|
|
a41c76 |
+ return STREQ(kernel_val, caller_val);
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+/**
|
|
|
a41c76 |
+ * virKernelCmdlineMatchParam:
|
|
|
a41c76 |
+ * @cmdline: kernel command line string to be checked for @arg
|
|
|
a41c76 |
+ * @arg: kernel command line argument
|
|
|
a41c76 |
+ * @values: array of possible values to match @arg
|
|
|
a41c76 |
+ * @len_values: size of array, it can be 0 meaning a match will be positive if
|
|
|
a41c76 |
+ * the argument has no value.
|
|
|
a41c76 |
+ * @flags: bitwise-OR of virKernelCmdlineFlags
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Try to match the provided kernel cmdline string with the provided @arg
|
|
|
a41c76 |
+ * and the list @values of possible values according to the matching strategy
|
|
|
a41c76 |
+ * defined in @flags.
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Returns true if a match is found, false otherwise
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+bool virKernelCmdlineMatchParam(const char *cmdline,
|
|
|
a41c76 |
+ const char *arg,
|
|
|
a41c76 |
+ const char **values,
|
|
|
a41c76 |
+ size_t len_values,
|
|
|
a41c76 |
+ virKernelCmdlineFlags flags)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ bool match = false;
|
|
|
a41c76 |
+ size_t i;
|
|
|
a41c76 |
+ const char *next = cmdline;
|
|
|
a41c76 |
+ g_autofree char *arg_norm = virKernelArgNormalize(arg);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ while (next[0] != '\0') {
|
|
|
a41c76 |
+ g_autofree char *kparam = NULL;
|
|
|
a41c76 |
+ g_autofree char *kparam_norm = NULL;
|
|
|
a41c76 |
+ g_autofree char *kval = NULL;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ next = virKernelCmdlineNextParam(next, &kparam, &kval);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!kparam)
|
|
|
a41c76 |
+ break;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ kparam_norm = virKernelArgNormalize(kparam);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (STRNEQ(kparam_norm, arg_norm))
|
|
|
a41c76 |
+ continue;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!kval) {
|
|
|
a41c76 |
+ match = (len_values == 0) ? true : false;
|
|
|
a41c76 |
+ } else {
|
|
|
a41c76 |
+ match = false;
|
|
|
a41c76 |
+ for (i = 0; i < len_values; i++) {
|
|
|
a41c76 |
+ if (virKernelCmdlineStrCmp(kval, values[i], flags)) {
|
|
|
a41c76 |
+ match = true;
|
|
|
a41c76 |
+ break;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (match && (flags & VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST))
|
|
|
a41c76 |
+ break;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return match;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
diff --git a/src/util/virutil.h b/src/util/virutil.h
|
|
|
a41c76 |
index 0dcaff79ac..f1d2ccdd1f 100644
|
|
|
a41c76 |
--- a/src/util/virutil.h
|
|
|
a41c76 |
+++ b/src/util/virutil.h
|
|
|
a41c76 |
@@ -145,6 +145,40 @@ bool virHostHasIOMMU(void);
|
|
|
a41c76 |
|
|
|
a41c76 |
char *virHostGetDRMRenderNode(void) G_GNUC_NO_INLINE;
|
|
|
a41c76 |
|
|
|
a41c76 |
+/* Kernel cmdline match and comparison strategy for arg=value pairs */
|
|
|
a41c76 |
+typedef enum {
|
|
|
a41c76 |
+ /* substring comparison of argument values */
|
|
|
a41c76 |
+ VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX = 1,
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ /* strict string comparison of argument values */
|
|
|
a41c76 |
+ VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ = 2,
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ /* look for any occurrence of the argument with the expected value,
|
|
|
a41c76 |
+ * this should be used when an argument set to the expected value overrides
|
|
|
a41c76 |
+ * all the other occurrences of the argument, e.g. when looking for 'arg=1'
|
|
|
a41c76 |
+ * in 'arg=0 arg=1 arg=0' the search would succeed with this flag
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+ VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST = 4,
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ /* look for the last occurrence of argument with the expected value,
|
|
|
a41c76 |
+ * this should be used when the last occurrence of the argument overrides
|
|
|
a41c76 |
+ * all the other ones, e.g. when looking for 'arg=1' in 'arg=0 arg=1' the
|
|
|
a41c76 |
+ * search would succeed with this flag, but in 'arg=1 arg=0' it would not,
|
|
|
a41c76 |
+ * because 'arg=0' overrides all the previous occurrences of 'arg'
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+ VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST = 8,
|
|
|
a41c76 |
+} virKernelCmdlineFlags;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+const char *virKernelCmdlineNextParam(const char *cmdline,
|
|
|
a41c76 |
+ char **param,
|
|
|
a41c76 |
+ char **val);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+bool virKernelCmdlineMatchParam(const char *cmdline,
|
|
|
a41c76 |
+ const char *arg,
|
|
|
a41c76 |
+ const char **values,
|
|
|
a41c76 |
+ size_t len_values,
|
|
|
a41c76 |
+ virKernelCmdlineFlags flags);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
/**
|
|
|
a41c76 |
* VIR_ASSIGN_IS_OVERFLOW:
|
|
|
a41c76 |
* @rvalue: value that is checked (evaluated twice)
|
|
|
a41c76 |
diff --git a/tests/utiltest.c b/tests/utiltest.c
|
|
|
a41c76 |
index 5ae04585cb..2bff7859dc 100644
|
|
|
a41c76 |
--- a/tests/utiltest.c
|
|
|
a41c76 |
+++ b/tests/utiltest.c
|
|
|
a41c76 |
@@ -254,6 +254,140 @@ testOverflowCheckMacro(const void *data G_GNUC_UNUSED)
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
|
|
|
a41c76 |
+struct testKernelCmdlineNextParamData
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ const char *cmdline;
|
|
|
a41c76 |
+ const char *param;
|
|
|
a41c76 |
+ const char *val;
|
|
|
a41c76 |
+ const char *next;
|
|
|
a41c76 |
+};
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static struct testKernelCmdlineNextParamData kEntries[] = {
|
|
|
a41c76 |
+ { "arg1 arg2 arg3=val1", "arg1", NULL, " arg2 arg3=val1" },
|
|
|
a41c76 |
+ { "arg1=val1 arg2 arg3=val3 arg4", "arg1", "val1", " arg2 arg3=val3 arg4" },
|
|
|
a41c76 |
+ { "arg1=sub1=val1,sub2=val2 arg3=val3 arg4", "arg1", "sub1=val1,sub2=val2", " arg3=val3 arg4" },
|
|
|
a41c76 |
+ { "arg3=val3 ", "arg3", "val3", " " },
|
|
|
a41c76 |
+ { "arg3=val3", "arg3", "val3", "" },
|
|
|
a41c76 |
+ { "arg-3=val3 arg4", "arg-3", "val3", " arg4" },
|
|
|
a41c76 |
+ { " arg_3=val3 arg4", "arg_3", "val3", " arg4" },
|
|
|
a41c76 |
+ { "arg2=\"value with space\" arg3=val3", "arg2", "value with space", " arg3=val3" },
|
|
|
a41c76 |
+ { " arg2=\"value with space\" arg3=val3", "arg2", "value with space", " arg3=val3" },
|
|
|
a41c76 |
+ { " \"arg2=value with space\" arg3=val3", "arg2", "value with space", " arg3=val3" },
|
|
|
a41c76 |
+ { "arg2=\"val\"ue arg3", "arg2", "val\"ue", " arg3" },
|
|
|
a41c76 |
+ { "arg2=value\" long\" arg3", "arg2", "value\" long\"", " arg3" },
|
|
|
a41c76 |
+ { " \"arg2 with space=value with space\" arg3", "arg2 with space", "value with space", " arg3" },
|
|
|
a41c76 |
+ { " arg2\" with space=val2\" arg3", "arg2\" with space", "val2\"", " arg3" },
|
|
|
a41c76 |
+ { " arg2longer=someval\" long\" arg2=val2", "arg2longer", "someval\" long\"", " arg2=val2" },
|
|
|
a41c76 |
+ { "=val1 arg2=val2", "=val1", NULL, " arg2=val2" },
|
|
|
a41c76 |
+ { " ", NULL, NULL, "" },
|
|
|
a41c76 |
+ { "", NULL, NULL, "" },
|
|
|
a41c76 |
+};
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static int
|
|
|
a41c76 |
+testKernelCmdlineNextParam(const void *data G_GNUC_UNUSED)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ const char *next;
|
|
|
a41c76 |
+ size_t i;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ for (i = 0; i < G_N_ELEMENTS(kEntries); ++i) {
|
|
|
a41c76 |
+ g_autofree char * param = NULL;
|
|
|
a41c76 |
+ g_autofree char * val = NULL;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ next = virKernelCmdlineNextParam(kEntries[i].cmdline, ¶m, &val;;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (STRNEQ_NULLABLE(param, kEntries[i].param) ||
|
|
|
a41c76 |
+ STRNEQ_NULLABLE(val, kEntries[i].val) ||
|
|
|
a41c76 |
+ STRNEQ(next, kEntries[i].next)) {
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("\nKernel cmdline [%s]", kEntries[i].cmdline);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Expect param [%s]", kEntries[i].param);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Actual param [%s]", param);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Expect value [%s]", kEntries[i].val);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Actual value [%s]", val);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Expect next [%s]", kEntries[i].next);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Actual next [%s]", next);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+struct testKernelCmdlineMatchData
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ const char *cmdline;
|
|
|
a41c76 |
+ const char *arg;
|
|
|
a41c76 |
+ const char *values[2];
|
|
|
a41c76 |
+ virKernelCmdlineFlags flags;
|
|
|
a41c76 |
+ bool result;
|
|
|
a41c76 |
+};
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static struct testKernelCmdlineMatchData kMatchEntries[] = {
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"1", "y"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, false },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"on", "yes"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, true },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"1", "y"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST | VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX, true },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"a", "b"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST | VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX, false },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"on", "yes"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, false },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 myarg=yes arg4=val4 myarg=no arg5", "myarg", {"1", "y"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX, false },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 arg4=val4 myarg=yes arg5", "myarg", {"on", "yes"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, true },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 arg4=val4 myarg=yes arg5", "myarg", {"1", "y"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX, true },
|
|
|
a41c76 |
+ {"arg1 myarg=no arg2=val2 arg4=val4 myarg arg5", "myarg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, true },
|
|
|
a41c76 |
+ {"arg1 myarg arg2=val2 arg4=val4 myarg=yes arg5", "myarg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST, true },
|
|
|
a41c76 |
+ {"arg1 myarg arg2=val2 arg4=val4 myarg=yes arg5", "myarg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, false },
|
|
|
a41c76 |
+ {"arg1 my-arg=no arg2=val2 arg4=val4 my_arg=yes arg5", "my-arg", {"on", "yes"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, true },
|
|
|
a41c76 |
+ {"arg1 my-arg=no arg2=val2 arg4=val4 my_arg=yes arg5 ", "my-arg", {"on", "yes"}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, true },
|
|
|
a41c76 |
+ {"arg1 my-arg arg2=val2 arg4=val4 my_arg=yes arg5", "my_arg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST, true },
|
|
|
a41c76 |
+ {"arg1 my-arg arg2=val2 arg4=val4 my-arg=yes arg5", "my_arg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST, true },
|
|
|
a41c76 |
+ {"=arg1 my-arg arg2=val2 arg4=val4 my-arg=yes arg5", "my_arg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST, true },
|
|
|
a41c76 |
+ {"my-arg =arg1 arg2=val2 arg4=val4 my-arg=yes arg5", "=arg1", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, true },
|
|
|
a41c76 |
+ {"arg1 arg2=val2 myarg=sub1=val1 arg5", "myarg", {"sub1=val1", NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, true },
|
|
|
a41c76 |
+ {"arg1 arg2=", "arg2", {"", ""}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST | VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ, true },
|
|
|
a41c76 |
+ {" ", "myarg", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, false },
|
|
|
a41c76 |
+ {"", "", {NULL, NULL}, VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST, false },
|
|
|
a41c76 |
+};
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static int
|
|
|
a41c76 |
+testKernelCmdlineMatchParam(const void *data G_GNUC_UNUSED)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ bool result;
|
|
|
a41c76 |
+ size_t i, lenValues;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ for (i = 0; i < G_N_ELEMENTS(kMatchEntries); ++i) {
|
|
|
a41c76 |
+ if (kMatchEntries[i].values[0] == NULL)
|
|
|
a41c76 |
+ lenValues = 0;
|
|
|
a41c76 |
+ else
|
|
|
a41c76 |
+ lenValues = G_N_ELEMENTS(kMatchEntries[i].values);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ result = virKernelCmdlineMatchParam(kMatchEntries[i].cmdline,
|
|
|
a41c76 |
+ kMatchEntries[i].arg,
|
|
|
a41c76 |
+ kMatchEntries[i].values,
|
|
|
a41c76 |
+ lenValues,
|
|
|
a41c76 |
+ kMatchEntries[i].flags);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (result != kMatchEntries[i].result) {
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("\nKernel cmdline [%s]", kMatchEntries[i].cmdline);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Kernel argument [%s]", kMatchEntries[i].arg);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Kernel values [%s] [%s]", kMatchEntries[i].values[0],
|
|
|
a41c76 |
+ kMatchEntries[i].values[1]);
|
|
|
a41c76 |
+ if (kMatchEntries[i].flags & VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX)
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Flag [VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX]");
|
|
|
a41c76 |
+ if (kMatchEntries[i].flags & VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ)
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Flag [VIR_KERNEL_CMDLINE_FLAGS_CMP_EQ]");
|
|
|
a41c76 |
+ if (kMatchEntries[i].flags & VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST)
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Flag [VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST]");
|
|
|
a41c76 |
+ if (kMatchEntries[i].flags & VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST)
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Flag [VIR_KERNEL_CMDLINE_FLAGS_SEARCH_LAST]");
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Expect result [%d]", kMatchEntries[i].result);
|
|
|
a41c76 |
+ VIR_TEST_DEBUG("Actual result [%d]", result);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
|
|
|
a41c76 |
|
|
|
a41c76 |
static int
|
|
|
a41c76 |
@@ -277,6 +411,8 @@ mymain(void)
|
|
|
a41c76 |
DO_TEST(ParseVersionString);
|
|
|
a41c76 |
DO_TEST(RoundValueToPowerOfTwo);
|
|
|
a41c76 |
DO_TEST(OverflowCheckMacro);
|
|
|
a41c76 |
+ DO_TEST(KernelCmdlineNextParam);
|
|
|
a41c76 |
+ DO_TEST(KernelCmdlineMatchParam);
|
|
|
a41c76 |
|
|
|
a41c76 |
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
|
a41c76 |
}
|
|
|
a41c76 |
--
|
|
|
a41c76 |
2.27.0
|
|
|
a41c76 |
|