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 (strchr(COMMENTS, c))
214 else if (!strchr(WHITESPACE, c)) {
216 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
226 if (strchr(newline, c)) {
229 } else if (strchr(WHITESPACE, c))
234 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
245 if (strchr(newline, c)) {
250 else if (!strchr(WHITESPACE, c)) {
258 if (strchr(newline, c)) {
265 r = push(key, value, userdata);
271 value_alloc = n_value = 0;
272 } else if (c == '\'')
273 state = SINGLE_QUOTE_VALUE;
275 state = DOUBLE_QUOTE_VALUE;
277 state = VALUE_ESCAPE;
278 else if (!strchr(WHITESPACE, c)) {
281 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
286 value[n_value++] = c;
292 if (strchr(newline, c)) {
299 /* Chomp off trailing whitespace */
300 if (last_whitespace != (size_t) -1)
301 value[last_whitespace] = 0;
303 r = push(key, value, userdata);
309 value_alloc = n_value = 0;
310 } else if (c == '\\') {
311 state = VALUE_ESCAPE;
312 last_whitespace = (size_t) -1;
314 if (!strchr(WHITESPACE, c))
315 last_whitespace = (size_t) -1;
316 else if (last_whitespace == (size_t) -1)
317 last_whitespace = n_value;
319 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
324 value[n_value++] = c;
332 if (!strchr(newline, c)) {
333 /* Escaped newlines we eat up entirely */
334 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
339 value[n_value++] = c;
343 case SINGLE_QUOTE_VALUE:
347 state = SINGLE_QUOTE_VALUE_ESCAPE;
349 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
354 value[n_value++] = c;
359 case SINGLE_QUOTE_VALUE_ESCAPE:
360 state = SINGLE_QUOTE_VALUE;
362 if (!strchr(newline, c)) {
363 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
368 value[n_value++] = c;
372 case DOUBLE_QUOTE_VALUE:
376 state = DOUBLE_QUOTE_VALUE_ESCAPE;
378 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
383 value[n_value++] = c;
388 case DOUBLE_QUOTE_VALUE_ESCAPE:
389 state = DOUBLE_QUOTE_VALUE;
391 if (!strchr(newline, c)) {
392 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
397 value[n_value++] = c;
403 state = COMMENT_ESCAPE;
404 else if (strchr(newline, c))
414 if (state == PRE_VALUE ||
416 state == VALUE_ESCAPE ||
417 state == SINGLE_QUOTE_VALUE ||
418 state == SINGLE_QUOTE_VALUE_ESCAPE ||
419 state == DOUBLE_QUOTE_VALUE ||
420 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
427 r = push(key, value, userdata);
439 static int parse_env_file_push(const char *key, char *value, void *userdata) {
441 va_list* ap = (va_list*) userdata;
446 while ((k = va_arg(aq, const char *))) {
449 v = va_arg(aq, char **);
467 const char *newline, ...) {
475 va_start(ap, newline);
476 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
482 static int load_env_file_push(const char *key, char *value, void *userdata) {
483 char ***m = userdata;
487 p = strjoin(key, "=", strempty(value), NULL);
501 int load_env_file(const char *fname, const char *newline, char ***rl) {
508 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
518 static void write_env_var(FILE *f, const char *v) {
530 fwrite(v, 1, p-v, f);
532 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\")) {
536 if (strchr("\'\"\\", *p))
549 int write_env_file(const char *fname, char **l) {
551 char _cleanup_free_ *p = NULL;
552 FILE _cleanup_fclose_ *f = NULL;
555 r = fopen_temporary(fname, &f, &p);
559 fchmod_umask(fileno(f), 0644);
563 write_env_var(f, *i);
568 r = errno ? -errno : -EIO;
570 if (rename(p, fname) < 0)