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_to_file(FILE *f, const char *line) {
30 if (!endswith(line, "\n"))
36 return errno ? -errno : -EIO;
41 int write_string_file(const char *fn, const char *line) {
42 _cleanup_fclose_ FILE *f = NULL;
51 return write_string_to_file(f, line);
54 int write_string_file_atomic(const char *fn, const char *line) {
55 _cleanup_fclose_ FILE *f = NULL;
56 _cleanup_free_ char *p = NULL;
62 r = fopen_temporary(fn, &f, &p);
66 fchmod_umask(fileno(f), 0644);
70 if (!endswith(line, "\n"))
76 r = errno ? -errno : -EIO;
78 if (rename(p, fn) < 0)
90 int read_one_line_file(const char *fn, char **line) {
91 _cleanup_fclose_ FILE *f = NULL;
101 if (!fgets(t, sizeof(t), f)) {
104 return errno ? -errno : -EIO;
118 int read_full_file(const char *fn, char **contents, size_t *size) {
119 _cleanup_fclose_ FILE *f = NULL;
121 _cleanup_free_ char *buf = NULL;
131 if (fstat(fileno(f), &st) < 0)
135 if (st.st_size > 4*1024*1024)
138 n = st.st_size > 0 ? st.st_size : LINE_MAX;
145 t = realloc(buf, n+1);
150 k = fread(buf + l, 1, n - l, f);
177 static int parse_env_file_internal(
180 int (*push) (const char *key, char *value, void *userdata),
183 _cleanup_free_ char *contents = NULL, *key = NULL;
184 size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
185 char *p, *value = NULL;
195 SINGLE_QUOTE_VALUE_ESCAPE,
197 DOUBLE_QUOTE_VALUE_ESCAPE,
205 r = read_full_file(fname, &contents, NULL);
209 for (p = contents; *p; p++) {
215 if (strchr(COMMENTS, c))
217 else if (!strchr(WHITESPACE, c)) {
219 last_key_whitespace = (size_t) -1;
221 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
231 if (strchr(newline, c)) {
234 } else if (c == '=') {
236 last_value_whitespace = (size_t) -1;
238 if (!strchr(WHITESPACE, c))
239 last_key_whitespace = (size_t) -1;
240 else if (last_key_whitespace == (size_t) -1)
241 last_key_whitespace = n_key;
243 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
254 if (strchr(newline, c)) {
261 /* strip trailing whitespace from key */
262 if (last_key_whitespace != (size_t) -1)
263 key[last_key_whitespace] = 0;
265 r = push(key, value, userdata);
271 value_alloc = n_value = 0;
273 } else if (c == '\'')
274 state = SINGLE_QUOTE_VALUE;
276 state = DOUBLE_QUOTE_VALUE;
278 state = VALUE_ESCAPE;
279 else if (!strchr(WHITESPACE, c)) {
282 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
287 value[n_value++] = c;
293 if (strchr(newline, c)) {
301 /* Chomp off trailing whitespace from value */
302 if (last_value_whitespace != (size_t) -1)
303 value[last_value_whitespace] = 0;
305 /* strip trailing whitespace from key */
306 if (last_key_whitespace != (size_t) -1)
307 key[last_key_whitespace] = 0;
309 r = push(key, value, userdata);
315 value_alloc = n_value = 0;
317 } else if (c == '\\') {
318 state = VALUE_ESCAPE;
319 last_value_whitespace = (size_t) -1;
321 if (!strchr(WHITESPACE, c))
322 last_value_whitespace = (size_t) -1;
323 else if (last_value_whitespace == (size_t) -1)
324 last_value_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) {
435 if (last_value_whitespace != (size_t) -1)
436 value[last_value_whitespace] = 0;
438 /* strip trailing whitespace from key */
439 if (last_key_whitespace != (size_t) -1)
440 key[last_key_whitespace] = 0;
442 r = push(key, value, userdata);
454 static int parse_env_file_push(const char *key, char *value, void *userdata) {
456 va_list* ap = (va_list*) userdata;
461 while ((k = va_arg(aq, const char *))) {
464 v = va_arg(aq, char **);
482 const char *newline, ...) {
490 va_start(ap, newline);
491 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
497 static int load_env_file_push(const char *key, char *value, void *userdata) {
498 char ***m = userdata;
502 p = strjoin(key, "=", strempty(value), NULL);
516 int load_env_file(const char *fname, const char *newline, char ***rl) {
523 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
533 static void write_env_var(FILE *f, const char *v) {
545 fwrite(v, 1, p-v, f);
547 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
551 if (strchr("\'\"\\`$", *p))
564 int write_env_file(const char *fname, char **l) {
566 _cleanup_free_ char *p = NULL;
567 _cleanup_fclose_ FILE *f = NULL;
570 r = fopen_temporary(fname, &f, &p);
574 fchmod_umask(fileno(f), 0644);
578 write_env_var(f, *i);
583 r = errno ? -errno : -EIO;
585 if (rename(p, fname) < 0)