diff options
43 files changed, 406 insertions, 331 deletions
@@ -63,6 +63,13 @@ CHANGES WITH 240 in spe: has been added to revert this change in behaviour, which might be an option for systems that turn off memcg in the kernel. + * When no /etc/locale.conf file exists (and hence no locale settings + are in place), systemd will now use the "C.UTF-8" locale by default, + and set LANG= to it. This locale is supported by various + distributions including Fedora, with clear indications that upstream + glibc is going to make it available too. This locale enables UTF-8 + mode by default, which appears appropriate for 2018. + CHANGES WITH 239: * NETWORK INTERFACE DEVICE NAMING CHANGES: systemd-udevd's "net_id" @@ -28,12 +28,11 @@ Features: * systemd-gpt-auto: if we find the root dir mounted read-only and the gpt flag doesn't say so generate job that remounts it writable +* when no locale is configured, default to UEFI's PlatformLang variable + * When logind.conf contains HandleLidSwitch=suspend-then-hibernate and we can't hibernate because the swap partition isn't large enough, still suspend -* Now that C.UTF-8 is standardized in glibc, default to it if locale.conf - doesn't set anything otherwise - * bootctl: implement Type #2 boot loader entry discovery * bootctl,sd-boot: actually honour the "architecture" key diff --git a/src/basic/exec-util.c b/src/basic/exec-util.c index 031a99afc1..10d774dfcd 100644 --- a/src/basic/exec-util.c +++ b/src/basic/exec-util.c @@ -241,7 +241,7 @@ static int gather_environment_generate(int fd, void *arg) { return -errno; } - r = load_env_file_pairs(f, NULL, NULL, &new); + r = load_env_file_pairs(f, NULL, &new); if (r < 0) return r; diff --git a/src/basic/fileio.c b/src/basic/fileio.c index dc12d0e07f..d3593f196f 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -367,7 +367,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) { static int parse_env_file_internal( FILE *f, const char *fname, - const char *newline, int (*push) (const char *filename, unsigned line, const char *key, char *value, void *userdata, int *n_pushed), void *userdata, @@ -393,8 +392,6 @@ static int parse_env_file_internal( COMMENT_ESCAPE } state = PRE_KEY; - assert(newline); - if (f) r = read_full_stream(f, &contents, NULL); else @@ -422,7 +419,7 @@ static int parse_env_file_internal( break; case KEY: - if (strchr(newline, c)) { + if (strchr(NEWLINE, c)) { state = PRE_KEY; line++; n_key = 0; @@ -444,7 +441,7 @@ static int parse_env_file_internal( break; case PRE_VALUE: - if (strchr(newline, c)) { + if (strchr(NEWLINE, c)) { state = PRE_KEY; line++; key[n_key] = 0; @@ -482,7 +479,7 @@ static int parse_env_file_internal( break; case VALUE: - if (strchr(newline, c)) { + if (strchr(NEWLINE, c)) { state = PRE_KEY; line++; @@ -527,7 +524,7 @@ static int parse_env_file_internal( case VALUE_ESCAPE: state = VALUE; - if (!strchr(newline, c)) { + if (!strchr(NEWLINE, c)) { /* Escaped newlines we eat up entirely */ if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; @@ -553,7 +550,7 @@ static int parse_env_file_internal( case SINGLE_QUOTE_VALUE_ESCAPE: state = SINGLE_QUOTE_VALUE; - if (!strchr(newline, c)) { + if (!strchr(NEWLINE, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; @@ -578,7 +575,7 @@ static int parse_env_file_internal( case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; - if (!strchr(newline, c)) { + if (!strchr(NEWLINE, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; @@ -589,7 +586,7 @@ static int parse_env_file_internal( case COMMENT: if (c == '\\') state = COMMENT_ESCAPE; - else if (strchr(newline, c)) { + else if (strchr(NEWLINE, c)) { state = PRE_KEY; line++; } @@ -698,17 +695,13 @@ static int parse_env_file_push( int parse_env_filev( FILE *f, const char *fname, - const char *newline, va_list ap) { int r, n_pushed = 0; va_list aq; - if (!newline) - newline = NEWLINE; - va_copy(aq, ap); - r = parse_env_file_internal(f, fname, newline, parse_env_file_push, &aq, &n_pushed); + r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed); va_end(aq); if (r < 0) return r; @@ -716,17 +709,16 @@ int parse_env_filev( return n_pushed; } -int parse_env_file( +int parse_env_file_sentinel( FILE *f, const char *fname, - const char *newline, ...) { va_list ap; int r; - va_start(ap, newline); - r = parse_env_filev(f, fname, newline, ap); + va_start(ap, fname); + r = parse_env_filev(f, fname, ap); va_end(ap); return r; @@ -762,14 +754,11 @@ static int load_env_file_push( return 0; } -int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { +int load_env_file(FILE *f, const char *fname, char ***rl) { char **m = NULL; int r; - if (!newline) - newline = NEWLINE; - - r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL); + r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL); if (r < 0) { strv_free(m); return r; @@ -811,14 +800,11 @@ static int load_env_file_push_pairs( return 0; } -int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) { +int load_env_file_pairs(FILE *f, const char *fname, char ***rl) { char **m = NULL; int r; - if (!newline) - newline = NEWLINE; - - r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL); + r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL); if (r < 0) { strv_free(m); return r; @@ -871,7 +857,7 @@ int merge_env_file( * plus "extended" substitutions, unlike other exported parsing functions. */ - return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL); + return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL); } static void write_env_var(FILE *f, const char *v) { diff --git a/src/basic/fileio.h b/src/basic/fileio.h index a9e0c2526f..dae115e3bb 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -44,10 +44,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size); int verify_file(const char *fn, const char *blob, bool accept_extra_nl); -int parse_env_filev(FILE *f, const char *fname, const char *separator, va_list ap); -int parse_env_file(FILE *f, const char *fname, const char *separator, ...) _sentinel_; -int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); -int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); +int parse_env_filev(FILE *f, const char *fname, va_list ap); +int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_; +#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL) +int load_env_file(FILE *f, const char *fname, char ***l); +int load_env_file_pairs(FILE *f, const char *fname, char ***l); int merge_env_file(char ***env, FILE *f, const char *fname); diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 8b89bd0024..9ad51a1972 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -389,6 +389,16 @@ const char *special_glyph(SpecialGlyph code) { return draw_table[is_locale_utf8()][code]; } +void locale_variables_free(char*l[_VARIABLE_LC_MAX]) { + LocaleVariable i; + + if (!l) + return; + + for (i = 0; i < _VARIABLE_LC_MAX; i++) + l[i] = mfree(l[i]); +} + static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { [VARIABLE_LANG] = "LANG", [VARIABLE_LANGUAGE] = "LANGUAGE", diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 7762254940..14beece6d8 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -66,3 +66,8 @@ static inline void freelocalep(locale_t *p) { freelocale(*p); } + +void locale_variables_free(char* l[_VARIABLE_LC_MAX]); +static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) { + locale_variables_free(*l); +} diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 207594cef8..82471a45ba 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -98,7 +98,7 @@ int parse_os_release(const char *root, ...) { return r; va_start(ap, root); - r = parse_env_filev(f, p, NEWLINE, ap); + r = parse_env_filev(f, p, ap); va_end(ap); return r; @@ -113,5 +113,5 @@ int load_os_release_pairs(const char *root, char ***ret) { if (r < 0) return r; - return load_env_file_pairs(f, p, NEWLINE, ret); + return load_env_file_pairs(f, p, ret); } diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 205ea08f6d..1670001364 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -39,42 +39,71 @@ int proc_cmdline(char **ret) { return read_one_line_file("/proc/cmdline", ret); } -int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, void *data, unsigned flags) { - const char *p; +static int proc_cmdline_extract_first(const char **p, char **ret_word, ProcCmdlineFlags flags) { + const char *q = *p; int r; - assert(parse_item); - - p = line; for (;;) { _cleanup_free_ char *word = NULL; - char *value, *key, *q; + const char *c; - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + r = extract_first_word(&q, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) break; - key = word; - /* Filter out arguments that are intended only for the initrd */ - q = startswith(word, "rd."); - if (q) { + c = startswith(word, "rd."); + if (c) { if (!in_initrd()) continue; - if (FLAGS_SET(flags, PROC_CMDLINE_STRIP_RD_PREFIX)) - key = q; + if (FLAGS_SET(flags, PROC_CMDLINE_STRIP_RD_PREFIX)) { + r = free_and_strdup(&word, c); + if (r < 0) + return r; + } } else if (FLAGS_SET(flags, PROC_CMDLINE_RD_STRICT) && in_initrd()) continue; /* And optionally filter out arguments that are intended only for the host */ - value = strchr(key, '='); + *p = q; + *ret_word = TAKE_PTR(word); + return 1; + } + + *p = q; + *ret_word = NULL; + return 0; +} + +int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) { + const char *p; + int r; + + assert(parse_item); + + /* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_parse(), let's make this + * clear. */ + assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL)); + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + char *value; + + r = proc_cmdline_extract_first(&p, &word, flags); + if (r < 0) + return r; + if (r == 0) + break; + + value = strchr(word, '='); if (value) *(value++) = 0; - r = parse_item(key, value, data); + r = parse_item(word, value, data); if (r < 0) return r; } @@ -82,7 +111,7 @@ int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, return 0; } -int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) { +int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) { _cleanup_free_ char *line = NULL; int r; @@ -127,29 +156,29 @@ bool proc_cmdline_key_streq(const char *x, const char *y) { return true; } -int proc_cmdline_get_key(const char *key, unsigned flags, char **value) { +int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) { _cleanup_free_ char *line = NULL, *ret = NULL; bool found = false; const char *p; int r; - /* Looks for a specific key on the kernel command line. Supports two modes: + /* Looks for a specific key on the kernel command line. Supports three modes: * - * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "=" - * is searched, and the value following this is returned in "value". + * a) The "ret_value" parameter is used. In this case a parameter beginning with the "key" string followed by + * "=" is searched for, and the value following it is returned in "ret_value". * - * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a - * separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then - * this is also accepted, and "value" is returned as NULL. + * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a separate + * word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then this is + * also accepted, and "value" is returned as NULL. * - * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed. + * c) The "ret_value" parameter is NULL. In this case a search for the exact "key" parameter is performed. * * In all three cases, > 0 is returned if the key is found, 0 if not. */ if (isempty(key)) return -EINVAL; - if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !value) + if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value) return -EINVAL; r = proc_cmdline(&line); @@ -159,31 +188,17 @@ int proc_cmdline_get_key(const char *key, unsigned flags, char **value) { p = line; for (;;) { _cleanup_free_ char *word = NULL; - const char *e, *k, *q; - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + r = proc_cmdline_extract_first(&p, &word, flags); if (r < 0) return r; if (r == 0) break; - k = word; - - /* Automatically filter out arguments that are intended only for the initrd, if we are not in the - * initrd. */ - q = startswith(word, "rd."); - if (q) { - if (!in_initrd()) - continue; + if (ret_value) { + const char *e; - if (FLAGS_SET(flags, PROC_CMDLINE_STRIP_RD_PREFIX)) - k = q; - - } else if (FLAGS_SET(flags, PROC_CMDLINE_RD_STRICT) && in_initrd()) - continue; - - if (value) { - e = proc_cmdline_key_startswith(k, key); + e = proc_cmdline_key_startswith(word, key); if (!e) continue; @@ -198,13 +213,15 @@ int proc_cmdline_get_key(const char *key, unsigned flags, char **value) { found = true; } else { - if (streq(k, key)) + if (streq(word, key)) { found = true; + break; /* we found what we were looking for */ + } } } - if (value) - *value = TAKE_PTR(ret); + if (ret_value) + *ret_value = TAKE_PTR(ret); return found; } @@ -234,6 +251,62 @@ int proc_cmdline_get_bool(const char *key, bool *ret) { return 1; } +int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) { + _cleanup_free_ char *line = NULL; + const char *p; + va_list ap; + int r, ret = 0; + + /* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_get_key_many(), let's make + * this clear. */ + assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL)); + + /* This call may clobber arguments on failure! */ + + r = proc_cmdline(&line); + if (r < 0) + return r; + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + + r = proc_cmdline_extract_first(&p, &word, flags); + if (r < 0) + return r; + if (r == 0) + break; + + va_start(ap, flags); + + for (;;) { + char **v; + const char *k, *e; + + k = va_arg(ap, const char*); + if (!k) + break; + + assert_se(v = va_arg(ap, char**)); + + e = proc_cmdline_key_startswith(word, k); + if (e && *e == '=') { + r = free_and_strdup(v, e + 1); + if (r < 0) { + va_end(ap); + return r; + } + + ret++; + } + } + + va_end(ap); + } + + return ret; +} + int shall_restore_state(void) { bool ret; int r; diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index efa88df0a0..ff04379fbd 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -5,22 +5,25 @@ #include "log.h" -enum { +typedef enum ProcCmdlineFlags { PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, PROC_CMDLINE_RD_STRICT = 1 << 2, -}; +} ProcCmdlineFlags; typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data); int proc_cmdline(char **ret); -int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, void *data, unsigned flags); -int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, unsigned flags); +int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags); +int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, ProcCmdlineFlags flags); -int proc_cmdline_get_key(const char *parameter, unsigned flags, char **value); +int proc_cmdline_get_key(const char *parameter, ProcCmdlineFlags flags, char **value); int proc_cmdline_get_bool(const char *key, bool *ret); +int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...); +#define proc_cmdline_get_key_many(flags, ...) proc_cmdline_get_key_many_internal(flags, __VA_ARGS__, NULL) + char *proc_cmdline_key_startswith(const char *s, const char *prefix); bool proc_cmdline_key_streq(const char *x, const char *y); diff --git a/src/basic/util.c b/src/basic/util.c index b6e874c3b8..cd75529cfe 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -248,7 +248,9 @@ int container_get_leader(const char *machine, pid_t *pid) { return -EINVAL; p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + r = parse_env_file(NULL, p, + "LEADER", &s, + "CLASS", &class); if (r == -ENOENT) return -EHOSTDOWN; if (r < 0) diff --git a/src/core/execute.c b/src/core/execute.c index 435d94a86d..cf3c055167 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3961,7 +3961,7 @@ static int exec_context_load_environment(const Unit *unit, const ExecContext *c, assert(pglob.gl_pathc > 0); for (n = 0; n < pglob.gl_pathc; n++) { - k = load_env_file(NULL, pglob.gl_pathv[n], NULL, &p); + k = load_env_file(NULL, pglob.gl_pathv[n], &p); if (k < 0) { if (ignore) continue; diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index c14523fee9..fff3a798c4 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -8,42 +8,39 @@ #include "fileio.h" #include "locale-setup.h" #include "locale-util.h" +#include "proc-cmdline.h" #include "string-util.h" #include "strv.h" #include "util.h" #include "virt.h" int locale_setup(char ***environment) { - char **add; - char *variables[_VARIABLE_LC_MAX] = {}; - int r = 0, i; - - if (detect_container() <= 0) { - r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE, - "locale.LANG", &variables[VARIABLE_LANG], - "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], - "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "locale.LC_TIME", &variables[VARIABLE_LC_TIME], - "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], - "locale.LC_NAME", &variables[VARIABLE_LC_NAME], - "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read /proc/cmdline: %m"); - } - - /* Hmm, nothing set on the kernel cmd line? Then let's - * try /etc/locale.conf */ + _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; + _cleanup_strv_free_ char **add = NULL; + LocaleVariable i; + int r; + + r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX, + "locale.LANG", &variables[VARIABLE_LANG], + "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], + "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "locale.LC_TIME", &variables[VARIABLE_LC_TIME], + "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], + "locale.LC_NAME", &variables[VARIABLE_LC_NAME], + "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); + if (r < 0 && r != -ENOENT) + log_warning_errno(r, "Failed to read /proc/cmdline: %m"); + + /* Hmm, nothing set on the kernel cmd line? Then let's try /etc/locale.conf */ if (r <= 0) { - r = parse_env_file(NULL, "/etc/locale.conf", NEWLINE, + r = parse_env_file(NULL, "/etc/locale.conf", "LANG", &variables[VARIABLE_LANG], "LANGUAGE", &variables[VARIABLE_LANGUAGE], "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], @@ -57,14 +54,11 @@ int locale_setup(char ***environment) { "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - + "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read /etc/locale.conf: %m"); } - add = NULL; for (i = 0; i < _VARIABLE_LC_MAX; i++) { char *s; @@ -72,36 +66,32 @@ int locale_setup(char ***environment) { continue; s = strjoin(locale_variable_to_string(i), "=", variables[i]); - if (!s) { - r = -ENOMEM; - goto finish; - } + if (!s) + return -ENOMEM; - if (strv_consume(&add, s) < 0) { - r = -ENOMEM; - goto finish; - } + if (strv_consume(&add, s) < 0) + return -ENOMEM; } - if (!strv_isempty(add)) { - char **e; + if (strv_isempty(add)) { + /* If no locale is configured then default to C.UTF-8. */ - e = strv_env_merge(2, *environment, add); - if (!e) { - r = -ENOMEM; - goto finish; - } - - strv_free_and_replace(*environment, e); + add = strv_new("LANG=C.UTF-8"); + if (!add) + return -ENOMEM; } - r = 0; + if (strv_isempty(*environment)) + strv_free_and_replace(*environment, add); + else { + char **merged; -finish: - strv_free(add); + merged = strv_env_merge(2, *environment, add); + if (!merged) + return -ENOMEM; - for (i = 0; i < _VARIABLE_LC_MAX; i++) - free(variables[i]); + strv_free_and_replace(*environment, merged); + } - return r; + return 0; } diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a0535070b3..4cbf2bde8b 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -89,13 +89,12 @@ static int context_read_data(Context *c) { if (r < 0 && r != -ENOENT) return r; - r = parse_env_file(NULL, "/etc/machine-info", NEWLINE, + r = parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], "ICON_NAME", &c->data[PROP_ICON_NAME], "CHASSIS", &c->data[PROP_CHASSIS], "DEPLOYMENT", &c->data[PROP_DEPLOYMENT], - "LOCATION", &c->data[PROP_LOCATION], - NULL); + "LOCATION", &c->data[PROP_LOCATION]); if (r < 0 && r != -ENOENT) return r; @@ -314,7 +313,7 @@ static int context_write_data_machine_info(Context *c) { assert(c); - r = load_env_file(NULL, "/etc/machine-info", NULL, &l); + r = load_env_file(NULL, "/etc/machine-info", &l); if (r < 0 && r != -ENOENT) return r; diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 88fc51ec26..b91d520cf0 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -149,10 +149,7 @@ static int load_cursor_state(Uploader *u) { if (!u->state_file) return 0; - r = parse_env_file(NULL, u->state_file, NEWLINE, - "LAST_CURSOR", &u->last_cursor, - NULL); - + r = parse_env_file(NULL, u->state_file, "LAST_CURSOR", &u->last_cursor); if (r == -ENOENT) log_debug("State file %s is not present.", u->state_file); else if (r < 0) diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 9ddcbb9d9d..81aa7bd99f 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -651,7 +651,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { return log_oom(); } - r = parse_env_file(NULL, stream->state_file, NEWLINE, + r = parse_env_file(NULL, stream->state_file, "PRIORITY", &priority, "LEVEL_PREFIX", &level_prefix, "FORWARD_TO_SYSLOG", &forward_to_syslog, @@ -659,8 +659,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { "FORWARD_TO_CONSOLE", &forward_to_console, "IDENTIFIER", &stream->identifier, "UNIT", &stream->unit_id, - "STREAM_ID", &stream_id, - NULL); + "STREAM_ID", &stream_id); if (r < 0) return log_error_errno(r, "Failed to read: %s", stream->state_file); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index b54e8020f1..1edabbde72 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1888,7 +1888,9 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in assert_return(machine_name_is_valid(machine), -EINVAL); p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL); + r = parse_env_file(NULL, p, + "ROOT", &root, + "CLASS", &class); if (r == -ENOENT) return -EHOSTDOWN; if (r < 0) diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 863818d6da..a90c01d7db 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -1016,7 +1016,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (r < 0) return r; - r = parse_env_file(NULL, lease_file, NEWLINE, + r = parse_env_file(NULL, lease_file, "ADDRESS", &address, "ROUTER", &router, "NETMASK", &netmask, @@ -1067,8 +1067,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "OPTION_251", &options[27], "OPTION_252", &options[28], "OPTION_253", &options[29], - "OPTION_254", &options[30], - NULL); + "OPTION_254", &options[30]); if (r < 0) return r; diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 5940eccead..e048d2ce18 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -258,8 +258,7 @@ static int file_of_uid(uid_t uid, char **p) { } _public_ int sd_uid_get_state(uid_t uid, char**state) { - _cleanup_free_ char *p = NULL; - char *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; int r; assert_return(state, -EINVAL); @@ -268,24 +267,17 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL); + r = parse_env_file(NULL, p, "STATE", &s); if (r == -ENOENT) { - free(s); - s = strdup("offline"); - if (!s) - return -ENOMEM; - - } - else if (r < 0) { - free(s); + r = free_and_strdup(&s, "offline"); + if (r < 0) + return r; + } else if (r < 0) return r; - } - if (isempty(s)) { - free(s); + else if (isempty(s)) return -EIO; - } - *state = s; + *state = TAKE_PTR(s); return 0; } @@ -299,7 +291,7 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "DISPLAY", &s, NULL); + r = parse_env_file(NULL, p, "DISPLAY", &s); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -354,7 +346,7 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) variable = require_active ? "ACTIVE_UID" : "UIDS"; - r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL); + r = parse_env_file(NULL, p, variable, &s); if (r == -ENOENT) return 0; if (r < 0) @@ -383,7 +375,7 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL); + r = parse_env_file(NULL, p, variable, &s); if (r == -ENOENT || (r >= 0 && isempty(s))) { if (array) *array = NULL; @@ -461,7 +453,7 @@ _public_ int sd_session_is_active(const char *session) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "ACTIVE", &s, NULL); + r = parse_env_file(NULL, p, "ACTIVE", &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -480,7 +472,7 @@ _public_ int sd_session_is_remote(const char *session) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "REMOTE", &s, NULL); + r = parse_env_file(NULL, p, "REMOTE", &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -501,7 +493,7 @@ _public_ int sd_session_get_state(const char *session, char **state) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL); + r = parse_env_file(NULL, p, "STATE", &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -524,7 +516,7 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, "UID", &s, NULL); + r = parse_env_file(NULL, p, "UID", &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -546,7 +538,7 @@ static int session_get_string(const char *session, const char *field, char **val if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, field, &s, NULL); + r = parse_env_file(NULL, p, field, &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -638,10 +630,9 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, + r = parse_env_file(NULL, p, "ACTIVE", &s, - "ACTIVE_UID", &t, - NULL); + "ACTIVE_UID", &t); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -676,10 +667,9 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, + r = parse_env_file(NULL, p, "SESSIONS", &s, - "UIDS", &t, - NULL); + "UIDS", &t); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -745,9 +735,8 @@ static int seat_get_can(const char *seat, const char *variable) { if (r < 0) return r; - r = parse_env_file(NULL, p, NEWLINE, - variable, &s, - NULL); + r = parse_env_file(NULL, p, + variable, &s); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -901,7 +890,7 @@ _public_ int sd_machine_get_class(const char *machine, char **class) { return -EINVAL; p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, p, NEWLINE, "CLASS", &c, NULL); + r = parse_env_file(NULL, p, "CLASS", &c); if (r == -ENOENT) return -ENXIO; if (r < 0) @@ -925,7 +914,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) { assert_return(ifindices, -EINVAL); p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, p, NEWLINE, "NETIF", &netif, NULL); + r = parse_env_file(NULL, p, "NETIF", &netif); if (r == -ENOENT) return -ENXIO; if (r < 0) diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 3b8ce935b0..fc66d41b63 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -24,7 +24,7 @@ _public_ int sd_network_get_operational_state(char **state) { assert_return(state, -EINVAL); - r = parse_env_file(NULL, "/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL); + r = parse_env_file(NULL, "/run/systemd/netif/state", "OPER_STATE", &s); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -44,7 +44,7 @@ static int network_get_strv(const char *key, char ***ret) { assert_return(ret, -EINVAL); - r = parse_env_file(NULL, "/run/systemd/netif/state", NEWLINE, key, &s, NULL); + r = parse_env_file(NULL, "/run/systemd/netif/state", key, &s); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -92,7 +92,7 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) { xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(NULL, path, NEWLINE, field, &s, NULL); + r = parse_env_file(NULL, path, field, &s); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -115,7 +115,7 @@ static int network_link_get_strv(int ifindex, const char *key, char ***ret) { assert_return(ret, -EINVAL); xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(NULL, path, NEWLINE, key, &s, NULL); + r = parse_env_file(NULL, path, key, &s); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -216,7 +216,7 @@ static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { assert_return(ret, -EINVAL); xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(NULL, path, NEWLINE, key, &s, NULL); + r = parse_env_file(NULL, path, key, &s); if (r == -ENOENT) return -ENODATA; if (r < 0) diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index 69fcb3543c..18668a99ab 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -114,7 +114,7 @@ int locale_read_data(Context *c, sd_bus_message *m) { c->locale_mtime = t; context_free_locale(c); - r = parse_env_file(NULL, "/etc/locale.conf", NEWLINE, + r = parse_env_file(NULL, "/etc/locale.conf", "LANG", &c->locale[VARIABLE_LANG], "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], @@ -128,8 +128,7 @@ int locale_read_data(Context *c, sd_bus_message *m) { "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], - NULL); + "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]); if (r < 0) return r; } else { @@ -186,10 +185,9 @@ int vconsole_read_data(Context *c, sd_bus_message *m) { c->vc_mtime = t; context_free_vconsole(c); - r = parse_env_file(NULL, "/etc/vconsole.conf", NEWLINE, + r = parse_env_file(NULL, "/etc/vconsole.conf", "KEYMAP", &c->vc_keymap, - "KEYMAP_TOGGLE", &c->vc_keymap_toggle, - NULL); + "KEYMAP_TOGGLE", &c->vc_keymap_toggle); if (r < 0) return r; @@ -341,7 +339,7 @@ int vconsole_write_data(Context *c) { struct stat st; int r; - r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); + r = load_env_file(NULL, "/etc/vconsole.conf", &l); if (r < 0 && r != -ENOENT) return r; diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 44e3f13db8..8417ff6496 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -16,6 +16,7 @@ #include "fileio.h" #include "locale-util.h" #include "pager.h" +#include "proc-cmdline.h" #include "set.h" #include "spawn-polkit-agent.h" #include "strv.h" @@ -48,34 +49,33 @@ static void status_info_clear(StatusInfo *info) { } static void print_overridden_variables(void) { - int r; - char *variables[_VARIABLE_LC_MAX] = {}; - LocaleVariable j; + _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; bool print_warning = true; + LocaleVariable j; + int r; - if (detect_container() > 0 || arg_host) + if (arg_transport != BUS_TRANSPORT_LOCAL) return; - r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE, - "locale.LANG", &variables[VARIABLE_LANG], - "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], - "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "locale.LC_TIME", &variables[VARIABLE_LC_TIME], - "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], - "locale.LC_NAME", &variables[VARIABLE_LC_NAME], - "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - + r = proc_cmdline_get_key_many( + PROC_CMDLINE_STRIP_RD_PREFIX, + "locale.LANG", &variables[VARIABLE_LANG], + "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], + "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "locale.LC_TIME", &variables[VARIABLE_LC_TIME], + "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], + "locale.LC_NAME", &variables[VARIABLE_LC_NAME], + "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]); if (r < 0 && r != -ENOENT) { log_warning_errno(r, "Failed to read /proc/cmdline: %m"); - goto finish; + return; } for (j = 0; j < _VARIABLE_LC_MAX; j++) @@ -88,9 +88,6 @@ static void print_overridden_variables(void) { } else log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); } - finish: - for (j = 0; j < _VARIABLE_LC_MAX; j++) - free(variables[j]); } static void print_status_info(StatusInfo *i) { diff --git a/src/locale/localed.c b/src/locale/localed.c index c949fa3831..21d1ded65c 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -33,18 +33,19 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_strv_free_ char **l_set = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; - unsigned c_set, c_unset, p; + size_t c_set, c_unset; + LocaleVariable p; int r; assert(bus); l_unset = new0(char*, _VARIABLE_LC_MAX); if (!l_unset) - return -ENOMEM; + return log_oom(); l_set = new0(char*, _VARIABLE_LC_MAX); if (!l_set) - return -ENOMEM; + return log_oom(); for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) { const char *name; @@ -57,8 +58,9 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { else { char *s; - if (asprintf(&s, "%s=%s", name, c->locale[p]) < 0) - return -ENOMEM; + s = strjoin(name, "=", c->locale[p]); + if (!s) + return log_oom(); l_set[c_unset++] = s; } @@ -71,19 +73,19 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment"); if (r < 0) - return r; + return bus_log_create_error(r); r = sd_bus_message_append_strv(m, l_unset); if (r < 0) - return r; + return bus_log_create_error(r); r = sd_bus_message_append_strv(m, l_set); if (r < 0) - return r; + return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) - log_error_errno(r, "Failed to update the manager environment, ignoring: %m"); + return log_error_errno(r, "Failed to update the manager environment: %s", bus_error_message(&error, r)); return 0; } @@ -104,7 +106,7 @@ static int vconsole_reload(sd_bus *bus) { "ss", "systemd-vconsole-setup.service", "replace"); if (r < 0) - return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, -r)); + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); return 0; } @@ -253,20 +255,13 @@ static int property_get_xkb( return -EINVAL; } -static void locale_free(char ***l) { - int p; - - for (p = 0; p < _VARIABLE_LC_MAX; p++) - (*l)[p] = mfree((*l)[p]); -} - static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) { - Context *c = userdata; + _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {}; _cleanup_strv_free_ char **settings = NULL, **l = NULL; - char *new_locale[_VARIABLE_LC_MAX] = {}, **i; - _cleanup_(locale_free) _unused_ char **dummy = new_locale; + Context *c = userdata; bool modified = false; int interactive, p, r; + char **i; assert(m); assert(c); @@ -458,9 +453,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro log_info("Changed virtual console keymap to '%s' toggle '%s'", strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); - r = vconsole_reload(sd_bus_message_get_bus(m)); - if (r < 0) - log_error_errno(r, "Failed to request keymap reload: %m"); + (void) vconsole_reload(sd_bus_message_get_bus(m)); (void) sd_bus_emit_properties_changed( sd_bus_message_get_bus(m), diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index b1f45baaca..71eea72da5 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -193,15 +193,14 @@ int inhibitor_load(Inhibitor *i) { char *cc; int r; - r = parse_env_file(NULL, i->state_file, NEWLINE, + r = parse_env_file(NULL, i->state_file, "WHAT", &what, "UID", &uid, "PID", &pid, "WHO", &who, "WHY", &why, "MODE", &mode, - "FIFO", &i->fifo_path, - NULL); + "FIFO", &i->fifo_path); if (r < 0) return r; diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 197154a897..90af6bf070 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -406,7 +406,7 @@ int session_load(Session *s) { assert(s); - r = parse_env_file(NULL, s->state_file, NEWLINE, + r = parse_env_file(NULL, s->state_file, "REMOTE", &remote, "SCOPE", &s->scope, "SCOPE_JOB", &s->scope_job, @@ -431,8 +431,7 @@ int session_load(Session *s) { "CONTROLLER", &controller, "ACTIVE", &active, "DEVICES", &devices, - "IS_DISPLAY", &is_display, - NULL); + "IS_DISPLAY", &is_display); if (r < 0) return log_error_errno(r, "Failed to read %s: %m", s->state_file); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 0f4c5ccadb..8d82944618 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -312,13 +312,12 @@ int user_load(User *u) { assert(u); - r = parse_env_file(NULL, u->state_file, NEWLINE, + r = parse_env_file(NULL, u->state_file, "SERVICE_JOB", &u->service_job, "STOPPING", &stopping, "REALTIME", &realtime, "MONOTONIC", &monotonic, - "LAST_SESSION_TIMESTAMP", &last_session_timestamp, - NULL); + "LAST_SESSION_TIMESTAMP", &last_session_timestamp); if (r == -ENOENT) return 0; if (r < 0) diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 2f9f587973..c921974cbe 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -373,7 +373,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s pair[0] = -1; - r = load_env_file_pairs(f, "/etc/os-release", NULL, &l); + r = load_env_file_pairs(f, "/etc/os-release", &l); if (r < 0) return r; diff --git a/src/machine/machine.c b/src/machine/machine.c index d5e0d4953f..e114541b3f 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -251,7 +251,7 @@ int machine_load(Machine *m) { if (!m->state_file) return 0; - r = parse_env_file(NULL, m->state_file, NEWLINE, + r = parse_env_file(NULL, m->state_file, "SCOPE", &m->unit, "SCOPE_JOB", &m->scope_job, "SERVICE", &m->service, @@ -261,8 +261,7 @@ int machine_load(Machine *m) { "CLASS", &class, "REALTIME", &realtime, "MONOTONIC", &monotonic, - "NETIF", &netif, - NULL); + "NETIF", &netif); if (r < 0) { if (r == -ENOENT) return 0; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1ccaf0e15b..4af1a559b2 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -3210,13 +3210,12 @@ static int link_load(Link *link) { assert(link); - r = parse_env_file(NULL, link->state_file, NEWLINE, + r = parse_env_file(NULL, link->state_file, "NETWORK_FILE", &network_file, "ADDRESSES", &addresses, "ROUTES", &routes, "DHCP4_ADDRESS", &dhcp4_address, - "IPV4LL_ADDRESS", &ipv4ll_address, - NULL); + "IPV4LL_ADDRESS", &ipv4ll_address); if (r < 0 && r != -ENOENT) return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file); diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 51fadc8125..de39568eca 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -244,7 +244,7 @@ static int link_send_lldp(Link *link) { return r; (void) gethostname_strict(&hostname); - (void) parse_env_file(NULL, "/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL); + (void) parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &pretty_hostname); assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC); ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC); diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index ff402151e9..341fd14dc2 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -279,10 +279,9 @@ static int inspect_image(int argc, char *argv[], void *userdata) { if (!f) return log_error_errno(errno, "Failed to open /etc/os-release buffer: %m"); - r = parse_env_file(f, "/etc/os-release", NEWLINE, + r = parse_env_file(f, "/etc/os-release", "PORTABLE_PRETTY_NAME", &pretty_portable, - "PRETTY_NAME", &pretty_os, - NULL); + "PRETTY_NAME", &pretty_os); if (r < 0) return log_error_errno(r, "Failed to parse /etc/os-release: %m"); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index ff2be12415..0ae3b40018 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -1257,14 +1257,13 @@ int link_load_user(Link *l) { if (l->is_managed) return 0; /* if the device is managed, then networkd is our configuration source, not the bus API */ - r = parse_env_file(NULL, l->state_file, NEWLINE, + r = parse_env_file(NULL, l->state_file, "LLMNR", &llmnr, "MDNS", &mdns, "DNSSEC", &dnssec, "SERVERS", &servers, "DOMAINS", &domains, - "NTAS", &ntas, - NULL); + "NTAS", &ntas); if (r == -ENOENT) return 0; if (r < 0) diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 801cf133f9..36a611c3c1 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -339,7 +339,7 @@ int show_cgroup_get_path_and_warn( const char *m; m = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, m, NEWLINE, "SCOPE", &unit, NULL); + r = parse_env_file(NULL, m, "SCOPE", &unit); if (r < 0) return log_error_errno(r, "Failed to load machine data: %m"); diff --git a/src/shared/condition.c b/src/shared/condition.c index 2acf36d468..ecc32beadf 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -471,7 +471,7 @@ static int condition_test_needs_update(Condition *c) { uint64_t timestamp; int r; - r = parse_env_file(NULL, p, NULL, "TIMESTAMP_NSEC", ×tamp_str, NULL); + r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str); if (r < 0) { log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); return true; diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index c6b7a02ad9..ec3e1a10bb 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -1333,14 +1333,14 @@ int dissected_image_acquire_metadata(DissectedImage *m) { } case META_MACHINE_INFO: - r = load_env_file_pairs(f, "machine-info", NULL, &machine_info); + r = load_env_file_pairs(f, "machine-info", &machine_info); if (r < 0) log_debug_errno(r, "Failed to read /etc/machine-info: %m"); break; case META_OS_RELEASE: - r = load_env_file_pairs(f, "os-release", NULL, &os_release); + r = load_env_file_pairs(f, "os-release", &os_release); if (r < 0) log_debug_errno(r, "Failed to read OS release file: %m"); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 0344771a60..d5f6ab8529 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -1114,7 +1114,7 @@ int image_read_metadata(Image *i) { if (r < 0 && r != -ENOENT) log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name); else if (r >= 0) { - r = load_env_file_pairs(NULL, path, NULL, &machine_info); + r = load_env_file_pairs(NULL, path, &machine_info); if (r < 0) log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name); } diff --git a/src/shared/tests.c b/src/shared/tests.c index d21bd22b40..bab39685ff 100644 --- a/src/shared/tests.c +++ b/src/shared/tests.c @@ -47,7 +47,7 @@ static void load_testdata_env(void) { dirname(s); envpath = path_join(NULL, s, "systemd-runtest.env"); - if (load_env_file_pairs(NULL, envpath, NULL, &pairs) < 0) + if (load_env_file_pairs(NULL, envpath, &pairs) < 0) return; STRV_FOREACH_PAIR(k, v, pairs) diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 959217c511..e0c198eb6a 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -29,12 +29,11 @@ int udev_parse_config_full( _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL, *resolve_names = NULL; int r; - r = parse_env_file(NULL, "/etc/udev/udev.conf", NEWLINE, + r = parse_env_file(NULL, "/etc/udev/udev.conf", "udev_log", &log_val, "children_max", &children_max, "exec_delay", &exec_delay, - "event_timeout", &event_timeout, - NULL); + "event_timeout", &event_timeout); if (r == -ENOENT) return 0; if (r < 0) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a18fb598fd..304dd1bbfb 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -56,6 +56,7 @@ #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" +#include "proc-cmdline.h" #include "process-util.h" #include "reboot-util.h" #include "rlimit-util.h" @@ -5700,9 +5701,7 @@ static int switch_root(int argc, char *argv[], void *userdata) { if (argc >= 3) init = argv[2]; else { - r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE, - "init", &cmdline_init, - NULL); + r = proc_cmdline_get_key("init", 0, &cmdline_init); if (r < 0) log_debug_errno(r, "Failed to parse /proc/cmdline: %m"); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index cabaef6ab8..ac86d6d588 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -55,7 +55,7 @@ static void test_parse_env_file(void) { fflush(f); fclose(f); - r = load_env_file(NULL, t, NULL, &a); + r = load_env_file(NULL, t, &a); assert_se(r >= 0); STRV_FOREACH(i, a) @@ -82,7 +82,7 @@ static void test_parse_env_file(void) { } r = parse_env_file( - NULL, t, NULL, + NULL, t, "one", &one, "two", &two, "three", &three, @@ -92,8 +92,7 @@ static void test_parse_env_file(void) { "seven", &seven, "eight", &eight, "export nine", &nine, - "ten", &ten, - NULL); + "ten", &ten); assert_se(r >= 0); @@ -128,7 +127,7 @@ static void test_parse_env_file(void) { r = write_env_file(p, a); assert_se(r >= 0); - r = load_env_file(NULL, p, NULL, &b); + r = load_env_file(NULL, p, &b); assert_se(r >= 0); } @@ -157,7 +156,7 @@ static void test_parse_multiline_env_file(void) { fflush(f); fclose(f); - r = load_env_file(NULL, t, NULL, &a); + r = load_env_file(NULL, t, &a); assert_se(r >= 0); STRV_FOREACH(i, a) @@ -176,7 +175,7 @@ static void test_parse_multiline_env_file(void) { r = write_env_file(p, a); assert_se(r >= 0); - r = load_env_file(NULL, p, NULL, &b); + r = load_env_file(NULL, p, &b); assert_se(r >= 0); } @@ -467,7 +466,7 @@ static void test_load_env_file_pairs(void) { f = fdopen(fd, "r"); assert_se(f); - r = load_env_file_pairs(f, fn, NULL, &l); + r = load_env_file_pairs(f, fn, &l); assert_se(r >= 0); assert_se(strv_length(l) == 14); diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 1b6724755f..00cc2f48aa 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -28,15 +28,22 @@ static void test_proc_cmdline_parse(void) { static void test_proc_cmdline_override(void) { log_info("/* %s */", __func__); - assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm") == 0); + 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); /* Test if the override works */ _cleanup_free_ char *line = NULL, *value = NULL; assert_se(proc_cmdline(&line) >= 0); /* Test if parsing makes uses of the override */ - assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm")); + assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"")); assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("some_arg_with_space", 0, &value) > 0 && streq_ptr(value, "foo bar")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("and_one_more", 0, &value) > 0 && streq_ptr(value, "zzz aaa")); + value = mfree(value); } static int parse_item_given(const char *key, const char *value, void *data) { @@ -50,6 +57,10 @@ static int parse_item_given(const char *key, const char *value, void *data) { assert_se(streq(value, "quux")); else if (streq(key, "wuff-piep")) assert_se(streq(value, "tuet ")); + else if (streq(key, "space")) + assert_se(streq(value, "x y z")); + else if (streq(key, "miepf")) + assert_se(streq(value, "uuu")); else if (in_initrd() && *strip && streq(key, "zumm")) assert_se(!value); else if (in_initrd() && !*strip && streq(key, "rd.zumm")) @@ -67,13 +78,12 @@ static void test_proc_cmdline_given(bool flip_initrd) { in_initrd_force(!in_initrd()); bool t = true, f = false; - assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm", + assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm space='x y z' miepf=\"uuu\"", parse_item_given, &t, PROC_CMDLINE_STRIP_RD_PREFIX) >= 0); - assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm", + assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm space='x y z' miepf=\"uuu\"", parse_item_given, &f, 0) >= 0); - if (flip_initrd) in_initrd_force(!in_initrd()); } @@ -82,7 +92,7 @@ static void test_proc_cmdline_get_key(void) { _cleanup_free_ char *value = NULL; log_info("/* %s */", __func__); - assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm") == 0); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm spaaace='ö ü ß' ticks=\"''\"") == 0); assert_se(proc_cmdline_get_key("", 0, &value) == -EINVAL); assert_se(proc_cmdline_get_key("abc", 0, NULL) == 0); @@ -114,6 +124,11 @@ static void test_proc_cmdline_get_key(void) { assert_se(proc_cmdline_get_key("zumm", 0, &value) == 0 && value == NULL); assert_se(proc_cmdline_get_key("zumm", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && value == NULL); assert_se(proc_cmdline_get_key("zumm", 0, NULL) > 0); + + assert_se(proc_cmdline_get_key("spaaace", 0, &value) > 0 && streq_ptr(value, "ö ü ß")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("ticks", 0, &value) > 0 && streq_ptr(value, "''")); } static void test_proc_cmdline_get_bool(void) { @@ -135,6 +150,28 @@ static void test_proc_cmdline_get_bool(void) { assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false); } +static void test_proc_cmdline_get_key_many(void) { + _cleanup_free_ char *value1 = NULL, *value2 = NULL, *value3 = NULL, *value4 = NULL, *value5 = NULL, *value6 = NULL; + + log_info("/* %s */", __func__); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm SPACE='one two' doubleticks=\" aaa aaa \"") == 0); + + assert_se(proc_cmdline_get_key_many(0, + "wuff-piep", &value3, + "foo_bar", &value1, + "idontexist", &value2, + "zumm", &value4, + "SPACE", &value5, + "doubleticks", &value6) == 4); + + assert_se(streq_ptr(value1, "quux")); + assert_se(!value2); + assert_se(streq_ptr(value3, "tuet")); + assert_se(!value4); + assert_se(streq_ptr(value5, "one two")); + assert_se(streq_ptr(value6, " aaa aaa ")); +} + static void test_proc_cmdline_key_streq(void) { log_info("/* %s */", __func__); @@ -199,6 +236,7 @@ int main(void) { test_proc_cmdline_key_startswith(); test_proc_cmdline_get_key(); test_proc_cmdline_get_bool(); + test_proc_cmdline_get_key_many(); test_runlevel_to_target(); return 0; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index fe6da4fe2d..493ca50220 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -531,7 +531,7 @@ static void test_load_env_file_1(void) { assert_se(fd >= 0); assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=a")); assert_se(streq(data[1], "b=bc")); @@ -553,7 +553,7 @@ static void test_load_env_file_2(void) { assert_se(fd >= 0); assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=a")); assert_se(data[1] == NULL); @@ -570,7 +570,7 @@ static void test_load_env_file_3(void) { assert_se(fd >= 0); assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(data == NULL); } @@ -585,7 +585,7 @@ static void test_load_env_file_4(void) { assert_se(fd >= 0); assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); assert_se(streq(data[1], "MODULE_0=coretemp")); @@ -604,7 +604,7 @@ static void test_load_env_file_5(void) { assert_se(fd >= 0); assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=")); assert_se(streq(data[1], "b=")); diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 4c55ed7cb5..41059bae04 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -23,6 +23,7 @@ #include "io-util.h" #include "locale-util.h" #include "log.h" +#include "proc-cmdline.h" #include "process-util.h" #include "signal-util.h" #include "stdio-util.h" @@ -417,32 +418,29 @@ int main(int argc, char **argv) { utf8 = is_locale_utf8(); - r = parse_env_file(NULL, "/etc/vconsole.conf", NEWLINE, + r = parse_env_file(NULL, "/etc/vconsole.conf", "KEYMAP", &vc_keymap, "KEYMAP_TOGGLE", &vc_keymap_toggle, "FONT", &vc_font, "FONT_MAP", &vc_font_map, - "FONT_UNIMAP", &vc_font_unimap, - NULL); + "FONT_UNIMAP", &vc_font_unimap); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read /etc/vconsole.conf: %m"); /* Let the kernel command line override /etc/vconsole.conf */ - if (detect_container() <= 0) { - r = parse_env_file(NULL, "/proc/cmdline", WHITESPACE, - "vconsole.keymap", &vc_keymap, - "vconsole.keymap_toggle", &vc_keymap_toggle, - "vconsole.font", &vc_font, - "vconsole.font_map", &vc_font_map, - "vconsole.font_unimap", &vc_font_unimap, - /* compatibility with obsolete multiple-dot scheme */ - "vconsole.keymap.toggle", &vc_keymap_toggle, - "vconsole.font.map", &vc_font_map, - "vconsole.font.unimap", &vc_font_unimap, - NULL); - if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read /proc/cmdline: %m"); - } + r = proc_cmdline_get_key_many( + PROC_CMDLINE_STRIP_RD_PREFIX, + "vconsole.keymap", &vc_keymap, + "vconsole.keymap_toggle", &vc_keymap_toggle, + "vconsole.font", &vc_font, + "vconsole.font_map", &vc_font_map, + "vconsole.font_unimap", &vc_font_unimap, + /* compatibility with obsolete multiple-dot scheme */ + "vconsole.keymap.toggle", &vc_keymap_toggle, + "vconsole.font.map", &vc_font_map, + "vconsole.font.unimap", &vc_font_unimap); + if (r < 0 && r != -ENOENT) + log_warning_errno(r, "Failed to read /proc/cmdline: %m"); (void) toggle_utf8_sysfs(utf8); (void) toggle_utf8(vc, fd, utf8); |