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:
Zbigniew Jędrzejewski-Szmek
2018-11-15 12:47:17 +01:00
committed by GitHub
43 changed files with 404 additions and 329 deletions
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+10
View File
@@ -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",
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+8 -5
View File
@@ -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
View File
@@ -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)