Merge pull request #10742 from poettering/c-utf8
default to C.UTF-8 locale, and many improvements to env var file parsing/kernel cmdline parsing
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
+16
-30
@@ -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) {
|
||||
|
||||
+5
-4
@@ -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);
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
+119
-46
@@ -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;
|
||||
if (ret_value) {
|
||||
const char *e;
|
||||
|
||||
/* 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 (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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+3
-1
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user