* Parsing kernel parameters and escaping "
@ 2009-07-05 13:54 Daniel Mierswa
2009-07-06 23:03 ` [RFC] " Daniel Mierswa
0 siblings, 1 reply; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-05 13:54 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 607 bytes --]
Hi list,
I was wondering why " cannot be escaped when parsing kernel parameters
in kernel/params.c. Given a disk label like 'foo " bar' and passing
something to the kernel command line like real_root=LABEL="foo \" bar"
this would make 'bar' a kernel parameter which is misleading imho. Any
ideas why this path was chosen and how I am supposed to pass such a
parameter that it is considered as one entity?
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply
know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC] Re: Parsing kernel parameters and escaping "
2009-07-05 13:54 Parsing kernel parameters and escaping " Daniel Mierswa
@ 2009-07-06 23:03 ` Daniel Mierswa
2009-07-06 23:05 ` Daniel Mierswa
2009-07-07 0:54 ` Daniel Mierswa
0 siblings, 2 replies; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-06 23:03 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1006 bytes --]
As stated in my last E-Mail in this thread there are currently some
limitations when passing quotes to kernel parameters, I tried to remove
some of those limitations. A git fp is attached.
(from the commit message):
> There was a limitation for kernel parameters with regards to quoting. It
> wasn't possible to escape quotes or use quotes to form space-filled
> values _inside_ parameters. This patch attempts to make that possible,
> kernel parameters are now parsed as follows:
> '"param= value"' [param= value][]
> 'param=" value "" combination "' [param][ value combination ]
> 'param=" \" test"' [param][ " test]
> '"param"=another' [param][another]
Any suggestions welcome. Please be kind, as I'm not too familar with
writing parsers, kernel development and what I may have broke. :-)
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply
know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-06 23:03 ` [RFC] " Daniel Mierswa
@ 2009-07-06 23:05 ` Daniel Mierswa
2009-07-07 0:54 ` Daniel Mierswa
1 sibling, 0 replies; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-06 23:05 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1.1: Type: text/plain, Size: 1100 bytes --]
Daniel Mierswa wrote:
> As stated in my last E-Mail in this thread there are currently some
> limitations when passing quotes to kernel parameters, I tried to remove
> some of those limitations. A git fp is attached.
>
> (from the commit message):
>> There was a limitation for kernel parameters with regards to quoting. It
>> wasn't possible to escape quotes or use quotes to form space-filled
>> values _inside_ parameters. This patch attempts to make that possible,
>> kernel parameters are now parsed as follows:
>> '"param= value"' [param= value][]
>> 'param=" value "" combination "' [param][ value combination ]
>> 'param=" \" test"' [param][ " test]
>> '"param"=another' [param][another]
>
> Any suggestions welcome. Please be kind, as I'm not too familar with
> writing parsers, kernel development and what I may have broke. :-)
>
Great I forgot the patch, here it is now.
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply
know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #1.2: kernel.patch --]
[-- Type: text/plain, Size: 4025 bytes --]
From 2dbc124b6c1674592ec5faaae5ca87fc7b16cc12 Mon Sep 17 00:00:00 2001
From: Daniel Mierswa <impulze@impulze.org>
Date: Tue, 7 Jul 2009 00:54:38 +0200
Subject: [PATCH] Attempt to handle quotes in kernel parameters
There was a limitation for kernel parameters with regards to quoting. It
wasn't possible to escape quotes or use quotes to form space-filled
values _inside_ parameters. This patch attempts to make that possible,
kernel parameters are now parsed as follows:
'"param= value"' [param= value][]
'param=" value "" combination "' [param][ value combination ]
'param=" \" test"' [param][ " test]
'"param"=another' [param][another]
---
kernel/params.c | 135 ++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 93 insertions(+), 42 deletions(-)
diff --git a/kernel/params.c b/kernel/params.c
index de273ec..0a9fc14 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -75,58 +75,109 @@ static int parse_one(char *param,
return -ENOENT;
}
-/* You can use " around spaces, but can't escape ". */
-/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+/* handle quotes in tokens (parameter and values)
+ * '" foo bar "' => ' foo bar '
+ * '" foo \" "' => ' foo " '
+ */
+static void add_token(char ** token, char * args)
{
- unsigned int i, equals = 0;
- int in_quote = 0, quoted = 0;
- char *next;
+ char * iterator, * last_quote;
+ int in_quotes;
- if (*args == '"') {
- args++;
- in_quote = 1;
- quoted = 1;
+ in_quotes = 0;
+
+ for (iterator = args; *iterator; iterator++) {
+ if (*iterator == '\\' && *(iterator + 1) == '"') {
+ char * mover;
+
+ /* move all characters back */
+ for (mover = iterator; *mover; mover++) {
+ *mover = *(mover + 1);
+ }
+
+ continue;
+ }
+
+ if (*iterator != '"') {
+ continue;
+ }
+
+ if (in_quotes) {
+ char * mover;
+
+ /* move whole string back until current " is reached */
+ for (mover = last_quote; mover != iterator - 1; mover++) {
+ *mover = *(mover + 1);
+ }
+
+ /* ignore the current " and move the rest of the string back */
+ while (*mover) {
+ *mover = *(mover + 2);
+ mover++;
+ }
+
+ /* ignored 2 quotes, decrease the iterator */
+ iterator -= 2;
+ last_quote = NULL;
+ } else {
+ last_quote = iterator;
+ }
+
+ in_quotes = !in_quotes;
}
- for (i = 0; args[i]; i++) {
- if (args[i] == ' ' && !in_quote)
+ *token = args;
+}
+
+static char * next_arg(char * args, char ** param, char ** val)
+{
+ char * token;
+ int in_quotes, is_escaped;
+
+ *param = *val = NULL;
+ in_quotes = is_escaped = 0;
+
+ /* tokenizer */
+ for (token = args; *token; token++) {
+ /* parameter or value is finished */
+ if (!in_quotes && *token == ' ') {
+ *token = '\0';
break;
- if (equals == 0) {
- if (args[i] == '=')
- equals = i;
}
- if (args[i] == '"')
- in_quote = !in_quote;
- }
- *param = args;
- if (!equals)
- *val = NULL;
- else {
- args[equals] = '\0';
- *val = args + equals + 1;
-
- /* Don't include quotes in value. */
- if (**val == '"') {
- (*val)++;
- if (args[i-1] == '"')
- args[i-1] = '\0';
+ /* parameter/value split */
+ if (!in_quotes && *token == '=' && !*param) {
+ *token = '\0';
+ add_token(param, args);
+ args = token + 1;
+ continue;
+ }
+
+ if (!is_escaped && *token == '\\') {
+ is_escaped = 1;
+ continue;
}
- if (quoted && args[i-1] == '"')
- args[i-1] = '\0';
+
+ if (*token == '"' && !is_escaped) {
+ in_quotes = !in_quotes;
+ }
+
+ /* always reset escape value, only " needs it */
+ is_escaped = 0;
}
- if (args[i]) {
- args[i] = '\0';
- next = args + i + 1;
- } else
- next = args + i;
+ if (!*param) {
+ add_token(param, args);
+ } else {
+ add_token(val, args);
+ }
+
+ /* remove trailing spaces */
+ while (*token == ' ') {
+ token++;
+ }
- /* Chew up trailing spaces. */
- while (*next == ' ')
- next++;
- return next;
+ return token + 1;
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
--
1.6.3.3
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-06 23:03 ` [RFC] " Daniel Mierswa
2009-07-06 23:05 ` Daniel Mierswa
@ 2009-07-07 0:54 ` Daniel Mierswa
2009-07-12 9:41 ` Rusty Russell
1 sibling, 1 reply; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-07 0:54 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1.1: Type: text/plain, Size: 335 bytes --]
Second version of the patch, I accidently forgot to take care of out of
bounds checking when reaching the end of the kernel parameter line.
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply
know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #1.2: kernel.patch --]
[-- Type: text/plain, Size: 4265 bytes --]
From fe3bf00a0fc2db941fef41c44fc6d9eefad4d037 Mon Sep 17 00:00:00 2001
From: Daniel Mierswa <impulze@impulze.org>
Date: Tue, 7 Jul 2009 00:54:38 +0200
Subject: [PATCH] Attempt to handle quotes in kernel parameters
There was a limitation for kernel parameters with regards to quoting. It
wasn't possible to escape quotes or use quotes to form space-filled
values _inside_ parameters. This patch attempts to make that possible,
kernel parameters are now parsed as follows:
'"param= value"' [param= value][]
'param=" value "" combination "' [param][ value combination ]
'param=" \" test"' [param][ " test]
'"param"=another' [param][another]
---
kernel/params.c | 146 +++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 104 insertions(+), 42 deletions(-)
diff --git a/kernel/params.c b/kernel/params.c
index de273ec..73de8f5 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -75,58 +75,120 @@ static int parse_one(char *param,
return -ENOENT;
}
-/* You can use " around spaces, but can't escape ". */
-/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+/* handle quotes in tokens (parameter and values)
+ * '" foo bar "' => ' foo bar '
+ * '" foo \" "' => ' foo " '
+ */
+static void add_token(char ** token, char * args)
{
- unsigned int i, equals = 0;
- int in_quote = 0, quoted = 0;
- char *next;
+ char * iterator, * last_quote;
+ int in_quotes;
- if (*args == '"') {
- args++;
- in_quote = 1;
- quoted = 1;
+ in_quotes = 0;
+ last_quote = NULL;
+
+ for (iterator = args; *iterator; iterator++) {
+ if (*iterator == '\\' && *(iterator + 1) == '"') {
+ char * mover;
+
+ /* move all characters back */
+ for (mover = iterator; *mover; mover++) {
+ *mover = *(mover + 1);
+ }
+
+ continue;
+ }
+
+ if (*iterator != '"') {
+ continue;
+ }
+
+ if (in_quotes) {
+ char * mover;
+
+ /* move whole string back until current " is reached */
+ for (mover = last_quote; mover != iterator - 1; mover++) {
+ *mover = *(mover + 1);
+ }
+
+ /* ignore the current " and move the rest of the string back */
+ while (*mover) {
+ *mover = *(mover + 2);
+ mover++;
+ }
+
+ /* ignored 2 quotes, decrease the iterator */
+ iterator -= 2;
+ last_quote = NULL;
+ } else {
+ last_quote = iterator;
+ }
+
+ in_quotes = !in_quotes;
}
- for (i = 0; args[i]; i++) {
- if (args[i] == ' ' && !in_quote)
+ *token = args;
+}
+
+static char * next_arg(char * args, char ** param, char ** val)
+{
+ char * token, * next;
+ int in_quotes, is_escaped;
+
+ *param = *val = next = NULL;
+ in_quotes = is_escaped = 0;
+
+ /* tokenizer */
+ for (token = args; *token; token++) {
+ /* parameter or value is finished */
+ if (!in_quotes && *token == ' ') {
+ *token = '\0';
+
+ /* there're still characters in the parameter line */
+ next = token + 1;
+
+ /* remove trailing whitespace */
+ while (*next == ' ') {
+ next++;
+ }
+
break;
- if (equals == 0) {
- if (args[i] == '=')
- equals = i;
}
- if (args[i] == '"')
- in_quote = !in_quote;
- }
- *param = args;
- if (!equals)
- *val = NULL;
- else {
- args[equals] = '\0';
- *val = args + equals + 1;
-
- /* Don't include quotes in value. */
- if (**val == '"') {
- (*val)++;
- if (args[i-1] == '"')
- args[i-1] = '\0';
+ /* parameter/value split */
+ if (!in_quotes && *token == '=' && !*param) {
+ *token = '\0';
+ add_token(param, args);
+ args = token + 1;
+ continue;
}
- if (quoted && args[i-1] == '"')
- args[i-1] = '\0';
+
+ if (!is_escaped && *token == '\\') {
+ is_escaped = 1;
+ continue;
+ }
+
+ if (*token == '"' && !is_escaped) {
+ in_quotes = !in_quotes;
+ }
+
+ /* always reset escape value, only " needs it */
+ is_escaped = 0;
}
- if (args[i]) {
- args[i] = '\0';
- next = args + i + 1;
- } else
- next = args + i;
+ if (!*param) {
+ add_token(param, args);
+ } else {
+ add_token(val, args);
+ }
+
+ /* there're parameters left in the command line */
+ if (next) {
+ return next;
+ }
- /* Chew up trailing spaces. */
- while (*next == ' ')
- next++;
- return next;
+ /* end of the line */
+ return token;
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
--
1.6.3.3
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-07 0:54 ` Daniel Mierswa
@ 2009-07-12 9:41 ` Rusty Russell
2009-07-12 17:59 ` Daniel Mierswa
0 siblings, 1 reply; 9+ messages in thread
From: Rusty Russell @ 2009-07-12 9:41 UTC (permalink / raw)
To: Daniel Mierswa; +Cc: linux-kernel
On Tue, 7 Jul 2009 10:24:18 am Daniel Mierswa wrote:
> There was a limitation for kernel parameters with regards to quoting. It
> wasn't possible to escape quotes or use quotes to form space-filled
> values inside parameters.
Hi Daniel!
Yes, we've never had the ability to escape quotes (and you're the first to
ask), so when I wrote this code I kept it simple. You can have spaced out
values, but you need to quote the whole thing "param=some value with spaces".
We have to be careful not to break existing cmdlines tho: I don't know
if anyone uses \ currently, but simply interpreting \" is probably safe.
> +/* handle quotes in tokens (parameter and values)
> + * '" foo bar "' => ' foo bar '
> + * '" foo \" "' => ' foo " '
> + */
> +static void add_token(char ** token, char * args)
add_token is a weird name for this. It actually mangles the argument, and it
really should return the char *.
How about something like:
static unsigned int pull_token(char *args, const char *delim)
Which unescapes and returns the length of the token, or zero if it simply
swallowed delimeters? Assuming it always nul terminates, then the caller can
simply do:
while (*args) {
len = pull_token(args, " \t\n=");
if (!len)
/* Leading whitespace. */
continue;
*param = args;
args += len;
if (args[0] != '=') {
*val = NULL;
} else {
len = pull_token(args+1, " \t\n");
*val = args;
args += len;
}
Important cases to test are:
x param = "x", val = NULL
x= param = "x", val = ""
x=y=1 param = "x", val = "y=1"
Plus all variations where x and y contain quotes.
Cheers,
Rusty.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-12 9:41 ` Rusty Russell
@ 2009-07-12 17:59 ` Daniel Mierswa
2009-07-12 23:57 ` Rusty Russell
0 siblings, 1 reply; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-12 17:59 UTC (permalink / raw)
To: Rusty Russell; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1918 bytes --]
Rusty Russell wrote:
> Yes, we've never had the ability to escape quotes (and you're the first to
> ask), so when I wrote this code I kept it simple. You can have spaced out
> values, but you need to quote the whole thing "param=some value with spaces".
True, but that would leave quotes where they are instead of removing them.
> We have to be careful not to break existing cmdlines tho: I don't know
> if anyone uses \ currently, but simply interpreting \" is probably safe.
Yes, the only way that compatibility seems to break is that now \" in a quoted
string is replaced by a single ".
> add_token is a weird name for this. It actually mangles the argument, and it
> really should return the char *.
Fixed.
> How about something like:
> static unsigned int pull_token(char *args, const char *delim)
Fixed.
> Which unescapes and returns the length of the token, or zero if it simply
> swallowed delimeters? Assuming it always nul terminates, then the caller can
> simply do:
> [...]
Fixed.
> Important cases to test are:
> x param = "x", val = NULL
> x= param = "x", val = ""
> x=y=1 param = "x", val = "y=1"
>
> Plus all variations where x and y contain quotes.
Tested:
|param| => [param[(none)]]
|param=| => [param[]]
|param=value| => [param[value]]
|param=value=withequal | => [param[value=withequal]]
|param="value with spaces" | => [param[value with spaces]]
|param="value with spaces and quotes \"" | => [param[value with spaces and quotes "]]
|param=\"foo\" | => [param[\"foo" ]]
|"param = value" | => [param = value[(none)]]
> Cheers,
> Rusty.
Thanks for your kind feedback, I'm willing to put more effort into this when needed. I really
first wanted to check if patches for this are welcomed.
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #2: kernel2.patch --]
[-- Type: text/plain, Size: 4158 bytes --]
>From 21402346a295eb539a111b777ee54f3dd5263b6f Mon Sep 17 00:00:00 2001
From: Daniel Mierswa <impulze@impulze.org>
Date: Tue, 7 Jul 2009 00:54:38 +0200
Subject: [PATCH] Attempt to handle quotes in kernel parameters
There was a limitation for kernel parameters with regards to quoting. It
wasn't possible to escape quotes or use quotes to form space-filled
values _inside_ parameters. This patch attempts to make that possible,
kernel parameters are now parsed as follows:
'"param= value"' [param= value][]
'param=" value "" combination "' [param][ value combination ]
'param=" \" test"' [param][ " test]
'"param"=another' [param][another]
Signed-off-by: Daniel Mierswa <impulze@impulze.org>
---
kernel/params.c | 128 +++++++++++++++++++++++++++++++++++--------------------
1 files changed, 82 insertions(+), 46 deletions(-)
diff --git a/kernel/params.c b/kernel/params.c
index 7f6912c..5f9709d 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -72,58 +72,98 @@ static int parse_one(char *param,
return -ENOENT;
}
-/* You can use " around spaces, but can't escape ". */
-/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+/* modifies args with handled quotes
+ * [" foo bar "] => [ foo bar ]
+ * [" foo \" "] => [ foo " ]
+ * [\"foo] => [\"foo]
+ * [\"foo\" ] => [\"foo" ]
+ */
+static size_t pull_token(char *args, char const *delim)
{
- unsigned int i, equals = 0;
- int in_quote = 0, quoted = 0;
- char *next;
+ size_t length = 0;
+ char *iterator = NULL, *last_quote = NULL;
+
+ for (iterator = args; *iterator; iterator++, length++) {
+ if (*iterator == '"') {
+ if (last_quote) {
+ char *mover = last_quote;
+
+ /* move whole string back until current " is reached */
+ while (mover != iterator - 1) {
+ *mover = *(mover + 1);
+ mover++;
+ }
+
+ /* ignore the current " and move the rest of the string back */
+ while (*mover) {
+ *mover = *(mover + 2);
+ mover++;
+ }
+
+ /* ignored 2 quotes, decrease the iterator and length */
+ length -= 2;
+ iterator -= 2;
+ last_quote = NULL;
+ } else {
+ last_quote = iterator;
+ }
- if (*args == '"') {
- args++;
- in_quote = 1;
- quoted = 1;
- }
+ continue;
+ }
- for (i = 0; args[i]; i++) {
- if (args[i] == ' ' && !in_quote)
- break;
- if (equals == 0) {
- if (args[i] == '=')
- equals = i;
+ if (last_quote) {
+ /* escaped quote */
+ if (*iterator == '\\' && *(iterator + 1) == '"') {
+ char *mover = NULL;
+
+ /* move all characters back */
+ for (mover = iterator; *mover; mover++) {
+ *mover = *(mover + 1);
+ }
+ }
+
+ continue;
+ }
+
+ {
+ /* check for delimiter */
+ char const *delim_iterator = NULL;
+ for (delim_iterator = delim; *delim_iterator; delim_iterator++) {
+ if (*iterator == *delim_iterator) {
+ return length;
+ }
+ }
}
- if (args[i] == '"')
- in_quote = !in_quote;
}
+ return length;
+}
+
+static char *next_arg(char *args, char **param, char **val)
+{
+ size_t len;
+
+ /* Chew leading spaces */
+ while (*args == ' ')
+ args++;
+
+ len = pull_token(args, " \t\n=");
*param = args;
- if (!equals)
+ args += len;
+
+ if (*args == '=') {
+ (*param)[len] = '\0';
+ args++;
+ len = pull_token(args, " \t\n");
+ *val = args;
+ args += len;
+ (*val)[len] = '\0';
+ } else {
+ (*param)[len] = '\0';
*val = NULL;
- else {
- args[equals] = '\0';
- *val = args + equals + 1;
-
- /* Don't include quotes in value. */
- if (**val == '"') {
- (*val)++;
- if (args[i-1] == '"')
- args[i-1] = '\0';
- }
- if (quoted && args[i-1] == '"')
- args[i-1] = '\0';
}
- if (args[i]) {
- args[i] = '\0';
- next = args + i + 1;
- } else
- next = args + i;
-
- /* Chew up trailing spaces. */
- while (*next == ' ')
- next++;
- return next;
+ return args + 1;
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
@@ -137,10 +177,6 @@ int parse_args(const char *name,
DEBUGP("Parsing ARGS: %s\n", args);
- /* Chew leading spaces */
- while (*args == ' ')
- args++;
-
while (*args) {
int ret;
int irq_was_disabled;
--
1.6.3.3
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-12 17:59 ` Daniel Mierswa
@ 2009-07-12 23:57 ` Rusty Russell
2009-07-13 2:49 ` Daniel Mierswa
0 siblings, 1 reply; 9+ messages in thread
From: Rusty Russell @ 2009-07-12 23:57 UTC (permalink / raw)
To: Daniel Mierswa; +Cc: linux-kernel
On Mon, 13 Jul 2009 03:29:39 am Daniel Mierswa wrote:
> Tested:
> |param| => [param[(none)]]
> |param=| => [param[]]
> |param=value| => [param[value]]
> |param=value=withequal | => [param[value=withequal]]
> |param="value with spaces" | => [param[value with spaces]]
> |param="value with spaces and quotes \"" | => [param[value with spaces and
> | quotes "]] param=\"foo\" | => [param[\"foo" ]]
> |"param = value" | => [param = value[(none)]]
Hi Daniel!
It might be nice to have that test code somewhere at the bottom of param.c,
at least while we're playing with the code.
> Thanks for your kind feedback, I'm willing to put more effort into this
> when needed. I really first wanted to check if patches for this are
> welcomed.
Well, IMO it's a maintainer's job to give feedback, and patches should always be welcomed (even if not applied!).
Now to the details:
> +static size_t pull_token(char *args, char const *delim)
> {
> - unsigned int i, equals = 0;
> - int in_quote = 0, quoted = 0;
> - char *next;
> + size_t length = 0;
> + char *iterator = NULL, *last_quote = NULL;
> +
> + for (iterator = args; *iterator; iterator++, length++) {
I really prefer "i" instead of "iterator". I actually think i as an
unsigned/size_t here would probably make the code neater, but that's an aside.
> + if (*iterator == '"') {
> + if (last_quote) {
> + char *mover = last_quote;
> +
> + /* move whole string back until current " is reached */
> + while (mover != iterator - 1) {
> + *mover = *(mover + 1);
> + mover++;
> + }
memmove?
> + {
> + /* check for delimiter */
> + char const *delim_iterator = NULL;
> + for (delim_iterator = delim; *delim_iterator; delim_iterator++) {
> + if (*iterator == *delim_iterator) {
> + return length;
> + }
> + }
How about:
if (strchr(delim, *iterator))
return length;
> +static char *next_arg(char *args, char **param, char **val)
> +{
> + size_t len;
> +
> + /* Chew leading spaces */
> + while (*args == ' ')
> + args++;
Note that this will undo another pending patch, which changes this to
isspace() to handle tabs et al.
Thanks!
Rusty.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-12 23:57 ` Rusty Russell
@ 2009-07-13 2:49 ` Daniel Mierswa
2009-07-14 2:49 ` Rusty Russell
0 siblings, 1 reply; 9+ messages in thread
From: Daniel Mierswa @ 2009-07-13 2:49 UTC (permalink / raw)
To: Rusty Russell; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1280 bytes --]
Rusty Russell wrote:
> It might be nice to have that test code somewhere at the bottom of param.c,
> at least while we're playing with the code.
Umm, I'm not sure where test-code is supposed to go in kernel code.
Should it be a main() function, a test() function, just a comment, could
you elaborate? All i did now was to build a small program that reads
argv[1] and uses next_arg just like parse_args() in params.c does.
> Well, IMO it's a maintainer's job to give feedback, and patches should always be welcomed (even if not applied!).
Ok, we'll see where this goes. So far I'm fine chatting about this with
everyone.
> I really prefer "i" instead of "iterator". I actually think i as an
> unsigned/size_t here would probably make the code neater, but that's an aside.
Fixed.
> memmove?
Fixed.
> How about:
> if (strchr(delim, *iterator))
> return length;
I really should do more C. :-P Fixed.
> Note that this will undo another pending patch, which changes this to
> isspace() to handle tabs et al.
I will re-do the patch against that commit then once it's done.
> Thanks!
Ditto.
--
Mierswa, Daniel
If you still don't like it, that's ok: that's why I'm boss. I simply
know better than you do.
--- Linus Torvalds, comp.os.linux.advocacy, 1996/07/22
[-- Attachment #2: kernel2.patch --]
[-- Type: text/plain, Size: 3797 bytes --]
>From 36d93d40b535ce7f1253d7740f214dc65b2975b9 Mon Sep 17 00:00:00 2001
From: Daniel Mierswa <impulze@impulze.org>
Date: Tue, 7 Jul 2009 00:54:38 +0200
Subject: [PATCH] Attempt to handle quotes in kernel parameters
There was a limitation for kernel parameters with regards to quoting. It
wasn't possible to escape quotes or use quotes to form space-filled
values _inside_ parameters. This patch attempts to make that possible,
kernel parameters are now parsed as follows:
'"param= value"' [param= value][]
'param=" value "" combination "' [param][ value combination ]
'param=" \" test"' [param][ " test]
'"param"=another' [param][another]
Signed-off-by: Daniel Mierswa <impulze@impulze.org>
---
kernel/params.c | 111 ++++++++++++++++++++++++++++++++----------------------
1 files changed, 66 insertions(+), 45 deletions(-)
diff --git a/kernel/params.c b/kernel/params.c
index 7f6912c..5908623 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -72,58 +72,83 @@ static int parse_one(char *param,
return -ENOENT;
}
-/* You can use " around spaces, but can't escape ". */
-/* Hyphens and underscores equivalent in parameter names. */
-static char *next_arg(char *args, char **param, char **val)
+/* modifies args with handled quotes
+ * [" foo bar "] => [ foo bar ]
+ * [" foo \" "] => [ foo " ]
+ * [\"foo] => [\"foo]
+ * [\"foo\" ] => [\"foo" ]
+ */
+int printf(char const *,...);
+static size_t pull_token(char *args, char const *delim)
{
- unsigned int i, equals = 0;
- int in_quote = 0, quoted = 0;
- char *next;
-
- if (*args == '"') {
- args++;
- in_quote = 1;
- quoted = 1;
- }
+ size_t i;
+ char *last_quote = NULL;
for (i = 0; args[i]; i++) {
- if (args[i] == ' ' && !in_quote)
+ if (args[i] == '"') {
+ if (last_quote) {
+ size_t remain_len = strlen(args + i + 1);
+
+ /* remove both quotes by moving strings */
+ memmove(last_quote, last_quote + 1, args + i - 1 - last_quote);
+ memmove(args + i - 1, args + i + 1, remain_len + 1);
+
+ /* fill the blank we've left */
+ args[i + remain_len] = '\0';
+
+ /* removed 2 quotes, decrease the iterator */
+ i -= 2;
+ last_quote = NULL;
+ } else {
+ last_quote = args + i;
+ }
+
+ continue;
+ }
+
+ if (last_quote) {
+ /* escaped quote */
+ if (args[i] == '\\' && args[i + 1] == '"') {
+ /* move all characters back */
+ memmove(args + i, args + i + 1, strlen(args + i + 1) + 1);
+ }
+
+ continue;
+ }
+
+ if (strchr(delim, args[i])) {
break;
- if (equals == 0) {
- if (args[i] == '=')
- equals = i;
}
- if (args[i] == '"')
- in_quote = !in_quote;
}
+ return i;
+}
+
+static char *next_arg(char *args, char **param, char **val)
+{
+ size_t len;
+
+ /* Chew leading spaces */
+ while (*args == ' ')
+ args++;
+
+ len = pull_token(args, " \t\n=");
*param = args;
- if (!equals)
+ args += len;
+
+ if (*args == '=') {
+ (*param)[len] = '\0';
+ args++;
+ len = pull_token(args, " \t\n");
+ *val = args;
+ args += len;
+ (*val)[len] = '\0';
+ } else {
+ (*param)[len] = '\0';
*val = NULL;
- else {
- args[equals] = '\0';
- *val = args + equals + 1;
-
- /* Don't include quotes in value. */
- if (**val == '"') {
- (*val)++;
- if (args[i-1] == '"')
- args[i-1] = '\0';
- }
- if (quoted && args[i-1] == '"')
- args[i-1] = '\0';
}
- if (args[i]) {
- args[i] = '\0';
- next = args + i + 1;
- } else
- next = args + i;
-
- /* Chew up trailing spaces. */
- while (*next == ' ')
- next++;
- return next;
+ return args + 1;
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
@@ -137,10 +162,6 @@ int parse_args(const char *name,
DEBUGP("Parsing ARGS: %s\n", args);
- /* Chew leading spaces */
- while (*args == ' ')
- args++;
-
while (*args) {
int ret;
int irq_was_disabled;
--
1.6.3.3
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC] Re: Parsing kernel parameters and escaping "
2009-07-13 2:49 ` Daniel Mierswa
@ 2009-07-14 2:49 ` Rusty Russell
0 siblings, 0 replies; 9+ messages in thread
From: Rusty Russell @ 2009-07-14 2:49 UTC (permalink / raw)
To: Daniel Mierswa; +Cc: linux-kernel
On Mon, 13 Jul 2009 12:19:17 pm Daniel Mierswa wrote:
> Rusty Russell wrote:
> > It might be nice to have that test code somewhere at the bottom of
> > param.c, at least while we're playing with the code.
>
> Umm, I'm not sure where test-code is supposed to go in kernel code.
> Should it be a main() function, a test() function, just a comment, could
> you elaborate? All i did now was to build a small program that reads
> argv[1] and uses next_arg just like parse_args() in params.c does.
Usually I write a function like:
#if 0
static int param_result(char *param, char *val)
{
static int expect;
const char *params[] = { "foo", "foo", ... };
const char *vals[] = "bar", NULL, ...};
BUG_ON(strcmp(param,params[expect]) != 0);
if (vals[expect] == NULL)
BUGON(val);
else
BUGON(strcmp(val, vals[expect]) != 0);
}
static int test_params(void)
{
char *str = kstrdup("foo=bar foo ...", GFP_KERNEL);
parse_args("test", str, NULL, 0, param_result);
return 0;
}
module_init(test_params);
#endif
> > Thanks!
>
> Ditto.
Thanks for all the work!
Rusty.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-07-14 2:49 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-05 13:54 Parsing kernel parameters and escaping " Daniel Mierswa
2009-07-06 23:03 ` [RFC] " Daniel Mierswa
2009-07-06 23:05 ` Daniel Mierswa
2009-07-07 0:54 ` Daniel Mierswa
2009-07-12 9:41 ` Rusty Russell
2009-07-12 17:59 ` Daniel Mierswa
2009-07-12 23:57 ` Rusty Russell
2009-07-13 2:49 ` Daniel Mierswa
2009-07-14 2:49 ` Rusty Russell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox