diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-03-23 08:33:59 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-03-29 10:34:39 +0900 |
commit | 94e0130ab0e22866033fb70891bd9155de1111a1 (patch) | |
tree | 7f9834d576477d3ac1ea0bd84aced3784ac6ca01 | |
parent | 70806d455483329ba69917832268800bff411382 (diff) | |
download | systemd-94e0130ab0e22866033fb70891bd9155de1111a1.tar.gz |
proc-cmdline: introduce proc_cmdline_strv()
When we are running in a container, we parse the command line of PID1 in
proc_cmdline_parse() or friends. Previously, first we merge the command
line nulstr as a single string, and then split by using
extract_first_word(). That's not only redundant, but also unsafe when
the command line argument contain a space.
This drops the redundant steps, hence we can safely parse arguments with
space.
-rw-r--r-- | src/basic/proc-cmdline.c | 51 | ||||
-rw-r--r-- | src/basic/proc-cmdline.h | 1 | ||||
-rw-r--r-- | src/test/test-proc-cmdline.c | 8 |
3 files changed, 40 insertions, 20 deletions
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 06822ddb49..010bb762c4 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -40,6 +40,30 @@ int proc_cmdline(char **ret) { return read_one_line_file("/proc/cmdline", ret); } +int proc_cmdline_strv(char ***ret) { + const char *e; + int r; + + assert(ret); + + /* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */ + e = secure_getenv("SYSTEMD_PROC_CMDLINE"); + if (e) + return strv_split_full(ret, e, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE); + + if (detect_container() > 0) + return get_process_cmdline_strv(1, /* flags = */ 0, ret); + else { + _cleanup_free_ char *s = NULL; + + r = read_one_line_file("/proc/cmdline", &s); + if (r < 0) + return r; + + return strv_split_full(ret, s, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE); + } +} + static char *mangle_word(const char *word, ProcCmdlineFlags flags) { char *c; @@ -90,7 +114,6 @@ static int proc_cmdline_parse_strv(char **args, proc_cmdline_parse_t parse_item, int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) { _cleanup_strv_free_ char **args = NULL; - _cleanup_free_ char *line = NULL; int r; assert(parse_item); @@ -98,6 +121,8 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF /* We parse the EFI variable first, because later settings have higher priority. */ if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) { + _cleanup_free_ char *line = NULL; + r = systemd_efi_options_variable(&line); if (r < 0) { if (r != -ENODATA) @@ -112,15 +137,10 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF return r; args = strv_free(args); - line = mfree(line); } } - r = proc_cmdline(&line); - if (r < 0) - return r; - - r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE); + r = proc_cmdline_strv(&args); if (r < 0) return r; @@ -229,11 +249,7 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value) return -EINVAL; - r = proc_cmdline(&line); - if (r < 0) - return r; - - r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE); + r = proc_cmdline_strv(&args); if (r < 0) return r; @@ -250,7 +266,6 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val return r; } - line = mfree(line); r = systemd_efi_options_variable(&line); if (r == -ENODATA) { if (ret_value) @@ -330,7 +345,6 @@ static int cmdline_get_key_ap(ProcCmdlineFlags flags, char* const* args, va_list int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) { _cleanup_strv_free_ char **args = NULL; - _cleanup_free_ char *line = NULL; int r, ret = 0; va_list ap; @@ -341,6 +355,8 @@ int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) { /* This call may clobber arguments on failure! */ if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) { + _cleanup_free_ char *line = NULL; + r = systemd_efi_options_variable(&line); if (r < 0 && r != -ENODATA) log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m"); @@ -357,15 +373,10 @@ int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) { ret = r; args = strv_free(args); - line = mfree(line); } } - r = proc_cmdline(&line); - if (r < 0) - return r; - - r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE); + r = proc_cmdline_strv(&args); if (r < 0) return r; diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index 8650e293ce..d64d7182b8 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -15,6 +15,7 @@ typedef enum ProcCmdlineFlags { typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data); int proc_cmdline(char **ret); +int proc_cmdline_strv(char ***ret); int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, ProcCmdlineFlags flags); diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 7f8330cc24..943eb3513c 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -9,6 +9,7 @@ #include "proc-cmdline.h" #include "special.h" #include "string-util.h" +#include "strv.h" #include "tests.h" static int obj; @@ -27,6 +28,7 @@ TEST(proc_cmdline_parse) { TEST(proc_cmdline_override) { _cleanup_free_ char *line = NULL, *value = NULL; + _cleanup_strv_free_ char **args = NULL; assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0); assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=different") == 0); @@ -35,6 +37,9 @@ TEST(proc_cmdline_override) { assert_se(proc_cmdline(&line) >= 0); assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"")); line = mfree(line); + assert_se(proc_cmdline_strv(&args) >= 0); + assert_se(strv_equal(args, STRV_MAKE("foo_bar=quux", "wuff-piep=tuet", "zumm", "some_arg_with_space=foo bar", "and_one_more=zzz aaa"))); + args = strv_free(args); /* Test if parsing makes uses of the override */ assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux")); @@ -52,6 +57,9 @@ TEST(proc_cmdline_override) { assert_se(proc_cmdline(&line) >= 0); assert_se(streq(line, "hoge")); line = mfree(line); + assert_se(proc_cmdline_strv(&args) >= 0); + assert_se(strv_equal(args, STRV_MAKE("hoge"))); + args = strv_free(args); assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux")); value = mfree(value); |