fileio.c revision f73141d7657b3f60b8669bc8386413d8a8a372c6
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/***
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering This file is part of systemd.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Copyright 2010 Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering (at your option) any later version.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is distributed in the hope that it will be useful, but
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Lesser General Public License for more details.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering***/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include <unistd.h>
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "fileio.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "util.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "strv.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poetteringint write_string_file(const char *fn, const char *line) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(fn);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(line);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering f = fopen(fn, "we");
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!f)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering errno = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (fputs(line, f) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return errno ? -errno : -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!endswith(line, "\n"))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering fputc('\n', f);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering fflush(f);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ferror(f))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return errno ? -errno : -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint write_string_file_atomic(const char *fn, const char *line) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *p = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(fn);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(line);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = fopen_temporary(fn, &f, &p);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering fchmod_umask(fileno(f), 0644);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering errno = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (fputs(line, f) < 0) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto finish;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!endswith(line, "\n"))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering fputc('\n', f);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering fflush(f);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ferror(f))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = errno ? -errno : -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (rename(p, fn) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringfinish:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering unlink(p);
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering return r;
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering}
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poetteringint read_one_line_file(const char *fn, char **line) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char t[LINE_MAX], *c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(fn);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(line);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering f = fopen(fn, "re");
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!f)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!fgets(t, sizeof(t), f)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ferror(f))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return errno ? -errno : -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering t[0] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering c = strdup(t);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!c)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering truncate_nl(c);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *line = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint read_full_file(const char *fn, char **contents, size_t *size) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering size_t n, l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *buf = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering struct stat st;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(fn);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(contents);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering f = fopen(fn, "re");
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!f)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (fstat(fileno(f), &st) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Safety check */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (st.st_size > 4*1024*1024)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -E2BIG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n = st.st_size > 0 ? st.st_size : LINE_MAX;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (;;) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char *t;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering size_t k;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering t = realloc(buf, n+1);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!t)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buf = t;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering k = fread(buf + l, 1, n - l, f);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (k <= 0) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ferror(f))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l += k;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n *= 2;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Safety check */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (n > 4*1024*1024)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -E2BIG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buf[l] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *contents = buf;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buf = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *size = l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmannstatic int parse_env_file_internal(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering const char *fname,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering const char *newline,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int (*push) (const char *key, char *value, void *userdata),
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering void *userdata) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *contents = NULL, *key = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_whitespace = (size_t) -1;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char *p, *value = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering enum {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering PRE_KEY,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering KEY,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering PRE_EQUAL,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering PRE_VALUE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering VALUE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering VALUE_ESCAPE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering SINGLE_QUOTE_VALUE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering SINGLE_QUOTE_VALUE_ESCAPE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering DOUBLE_QUOTE_VALUE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering DOUBLE_QUOTE_VALUE_ESCAPE,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering COMMENT,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering COMMENT_ESCAPE
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } state = PRE_KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(fname);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(newline);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = read_full_file(fname, &contents, NULL);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (p = contents; *p; p++) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char c = *p;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering switch (state) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case PRE_KEY:
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann if (strchr(COMMENTS, c))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = COMMENT;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (!strchr(WHITESPACE, c)) {
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann state = KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering key[n_key++] = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case KEY:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (strchr(newline, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n_key = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else if (strchr(WHITESPACE, c))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_EQUAL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (c == '=')
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann state = PRE_VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering key[n_key++] = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case PRE_EQUAL:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (strchr(newline, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n_key = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else if (c == '=')
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (!strchr(WHITESPACE, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n_key = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = COMMENT;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case PRE_VALUE:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (strchr(newline, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering key[n_key] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (value)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[n_value] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = push(key, value, userdata);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n_key = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value_alloc = n_value = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else if (c == '\'')
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = SINGLE_QUOTE_VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (c == '\"')
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = DOUBLE_QUOTE_VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (c == '\\')
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = VALUE_ESCAPE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (!strchr(WHITESPACE, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[n_value++] = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case VALUE:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (strchr(newline, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_KEY;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering key[n_key] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (value)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[n_value] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Chomp off trailing whitespace */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (last_whitespace != (size_t) -1)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[last_whitespace] = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = push(key, value, userdata);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering n_key = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value_alloc = n_value = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else if (c == '\\') {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = VALUE_ESCAPE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering last_whitespace = (size_t) -1;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!strchr(WHITESPACE, c))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering last_whitespace = (size_t) -1;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (last_whitespace == (size_t) -1)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering last_whitespace = n_value;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[n_value++] = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case VALUE_ESCAPE:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!strchr(newline, c)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Escaped newlines we eat up entirely */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto fail;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering value[n_value++] = c;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering break;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering case SINGLE_QUOTE_VALUE:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (c == '\'')
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering state = PRE_VALUE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else if (c == '\\')
state = SINGLE_QUOTE_VALUE_ESCAPE;
else {
if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
r = -ENOMEM;
goto fail;
}
value[n_value++] = c;
}
break;
case SINGLE_QUOTE_VALUE_ESCAPE:
state = SINGLE_QUOTE_VALUE;
if (!strchr(newline, c)) {
if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
r = -ENOMEM;
goto fail;
}
value[n_value++] = c;
}
break;
case DOUBLE_QUOTE_VALUE:
if (c == '\"')
state = PRE_VALUE;
else if (c == '\\')
state = DOUBLE_QUOTE_VALUE_ESCAPE;
else {
if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
r = -ENOMEM;
goto fail;
}
value[n_value++] = c;
}
break;
case DOUBLE_QUOTE_VALUE_ESCAPE:
state = DOUBLE_QUOTE_VALUE;
if (!strchr(newline, c)) {
if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
r = -ENOMEM;
goto fail;
}
value[n_value++] = c;
}
break;
case COMMENT:
if (c == '\\')
state = COMMENT_ESCAPE;
else if (strchr(newline, c))
state = PRE_KEY;
break;
case COMMENT_ESCAPE:
state = COMMENT;
break;
}
}
if (state == PRE_VALUE ||
state == VALUE ||
state == VALUE_ESCAPE ||
state == SINGLE_QUOTE_VALUE ||
state == SINGLE_QUOTE_VALUE_ESCAPE ||
state == DOUBLE_QUOTE_VALUE ||
state == DOUBLE_QUOTE_VALUE_ESCAPE) {
key[n_key] = 0;
if (value)
value[n_value] = 0;
r = push(key, value, userdata);
if (r < 0)
goto fail;
}
return 0;
fail:
free(value);
return r;
}
static int parse_env_file_push(const char *key, char *value, void *userdata) {
const char *k;
va_list* ap = (va_list*) userdata;
va_list aq;
va_copy(aq, *ap);
while ((k = va_arg(aq, const char *))) {
char **v;
v = va_arg(aq, char **);
if (streq(key, k)) {
va_end(aq);
free(*v);
*v = value;
return 1;
}
}
va_end(aq);
free(value);
return 0;
}
int parse_env_file(
const char *fname,
const char *newline, ...) {
va_list ap;
int r;
if (!newline)
newline = NEWLINE;
va_start(ap, newline);
r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
va_end(ap);
return r;
}
static int load_env_file_push(const char *key, char *value, void *userdata) {
char ***m = userdata;
char *p;
int r;
p = strjoin(key, "=", strempty(value), NULL);
if (!p)
return -ENOMEM;
r = strv_push(m, p);
if (r < 0) {
free(p);
return r;
}
free(value);
return 0;
}
int load_env_file(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);
if (r < 0) {
strv_free(m);
return r;
}
*rl = m;
return 0;
}
int write_env_file(const char *fname, char **l) {
char **i;
char _cleanup_free_ *p = NULL;
FILE _cleanup_fclose_ *f = NULL;
int r;
r = fopen_temporary(fname, &f, &p);
if (r < 0)
return r;
fchmod_umask(fileno(f), 0644);
errno = 0;
STRV_FOREACH(i, l) {
fputs(*i, f);
fputc('\n', f);
}
fflush(f);
if (ferror(f)) {
if (errno > 0)
r = -errno;
else
r = -EIO;
} else {
if (rename(p, fname) < 0)
r = -errno;
else
r = 0;
}
if (r < 0)
unlink(p);
return r;
}