1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 int write_string_file(const char *fn, const char *line) {
28 _cleanup_fclose_ FILE *f = NULL;
39 if (!endswith(line, "\n"))
45 return errno ? -errno : -EIO;
50 int write_string_file_atomic(const char *fn, const char *line) {
51 _cleanup_fclose_ FILE *f = NULL;
52 _cleanup_free_ char *p = NULL;
58 r = fopen_temporary(fn, &f, &p);
62 fchmod_umask(fileno(f), 0644);
66 if (!endswith(line, "\n"))
72 r = errno ? -errno : -EIO;
74 if (rename(p, fn) < 0)
86 int read_one_line_file(const char *fn, char **line) {
87 _cleanup_fclose_ FILE *f = NULL;
97 if (!fgets(t, sizeof(t), f)) {
100 return errno ? -errno : -EIO;
114 int read_full_file(const char *fn, char **contents, size_t *size) {
115 _cleanup_fclose_ FILE *f = NULL;
117 _cleanup_free_ char *buf = NULL;
127 if (fstat(fileno(f), &st) < 0)
131 if (st.st_size > 4*1024*1024)
134 n = st.st_size > 0 ? st.st_size : LINE_MAX;
141 t = realloc(buf, n+1);
146 k = fread(buf + l, 1, n - l, f);
173 static int parse_env_file_internal(
176 int (*push) (const char *key, char *value, void *userdata),
179 _cleanup_free_ char *contents = NULL, *key = NULL;
180 size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_whitespace = (size_t) -1;
181 char *p, *value = NULL;
192 SINGLE_QUOTE_VALUE_ESCAPE,
194 DOUBLE_QUOTE_VALUE_ESCAPE,
202 r = read_full_file(fname, &contents, NULL);
206 for (p = contents; *p; p++) {
212 if (startswith(p, "export "))
214 else if (strchr(COMMENTS, c))
216 else if (!strchr(WHITESPACE, c)) {
218 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
228 if (strchr(newline, c)) {
231 } else if (strchr(WHITESPACE, c))
236 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
247 if (strchr(newline, c)) {
252 else if (!strchr(WHITESPACE, c)) {
260 if (strchr(newline, c) || strchr(COMMENTS, c)) {
267 r = push(key, value, userdata);
273 value_alloc = n_value = 0;
274 } else if (c == '\'')
275 state = SINGLE_QUOTE_VALUE;
277 state = DOUBLE_QUOTE_VALUE;
279 state = VALUE_ESCAPE;
280 else if (!strchr(WHITESPACE, c)) {
283 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
288 value[n_value++] = c;
294 if (strchr(newline, c)) {
301 /* Chomp off trailing whitespace */
302 if (last_whitespace != (size_t) -1)
303 value[last_whitespace] = 0;
305 r = push(key, value, userdata);
311 value_alloc = n_value = 0;
312 } else if (c == '\\') {
313 state = VALUE_ESCAPE;
314 last_whitespace = (size_t) -1;
316 if (!strchr(WHITESPACE, c))
317 last_whitespace = (size_t) -1;
318 else if (last_whitespace == (size_t) -1)
319 last_whitespace = n_value;
321 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
326 value[n_value++] = c;
334 if (!strchr(newline, c)) {
335 /* Escaped newlines we eat up entirely */
336 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
341 value[n_value++] = c;
345 case SINGLE_QUOTE_VALUE:
349 state = SINGLE_QUOTE_VALUE_ESCAPE;
351 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
356 value[n_value++] = c;
361 case SINGLE_QUOTE_VALUE_ESCAPE:
362 state = SINGLE_QUOTE_VALUE;
364 if (!strchr(newline, c)) {
365 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
370 value[n_value++] = c;
374 case DOUBLE_QUOTE_VALUE:
378 state = DOUBLE_QUOTE_VALUE_ESCAPE;
380 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
385 value[n_value++] = c;
390 case DOUBLE_QUOTE_VALUE_ESCAPE:
391 state = DOUBLE_QUOTE_VALUE;
393 if (!strchr(newline, c)) {
394 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
399 value[n_value++] = c;
405 state = COMMENT_ESCAPE;
406 else if (strchr(newline, c))
416 if (state == PRE_VALUE ||
418 state == VALUE_ESCAPE ||
419 state == SINGLE_QUOTE_VALUE ||
420 state == SINGLE_QUOTE_VALUE_ESCAPE ||
421 state == DOUBLE_QUOTE_VALUE ||
422 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
429 r = push(key, value, userdata);
441 static int parse_env_file_push(const char *key, char *value, void *userdata) {
443 va_list* ap = (va_list*) userdata;
448 while ((k = va_arg(aq, const char *))) {
451 v = va_arg(aq, char **);
469 const char *newline, ...) {
477 va_start(ap, newline);
478 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
484 static int load_env_file_push(const char *key, char *value, void *userdata) {
485 char ***m = userdata;
489 p = strjoin(key, "=", strempty(value), NULL);
503 int load_env_file(const char *fname, const char *newline, char ***rl) {
510 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
520 static void write_env_var(FILE *f, const char *v) {
532 fwrite(v, 1, p-v, f);
534 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
538 if (strchr("\'\"\\`$", *p))
551 int write_env_file(const char *fname, char **l) {
553 char _cleanup_free_ *p = NULL;
554 FILE _cleanup_fclose_ *f = NULL;
557 r = fopen_temporary(fname, &f, &p);
561 fchmod_umask(fileno(f), 0644);
565 write_env_var(f, *i);
570 r = errno ? -errno : -EIO;
572 if (rename(p, fname) < 0)