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;
38 if (fputs(line, f) < 0)
39 return errno ? -errno : -EIO;
41 if (!endswith(line, "\n"))
47 return errno ? -errno : -EIO;
52 int write_string_file_atomic(const char *fn, const char *line) {
53 _cleanup_fclose_ FILE *f = NULL;
54 _cleanup_free_ char *p = NULL;
60 r = fopen_temporary(fn, &f, &p);
64 fchmod_umask(fileno(f), 0644);
67 if (fputs(line, f) < 0) {
72 if (!endswith(line, "\n"))
78 r = errno ? -errno : -EIO;
80 if (rename(p, fn) < 0)
93 int read_one_line_file(const char *fn, char **line) {
94 _cleanup_fclose_ FILE *f = NULL;
104 if (!fgets(t, sizeof(t), f)) {
107 return errno ? -errno : -EIO;
121 int read_full_file(const char *fn, char **contents, size_t *size) {
122 _cleanup_fclose_ FILE *f = NULL;
124 _cleanup_free_ char *buf = NULL;
134 if (fstat(fileno(f), &st) < 0)
138 if (st.st_size > 4*1024*1024)
141 n = st.st_size > 0 ? st.st_size : LINE_MAX;
148 t = realloc(buf, n+1);
153 k = fread(buf + l, 1, n - l, f);
180 static int parse_env_file_internal(
183 int (*push) (const char *key, char *value, void *userdata),
186 _cleanup_free_ char *contents = NULL, *key = NULL;
187 size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_whitespace = (size_t) -1;
188 char *p, *value = NULL;
199 SINGLE_QUOTE_VALUE_ESCAPE,
201 DOUBLE_QUOTE_VALUE_ESCAPE,
209 r = read_full_file(fname, &contents, NULL);
213 for (p = contents; *p; p++) {
219 if (strchr(COMMENTS, c))
221 else if (!strchr(WHITESPACE, c)) {
223 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
233 if (strchr(newline, c)) {
236 } else if (strchr(WHITESPACE, c))
241 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
252 if (strchr(newline, c)) {
257 else if (!strchr(WHITESPACE, c)) {
265 if (strchr(newline, c)) {
272 r = push(key, value, userdata);
278 value_alloc = n_value = 0;
279 } else if (c == '\'')
280 state = SINGLE_QUOTE_VALUE;
282 state = DOUBLE_QUOTE_VALUE;
284 state = VALUE_ESCAPE;
285 else if (!strchr(WHITESPACE, c)) {
288 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
293 value[n_value++] = c;
299 if (strchr(newline, c)) {
306 /* Chomp off trailing whitespace */
307 if (last_whitespace != (size_t) -1)
308 value[last_whitespace] = 0;
310 r = push(key, value, userdata);
316 value_alloc = n_value = 0;
317 } else if (c == '\\') {
318 state = VALUE_ESCAPE;
319 last_whitespace = (size_t) -1;
321 if (!strchr(WHITESPACE, c))
322 last_whitespace = (size_t) -1;
323 else if (last_whitespace == (size_t) -1)
324 last_whitespace = n_value;
326 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
331 value[n_value++] = c;
339 if (!strchr(newline, c)) {
340 /* Escaped newlines we eat up entirely */
341 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
346 value[n_value++] = c;
350 case SINGLE_QUOTE_VALUE:
354 state = SINGLE_QUOTE_VALUE_ESCAPE;
356 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
361 value[n_value++] = c;
366 case SINGLE_QUOTE_VALUE_ESCAPE:
367 state = SINGLE_QUOTE_VALUE;
369 if (!strchr(newline, c)) {
370 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
375 value[n_value++] = c;
379 case DOUBLE_QUOTE_VALUE:
383 state = DOUBLE_QUOTE_VALUE_ESCAPE;
385 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
390 value[n_value++] = c;
395 case DOUBLE_QUOTE_VALUE_ESCAPE:
396 state = DOUBLE_QUOTE_VALUE;
398 if (!strchr(newline, c)) {
399 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
404 value[n_value++] = c;
410 state = COMMENT_ESCAPE;
411 else if (strchr(newline, c))
421 if (state == PRE_VALUE ||
423 state == VALUE_ESCAPE ||
424 state == SINGLE_QUOTE_VALUE ||
425 state == SINGLE_QUOTE_VALUE_ESCAPE ||
426 state == DOUBLE_QUOTE_VALUE ||
427 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
434 r = push(key, value, userdata);
446 static int parse_env_file_push(const char *key, char *value, void *userdata) {
448 va_list* ap = (va_list*) userdata;
453 while ((k = va_arg(aq, const char *))) {
456 v = va_arg(aq, char **);
474 const char *newline, ...) {
482 va_start(ap, newline);
483 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
489 static int load_env_file_push(const char *key, char *value, void *userdata) {
490 char ***m = userdata;
494 p = strjoin(key, "=", strempty(value), NULL);
508 int load_env_file(const char *fname, const char *newline, char ***rl) {
515 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
525 int write_env_file(const char *fname, char **l) {
527 char _cleanup_free_ *p = NULL;
528 FILE _cleanup_fclose_ *f = NULL;
531 r = fopen_temporary(fname, &f, &p);
535 fchmod_umask(fileno(f), 0644);
551 if (rename(p, fname) < 0)