diff options
Diffstat (limited to 'src/shared/fileio.c')
-rw-r--r-- | src/shared/fileio.c | 148 |
1 files changed, 115 insertions, 33 deletions
diff --git a/src/shared/fileio.c b/src/shared/fileio.c index c5806249f6..fb1c1bcf9f 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -27,8 +27,12 @@ #include "utf8.h" #include "ctype.h" -int write_string_to_file(FILE *f, const char *line) { +int write_string_stream(FILE *f, const char *line) { + assert(f); + assert(line); + errno = 0; + fputs(line, f); if (!endswith(line, "\n")) fputc('\n', f); @@ -51,7 +55,7 @@ int write_string_file(const char *fn, const char *line) { if (!f) return -errno; - return write_string_to_file(f, line); + return write_string_stream(f, line); } int write_string_file_atomic(const char *fn, const char *line) { @@ -189,29 +193,33 @@ ssize_t sendfile_full(int out_fd, const char *fn) { return (ssize_t) l; } -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; +int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; - assert(fn); + assert(f); assert(contents); - f = fopen(fn, "re"); - if (!f) - return -errno; - if (fstat(fileno(f), &st) < 0) return -errno; - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; + n = LINE_MAX; - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; + if (S_ISREG(st.st_mode)) { + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + /* Start with the right file size, but be prepared for + * files from /proc which generally report a file size + * of 0 */ + if (st.st_size > 0) + n = st.st_size; + } + l = 0; for (;;) { char *t; size_t k; @@ -248,7 +256,21 @@ int read_full_file(const char *fn, char **contents, size_t *size) { return 0; } +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + return read_full_stream(f, contents, size); +} + static int parse_env_file_internal( + FILE *f, const char *fname, const char *newline, int (*push) (const char *filename, unsigned line, @@ -275,10 +297,12 @@ static int parse_env_file_internal( COMMENT_ESCAPE } state = PRE_KEY; - assert(fname); assert(newline); - r = read_full_file(fname, &contents, NULL); + if (f) + r = read_full_stream(f, &contents, NULL); + else + r = read_full_file(fname, &contents, NULL); if (r < 0) return r; @@ -532,25 +556,27 @@ fail: return r; } -static int parse_env_file_push(const char *filename, unsigned line, - const char *key, char *value, void *userdata) { +static int parse_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata) { const char *k; va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { - _cleanup_free_ char *p = utf8_escape_invalid(key); + _cleanup_free_ char *p; - log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", - filename, line, p); + p = utf8_escape_invalid(key); + log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); return -EINVAL; } if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *p = utf8_escape_invalid(value); + _cleanup_free_ char *p; - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", - filename, line, key, p); + p = utf8_escape_invalid(value); + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); return -EINVAL; } @@ -571,6 +597,7 @@ static int parse_env_file_push(const char *filename, unsigned line, va_end(aq); free(value); + return 0; } @@ -585,14 +612,16 @@ int parse_env_file( newline = NEWLINE; va_start(ap, newline); - r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap); + r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap); va_end(ap); return r; } -static int load_env_file_push(const char *filename, unsigned line, - const char *key, char *value, void *userdata) { +static int load_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata) { char ***m = userdata; char *p; int r; @@ -600,16 +629,14 @@ static int load_env_file_push(const char *filename, unsigned line, if (!utf8_is_valid(key)) { _cleanup_free_ char *t = utf8_escape_invalid(key); - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", - filename, line, t); + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); return -EINVAL; } if (value && !utf8_is_valid(value)) { _cleanup_free_ char *t = utf8_escape_invalid(value); - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", - filename, line, key, t); + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); return -EINVAL; } @@ -625,14 +652,69 @@ static int load_env_file_push(const char *filename, unsigned line, return 0; } -int load_env_file(const char *fname, const char *newline, char ***rl) { +int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { + char **m = NULL; + int r; + + if (!newline) + newline = NEWLINE; + + r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m); + if (r < 0) { + strv_free(m); + return r; + } + + *rl = m; + return 0; +} + +static int load_env_file_push_pairs( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata) { + char ***m = userdata; + int r; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *t = utf8_escape_invalid(key); + + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *t = utf8_escape_invalid(value); + + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); + return -EINVAL; + } + + r = strv_extend(m, key); + if (r < 0) + return -ENOMEM; + + if (!value) { + r = strv_extend(m, ""); + if (r < 0) + return -ENOMEM; + } else { + r = strv_push(m, value); + if (r < 0) + return r; + } + + return 0; +} + +int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) { char **m = NULL; int r; if (!newline) newline = NEWLINE; - r = parse_env_file_internal(fname, newline, load_env_file_push, &m); + r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m); if (r < 0) { strv_free(m); return r; |