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;
191 SINGLE_QUOTE_VALUE_ESCAPE,
193 DOUBLE_QUOTE_VALUE_ESCAPE,
201 r = read_full_file(fname, &contents, NULL);
205 for (p = contents; *p; p++) {
211 if (strchr(COMMENTS, c))
213 else if (!strchr(WHITESPACE, c)) {
215 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
225 if (strchr(newline, c)) {
231 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
242 if (strchr(newline, c) || strchr(COMMENTS, c)) {
249 /* strip trailing whitespace from key */
250 while(strchr(WHITESPACE, key[--n_key]))
253 r = push(key, value, userdata);
259 value_alloc = n_value = 0;
260 } else if (c == '\'')
261 state = SINGLE_QUOTE_VALUE;
263 state = DOUBLE_QUOTE_VALUE;
265 state = VALUE_ESCAPE;
266 else if (!strchr(WHITESPACE, c)) {
269 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
274 value[n_value++] = c;
280 if (strchr(newline, c)) {
287 /* Chomp off trailing whitespace */
288 if (last_whitespace != (size_t) -1)
289 value[last_whitespace] = 0;
291 /* strip trailing whitespace from key */
292 while(strchr(WHITESPACE, key[--n_key]))
295 r = push(key, value, userdata);
301 value_alloc = n_value = 0;
302 } else if (c == '\\') {
303 state = VALUE_ESCAPE;
304 last_whitespace = (size_t) -1;
306 if (!strchr(WHITESPACE, c))
307 last_whitespace = (size_t) -1;
308 else if (last_whitespace == (size_t) -1)
309 last_whitespace = n_value;
311 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
316 value[n_value++] = c;
324 if (!strchr(newline, c)) {
325 /* Escaped newlines we eat up entirely */
326 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
331 value[n_value++] = c;
335 case SINGLE_QUOTE_VALUE:
339 state = SINGLE_QUOTE_VALUE_ESCAPE;
341 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
346 value[n_value++] = c;
351 case SINGLE_QUOTE_VALUE_ESCAPE:
352 state = SINGLE_QUOTE_VALUE;
354 if (!strchr(newline, c)) {
355 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
360 value[n_value++] = c;
364 case DOUBLE_QUOTE_VALUE:
368 state = DOUBLE_QUOTE_VALUE_ESCAPE;
370 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
375 value[n_value++] = c;
380 case DOUBLE_QUOTE_VALUE_ESCAPE:
381 state = DOUBLE_QUOTE_VALUE;
383 if (!strchr(newline, c)) {
384 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
389 value[n_value++] = c;
395 state = COMMENT_ESCAPE;
396 else if (strchr(newline, c))
406 if (state == PRE_VALUE ||
408 state == VALUE_ESCAPE ||
409 state == SINGLE_QUOTE_VALUE ||
410 state == SINGLE_QUOTE_VALUE_ESCAPE ||
411 state == DOUBLE_QUOTE_VALUE ||
412 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
419 /* strip trailing whitespace from key */
420 while(strchr(WHITESPACE, key[--n_key]))
423 r = push(key, value, userdata);
435 static int parse_env_file_push(const char *key, char *value, void *userdata) {
437 va_list* ap = (va_list*) userdata;
442 while ((k = va_arg(aq, const char *))) {
445 v = va_arg(aq, char **);
463 const char *newline, ...) {
471 va_start(ap, newline);
472 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
478 static int load_env_file_push(const char *key, char *value, void *userdata) {
479 char ***m = userdata;
483 p = strjoin(key, "=", strempty(value), NULL);
497 int load_env_file(const char *fname, const char *newline, char ***rl) {
504 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
514 static void write_env_var(FILE *f, const char *v) {
526 fwrite(v, 1, p-v, f);
528 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
532 if (strchr("\'\"\\`$", *p))
545 int write_env_file(const char *fname, char **l) {
547 char _cleanup_free_ *p = NULL;
548 FILE _cleanup_fclose_ *f = NULL;
551 r = fopen_temporary(fname, &f, &p);
555 fchmod_umask(fileno(f), 0644);
559 write_env_var(f, *i);
564 r = errno ? -errno : -EIO;
566 if (rename(p, fname) < 0)