SHA256
1
0
forked from pool/kmod
kmod/0001-libkmod-config-revamp-kcmdline-parsing-into-a-state-.patch

144 lines
3.8 KiB
Diff
Raw Normal View History

From: Lucas De Marchi <lucas.demarchi@intel.com>
Date: Fri, 12 Feb 2021 01:45:21 -0800
Subject: libkmod-config: revamp kcmdline parsing into a state machine
Git-repo: git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
Git-commit: 01ed9af61e239b40514edf527ac87c79377266ac
Patch-mainline: v29
References: bsc#1181111
The handling of spaces and quotes is becoming hard to maintain. Convert
the parser into a state machine so we can check all the states. This
should make it easier to fix a corner case we have right now:
The kernel also accepts a quote before the module name instead of the
value. But this additional is left for later. This is purely an
algorithm change with no behavior change.
Tested-by: Jessica Yu <jeyu@kernel.org>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
libkmod/libkmod-config.c | 86 ++++++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 34 deletions(-)
diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c
index 971f20b8a352..d3cd10d42a10 100644
--- a/libkmod/libkmod-config.c
+++ b/libkmod/libkmod-config.c
@@ -499,7 +499,14 @@ static int kmod_config_parse_kcmdline(struct kmod_config *config)
char buf[KCMD_LINE_SIZE];
int fd, err;
char *p, *modname, *param = NULL, *value = NULL;
- bool is_quoted = false, is_module = true;
+ bool is_quoted = false, iter = true;
+ enum state {
+ STATE_IGNORE,
+ STATE_MODNAME,
+ STATE_PARAM,
+ STATE_VALUE,
+ STATE_COMPLETE,
+ } state;
fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC);
if (fd < 0) {
@@ -516,54 +523,65 @@ static int kmod_config_parse_kcmdline(struct kmod_config *config)
return err;
}
- for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) {
- if (*p == '"') {
+ state = STATE_MODNAME;
+ for (p = buf, modname = buf; iter; p++) {
+ switch (*p) {
+ case '"':
is_quoted = !is_quoted;
-
- if (is_quoted) {
- /* don't consider a module until closing quotes */
- is_module = false;
- } else if (param != NULL && value != NULL) {
+ break;
+ case '\0':
+ case '\n':
+ /* Stop iterating on new chars */
+ iter = false;
+ /* fall-through */
+ case ' ':
+ if (is_quoted && state == STATE_VALUE) {
+ /* no state change*/;
+ } else if (is_quoted) {
+ /* spaces are only allowed in the value part */
+ state = STATE_IGNORE;
+ } else if (state == STATE_VALUE || state == STATE_PARAM) {
+ *p = '\0';
+ state = STATE_COMPLETE;
+ } else {
/*
- * If we are indeed expecting a value and
- * closing quotes, then this can be considered
- * a valid option for a module
+ * go to next option, ignoring any possible
+ * partial match we have
*/
- is_module = true;
+ modname = p + 1;
+ state = STATE_MODNAME;
}
-
- continue;
- }
- if (is_quoted)
- continue;
-
- switch (*p) {
- case ' ':
- *p = '\0';
- if (is_module)
- kcmdline_parse_result(config, modname, param, value);
- param = value = NULL;
- modname = p + 1;
- is_module = true;
break;
case '.':
- if (param == NULL) {
+ if (state == STATE_MODNAME) {
*p = '\0';
param = p + 1;
+ state = STATE_PARAM;
+ } else if (state == STATE_PARAM) {
+ state = STATE_IGNORE;
}
break;
case '=':
- if (param != NULL)
+ if (state == STATE_PARAM) {
+ /*
+ * Don't set *p to '\0': the value var shadows
+ * param
+ */
value = p + 1;
- else
- is_module = false;
+ state = STATE_VALUE;
+ } else if (state == STATE_MODNAME) {
+ state = STATE_IGNORE;
+ }
break;
}
- }
- *p = '\0';
- if (is_module)
- kcmdline_parse_result(config, modname, param, value);
+ if (state == STATE_COMPLETE) {
+ kcmdline_parse_result(config, modname, param, value);
+ /* start over on next iteration */
+ modname = p + 1;
+ state = STATE_MODNAME;
+ }
+ }
return 0;
}
--
2.30.1