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/>.
28 int write_string_to_file(FILE *f, const char *line) {
31 if (!endswith(line, "\n"))
37 return errno ? -errno : -EIO;
42 int write_string_file(const char *fn, const char *line) {
43 _cleanup_fclose_ FILE *f = NULL;
52 return write_string_to_file(f, line);
55 int write_string_file_atomic(const char *fn, const char *line) {
56 _cleanup_fclose_ FILE *f = NULL;
57 _cleanup_free_ char *p = NULL;
63 r = fopen_temporary(fn, &f, &p);
67 fchmod_umask(fileno(f), 0644);
71 if (!endswith(line, "\n"))
77 r = errno ? -errno : -EIO;
79 if (rename(p, fn) < 0)
91 int read_one_line_file(const char *fn, char **line) {
92 _cleanup_fclose_ FILE *f = NULL;
102 if (!fgets(t, sizeof(t), f)) {
105 return errno ? -errno : -EIO;
119 int read_full_file(const char *fn, char **contents, size_t *size) {
120 _cleanup_fclose_ FILE *f = NULL;
122 _cleanup_free_ char *buf = NULL;
132 if (fstat(fileno(f), &st) < 0)
136 if (st.st_size > 4*1024*1024)
139 n = st.st_size > 0 ? st.st_size : LINE_MAX;
146 t = realloc(buf, n+1);
151 k = fread(buf + l, 1, n - l, f);
178 static int parse_env_file_internal(
181 int (*push) (const char *key, char *value, void *userdata),
184 _cleanup_free_ char *contents = NULL, *key = NULL;
185 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;
186 char *p, *value = NULL;
196 SINGLE_QUOTE_VALUE_ESCAPE,
198 DOUBLE_QUOTE_VALUE_ESCAPE,
206 r = read_full_file(fname, &contents, NULL);
210 for (p = contents; *p; p++) {
216 if (strchr(COMMENTS, c))
218 else if (!strchr(WHITESPACE, c)) {
220 last_key_whitespace = (size_t) -1;
222 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
232 if (strchr(newline, c)) {
235 } else if (c == '=') {
237 last_value_whitespace = (size_t) -1;
239 if (!strchr(WHITESPACE, c))
240 last_key_whitespace = (size_t) -1;
241 else if (last_key_whitespace == (size_t) -1)
242 last_key_whitespace = n_key;
244 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
255 if (strchr(newline, c)) {
262 /* strip trailing whitespace from key */
263 if (last_key_whitespace != (size_t) -1)
264 key[last_key_whitespace] = 0;
266 r = push(key, value, userdata);
272 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)) {
302 /* Chomp off trailing whitespace from value */
303 if (last_value_whitespace != (size_t) -1)
304 value[last_value_whitespace] = 0;
306 /* strip trailing whitespace from key */
307 if (last_key_whitespace != (size_t) -1)
308 key[last_key_whitespace] = 0;
310 r = push(key, value, userdata);
316 value_alloc = n_value = 0;
318 } else if (c == '\\') {
319 state = VALUE_ESCAPE;
320 last_value_whitespace = (size_t) -1;
322 if (!strchr(WHITESPACE, c))
323 last_value_whitespace = (size_t) -1;
324 else if (last_value_whitespace == (size_t) -1)
325 last_value_whitespace = n_value;
327 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
332 value[n_value++] = c;
340 if (!strchr(newline, c)) {
341 /* Escaped newlines we eat up entirely */
342 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
347 value[n_value++] = c;
351 case SINGLE_QUOTE_VALUE:
355 state = SINGLE_QUOTE_VALUE_ESCAPE;
357 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
362 value[n_value++] = c;
367 case SINGLE_QUOTE_VALUE_ESCAPE:
368 state = SINGLE_QUOTE_VALUE;
370 if (!strchr(newline, c)) {
371 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
376 value[n_value++] = c;
380 case DOUBLE_QUOTE_VALUE:
384 state = DOUBLE_QUOTE_VALUE_ESCAPE;
386 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
391 value[n_value++] = c;
396 case DOUBLE_QUOTE_VALUE_ESCAPE:
397 state = DOUBLE_QUOTE_VALUE;
399 if (!strchr(newline, c)) {
400 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
405 value[n_value++] = c;
411 state = COMMENT_ESCAPE;
412 else if (strchr(newline, c))
422 if (state == PRE_VALUE ||
424 state == VALUE_ESCAPE ||
425 state == SINGLE_QUOTE_VALUE ||
426 state == SINGLE_QUOTE_VALUE_ESCAPE ||
427 state == DOUBLE_QUOTE_VALUE ||
428 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
436 if (last_value_whitespace != (size_t) -1)
437 value[last_value_whitespace] = 0;
439 /* strip trailing whitespace from key */
440 if (last_key_whitespace != (size_t) -1)
441 key[last_key_whitespace] = 0;
443 r = push(key, value, userdata);
455 static int parse_env_file_push(const char *key, char *value, void *userdata) {
457 va_list* ap = (va_list*) userdata;
462 while ((k = va_arg(aq, const char *))) {
465 v = va_arg(aq, char **);
483 const char *newline, ...) {
491 va_start(ap, newline);
492 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
498 static int load_env_file_push(const char *key, char *value, void *userdata) {
499 char ***m = userdata;
503 p = strjoin(key, "=", strempty(value), NULL);
517 int load_env_file(const char *fname, const char *newline, char ***rl) {
524 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
534 static void write_env_var(FILE *f, const char *v) {
546 fwrite(v, 1, p-v, f);
548 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
552 if (strchr("\'\"\\`$", *p))
565 int write_env_file(const char *fname, char **l) {
567 _cleanup_free_ char *p = NULL;
568 _cleanup_fclose_ FILE *f = NULL;
571 r = fopen_temporary(fname, &f, &p);
575 fchmod_umask(fileno(f), 0644);
579 write_env_var(f, *i);
584 r = errno ? -errno : -EIO;
586 if (rename(p, fname) < 0)