From 565d91fdf198b88f7c2d72c67cfc6c30341a3596 Mon Sep 17 00:00:00 2001 From: Michal Vyskocil Date: Fri, 18 Jan 2013 10:05:10 +0100 Subject: [PATCH] util: continuation support for load_env_file Variable definitions can be written on more than one line - if each ends with a backslash, then is concatenated with a previous one. Only backslash and unix end of line (\n) are treated as a continuation. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=58083 [zj: squashed two patches together; cleaned up grammar; removed comment about ignoring trailing backslash -- it is not ignored.] Document continuation support in systemd.exec --- man/systemd.exec.xml | 8 +++++--- src/shared/util.c | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) Index: systemd-195/man/systemd.exec.xml =================================================================== --- systemd-195.orig/man/systemd.exec.xml +++ systemd-195/man/systemd.exec.xml @@ -282,9 +282,11 @@ contain new-line separated variable assignments. Empty lines and lines starting with ; or # will be ignored, - which may be used for commenting. The - parser strips leading and - trailing whitespace from the values + which may be used for commenting. A line + ending with a backslash will be concatenated + with the following one, allowing multiline variable + definitions. The parser strips leading + and trailing whitespace from the values of assignments, unless you use double quotes ("). The Index: systemd-195/src/shared/util.c =================================================================== --- systemd-195.orig/src/shared/util.c +++ systemd-195/src/shared/util.c @@ -876,69 +876,88 @@ fail: return r; } -int load_env_file( - const char *fname, - char ***rl) { - - FILE *f; - char **m = NULL; - int r; +int load_env_file(const char *fname, char ***rl) { + + _cleanup_fclose_ FILE *f; + _cleanup_strv_free_ char **m = NULL; + _cleanup_free_ char *c = NULL; assert(fname); assert(rl); - if (!(f = fopen(fname, "re"))) + /* This reads an environment file, but will not complain about + * any invalid assignments, that needs to be done by the + * caller */ + + f = fopen(fname, "re"); + if (!f) return -errno; while (!feof(f)) { - char l[LINE_MAX], *p, *u; - char **t; + char l[LINE_MAX], *p, *cs, *b; if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; + if (ferror(f)) + return -errno; + + /* The previous line was a continuation line? + * Let's process it now, before we leave the + * loop */ + if (c) + goto process; - r = -errno; - goto finish; + break; } - p = strstrip(l); + /* Is this a continuation line? If so, just append + * this to c, and go to next line right-away */ + cs = endswith(l, "\\\n"); + if (cs) { + *cs = '\0'; + b = strappend(c, l); + if (!b) + return -ENOMEM; - if (!*p) + free(c); + c = b; continue; + } - if (strchr(COMMENTS, *p)) - continue; + /* If the previous line was a continuation line, + * append the current line to it */ + if (c) { + b = strappend(c, l); + if (!b) + return -ENOMEM; - if (!(u = normalize_env_assignment(p))) { - r = log_oom(); - goto finish; + free(c); + c = b; } - t = strv_append(m, u); - free(u); + process: + p = strstrip(c ? c : l); - if (!t) { - r = log_oom(); - goto finish; + if (*p && !strchr(COMMENTS, *p)) { + _cleanup_free_ char *u; + int k; + + u = normalize_env_assignment(p); + if (!u) + return -ENOMEM; + + k = strv_extend(&m, u); + if (k < 0) + return -ENOMEM; } - strv_free(m); - m = t; + free(c); + c = NULL; } - r = 0; - *rl = m; m = NULL; -finish: - if (f) - fclose(f); - - strv_free(m); - - return r; + return 0; } int write_env_file(const char *fname, char **l) { Index: systemd-195/src/shared/strv.c =================================================================== --- systemd-195.orig/src/shared/strv.c +++ systemd-195/src/shared/strv.c @@ -370,6 +370,32 @@ fail: return NULL; } +int strv_extend(char ***l, const char *value) { + char **c; + char *v; + unsigned n; + + if (!value) + return 0; + + v = strdup(value); + if (!v) + return -ENOMEM; + + n = strv_length(*l); + c = realloc(*l, sizeof(char*) * (n + 2)); + if (!c) { + free(v); + return -ENOMEM; + } + + c[n] = v; + c[n+1] = NULL; + + *l = c; + return 0; +} + char **strv_uniq(char **l) { char **i; Index: systemd-195/src/shared/strv.h =================================================================== --- systemd-195.orig/src/shared/strv.h +++ systemd-195/src/shared/strv.h @@ -37,6 +37,7 @@ unsigned strv_length(char **l); char **strv_merge(char **a, char **b); char **strv_merge_concat(char **a, char **b, const char *suffix); char **strv_append(char **l, const char *s); +int strv_extend(char ***l, const char *value); char **strv_remove(char **l, const char *s); char **strv_remove_prefix(char **l, const char *s);