util: rework /proc/cmdline parser to use unquote_first_word()

This commit is contained in:
Lennart Poettering 2014-11-07 00:10:24 +01:00
parent b5884878a2
commit f32d2db140
4 changed files with 72 additions and 32 deletions

View File

@ -101,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) {
_cleanup_free_ char *word = NULL;
bool found;
r = unquote_first_word(&p, &word);
r = unquote_first_word(&p, &word, true);
if (r < 0)
return r;
if (r == 0)

View File

@ -6146,8 +6146,7 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
int shall_restore_state(void) {
_cleanup_free_ char *line = NULL;
const char *word, *state;
size_t l;
const char *p;
int r;
r = proc_cmdline(&line);
@ -6155,15 +6154,20 @@ int shall_restore_state(void) {
return r;
r = 1;
FOREACH_WORD_QUOTED(word, l, line, state) {
p = line;
for (;;) {
_cleanup_free_ char *word = NULL;
const char *e;
char n[l+1];
int k;
memcpy(n, word, l);
n[l] = 0;
k = unquote_first_word(&p, &word, true);
if (k < 0)
return k;
if (k == 0)
break;
e = startswith(n, "systemd.restore_state=");
e = startswith(word, "systemd.restore_state=");
if (!e)
continue;
@ -6186,8 +6190,7 @@ int proc_cmdline(char **ret) {
int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *line = NULL;
const char *w, *state;
size_t l;
const char *p;
int r;
assert(parse_item);
@ -6196,11 +6199,16 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
if (r < 0)
return r;
FOREACH_WORD_QUOTED(w, l, line, state) {
char word[l+1], *value;
p = line;
for (;;) {
_cleanup_free_ char *word = NULL;
char *value = NULL;
memcpy(word, w, l);
word[l] = 0;
r = unquote_first_word(&p, &word, true);
if (r < 0)
return r;
if (r == 0)
break;
/* Filter out arguments that are intended only for the
* initrd */
@ -6976,7 +6984,7 @@ int is_dir(const char* path, bool follow) {
return !!S_ISDIR(st.st_mode);
}
int unquote_first_word(const char **p, char **ret) {
int unquote_first_word(const char **p, char **ret, bool relax) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
@ -7035,8 +7043,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case VALUE_ESCAPE:
if (c == 0)
if (c == 0) {
if (relax)
goto finish;
return -EINVAL;
}
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@ -7047,9 +7058,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case SINGLE_QUOTE:
if (c == 0)
if (c == 0) {
if (relax)
goto finish;
return -EINVAL;
else if (c == '\'')
} else if (c == '\'')
state = VALUE;
else if (c == '\\')
state = SINGLE_QUOTE_ESCAPE;
@ -7063,8 +7076,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case SINGLE_QUOTE_ESCAPE:
if (c == 0)
if (c == 0) {
if (relax)
goto finish;
return -EINVAL;
}
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@ -7090,8 +7106,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case DOUBLE_QUOTE_ESCAPE:
if (c == 0)
if (c == 0) {
if (relax)
goto finish;
return -EINVAL;
}
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@ -7151,7 +7170,7 @@ int unquote_many_words(const char **p, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
r = unquote_first_word(p, &l[c]);
r = unquote_first_word(p, &l[c], false);
if (r < 0) {
int j;

View File

@ -1018,7 +1018,7 @@ int take_password_lock(const char *root);
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
int unquote_first_word(const char **p, char **ret);
int unquote_first_word(const char **p, char **ret, bool relax);
int unquote_many_words(const char **p, ...) _sentinel_;
int free_and_strdup(char **p, const char *s);

View File

@ -1173,51 +1173,60 @@ static void test_unquote_first_word(void) {
char *t;
p = original = "foobar waldo";
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 7);
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 12);
assert_se(unquote_first_word(&p, &t) == 0);
assert_se(unquote_first_word(&p, &t, false) == 0);
assert_se(!t);
assert_se(p == original + 12);
p = original = "\"foobar\" \'waldo\'";
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 9);
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 16);
assert_se(unquote_first_word(&p, &t) == 0);
assert_se(unquote_first_word(&p, &t, false) == 0);
assert_se(!t);
assert_se(p == original + 16);
p = original = "\"";
assert_se(unquote_first_word(&p, &t) == -EINVAL);
assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'";
assert_se(unquote_first_word(&p, &t) == -EINVAL);
assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'fooo";
assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
assert_se(p == original + 5);
p = original = "\'fooo";
assert_se(unquote_first_word(&p, &t, true) > 0);
assert_se(streq(t, "fooo"));
assert_se(p == original + 5);
p = original = "yay\'foo\'bar";
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "yayfoobar"));
free(t);
assert_se(p == original + 11);
p = original = " foobar ";
assert_se(unquote_first_word(&p, &t) > 0);
assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 12);
@ -1277,6 +1286,17 @@ static void test_unquote_many_words(void) {
free(a);
}
static int parse_item(const char *key, const char *value) {
assert_se(key);
log_info("kernel cmdline option <%s> = <%s>", key, strna(value));
return 0;
}
static void test_parse_proc_cmdline(void) {
assert_se(parse_proc_cmdline(parse_item) >= 0);
}
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@ -1348,6 +1368,7 @@ int main(int argc, char *argv[]) {
test_execute_directory();
test_unquote_first_word();
test_unquote_many_words();
test_parse_proc_cmdline();
return 0;
}