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)) {
249 /* strip trailing whitespace from key */
250 while(n_key && 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)) {
288 /* Chomp off trailing whitespace */
289 if (last_whitespace != (size_t) -1)
290 value[last_whitespace] = 0;
292 /* strip trailing whitespace from key */
293 while(n_key && strchr(WHITESPACE, key[--n_key]))
296 r = push(key, value, userdata);
302 value_alloc = n_value = 0;
303 } else if (c == '\\') {
304 state = VALUE_ESCAPE;
305 last_whitespace = (size_t) -1;
307 if (!strchr(WHITESPACE, c))
308 last_whitespace = (size_t) -1;
309 else if (last_whitespace == (size_t) -1)
310 last_whitespace = n_value;
312 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
317 value[n_value++] = c;
325 if (!strchr(newline, c)) {
326 /* Escaped newlines we eat up entirely */
327 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
332 value[n_value++] = c;
336 case SINGLE_QUOTE_VALUE:
340 state = SINGLE_QUOTE_VALUE_ESCAPE;
342 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
347 value[n_value++] = c;
352 case SINGLE_QUOTE_VALUE_ESCAPE:
353 state = SINGLE_QUOTE_VALUE;
355 if (!strchr(newline, c)) {
356 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
361 value[n_value++] = c;
365 case DOUBLE_QUOTE_VALUE:
369 state = DOUBLE_QUOTE_VALUE_ESCAPE;
371 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
376 value[n_value++] = c;
381 case DOUBLE_QUOTE_VALUE_ESCAPE:
382 state = DOUBLE_QUOTE_VALUE;
384 if (!strchr(newline, c)) {
385 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
390 value[n_value++] = c;
396 state = COMMENT_ESCAPE;
397 else if (strchr(newline, c))
407 if (state == PRE_VALUE ||
409 state == VALUE_ESCAPE ||
410 state == SINGLE_QUOTE_VALUE ||
411 state == SINGLE_QUOTE_VALUE_ESCAPE ||
412 state == DOUBLE_QUOTE_VALUE ||
413 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
420 /* strip trailing whitespace from key */
421 while(n_key && strchr(WHITESPACE, key[--n_key]))
424 r = push(key, value, userdata);
436 static int parse_env_file_push(const char *key, char *value, void *userdata) {
438 va_list* ap = (va_list*) userdata;
443 while ((k = va_arg(aq, const char *))) {
446 v = va_arg(aq, char **);
464 const char *newline, ...) {
472 va_start(ap, newline);
473 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
479 static int load_env_file_push(const char *key, char *value, void *userdata) {
480 char ***m = userdata;
484 p = strjoin(key, "=", strempty(value), NULL);
498 int load_env_file(const char *fname, const char *newline, char ***rl) {
505 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
515 static void write_env_var(FILE *f, const char *v) {
527 fwrite(v, 1, p-v, f);
529 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
533 if (strchr("\'\"\\`$", *p))
546 int write_env_file(const char *fname, char **l) {
548 _cleanup_free_ char *p = NULL;
549 _cleanup_fclose_ FILE *f = NULL;
552 r = fopen_temporary(fname, &f, &p);
556 fchmod_umask(fileno(f), 0644);
560 write_env_var(f, *i);
565 r = errno ? -errno : -EIO;
567 if (rename(p, fname) < 0)