summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-11-15 12:47:17 +0100
committerGitHub <noreply@github.com>2018-11-15 12:47:17 +0100
commitcd5a29ce983d0ccfa24b349288146d43b387c885 (patch)
tree749a8230da2674fb2f7778b70c8e0cadf791f969 /src/basic
parent042cad5737917e6964ddddba72b8fcc0cb890877 (diff)
parent483d713e0a39ecfe028ec49b9d9b0e67658ea79f (diff)
downloadsystemd-cd5a29ce983d0ccfa24b349288146d43b387c885.tar.gz
systemd-cd5a29ce983d0ccfa24b349288146d43b387c885.tar.bz2
systemd-cd5a29ce983d0ccfa24b349288146d43b387c885.zip
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
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/exec-util.c2
-rw-r--r--src/basic/fileio.c46
-rw-r--r--src/basic/fileio.h9
-rw-r--r--src/basic/locale-util.c10
-rw-r--r--src/basic/locale-util.h5
-rw-r--r--src/basic/os-util.c4
-rw-r--r--src/basic/proc-cmdline.c165
-rw-r--r--src/basic/proc-cmdline.h13
-rw-r--r--src/basic/util.c4
9 files changed, 169 insertions, 89 deletions
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)