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_value_whitespace
= (size_t) -1, last_key_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 last_key_whitespace
= (size_t) -1;
217 if (!greedy_realloc((void**) &key
, &key_alloc
, n_key
+2)) {
227 if (strchr(newline
, c
)) {
230 } else if (c
== '=') {
232 last_value_whitespace
= (size_t) -1;
234 if (!strchr(WHITESPACE
, c
))
235 last_key_whitespace
= (size_t) -1;
236 else if (last_key_whitespace
== (size_t) -1)
237 last_key_whitespace
= n_key
;
239 if (!greedy_realloc((void**) &key
, &key_alloc
, n_key
+2)) {
250 if (strchr(newline
, c
)) {
257 /* strip trailing whitespace from key */
258 if (last_key_whitespace
!= (size_t) -1)
259 key
[last_key_whitespace
] = 0;
261 r
= push(key
, value
, userdata
);
267 value_alloc
= n_value
= 0;
269 } else if (c
== '\'')
270 state
= SINGLE_QUOTE_VALUE
;
272 state
= DOUBLE_QUOTE_VALUE
;
274 state
= VALUE_ESCAPE
;
275 else if (!strchr(WHITESPACE
, c
)) {
278 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
283 value
[n_value
++] = c
;
289 if (strchr(newline
, c
)) {
297 /* Chomp off trailing whitespace from value */
298 if (last_value_whitespace
!= (size_t) -1)
299 value
[last_value_whitespace
] = 0;
301 /* strip trailing whitespace from key */
302 if (last_key_whitespace
!= (size_t) -1)
303 key
[last_key_whitespace
] = 0;
305 r
= push(key
, value
, userdata
);
311 value_alloc
= n_value
= 0;
313 } else if (c
== '\\') {
314 state
= VALUE_ESCAPE
;
315 last_value_whitespace
= (size_t) -1;
317 if (!strchr(WHITESPACE
, c
))
318 last_value_whitespace
= (size_t) -1;
319 else if (last_value_whitespace
== (size_t) -1)
320 last_value_whitespace
= n_value
;
322 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
327 value
[n_value
++] = c
;
335 if (!strchr(newline
, c
)) {
336 /* Escaped newlines we eat up entirely */
337 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
342 value
[n_value
++] = c
;
346 case SINGLE_QUOTE_VALUE
:
350 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
352 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
357 value
[n_value
++] = c
;
362 case SINGLE_QUOTE_VALUE_ESCAPE
:
363 state
= SINGLE_QUOTE_VALUE
;
365 if (!strchr(newline
, c
)) {
366 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
371 value
[n_value
++] = c
;
375 case DOUBLE_QUOTE_VALUE
:
379 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
381 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
386 value
[n_value
++] = c
;
391 case DOUBLE_QUOTE_VALUE_ESCAPE
:
392 state
= DOUBLE_QUOTE_VALUE
;
394 if (!strchr(newline
, c
)) {
395 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
400 value
[n_value
++] = c
;
406 state
= COMMENT_ESCAPE
;
407 else if (strchr(newline
, c
))
417 if (state
== PRE_VALUE
||
419 state
== VALUE_ESCAPE
||
420 state
== SINGLE_QUOTE_VALUE
||
421 state
== SINGLE_QUOTE_VALUE_ESCAPE
||
422 state
== DOUBLE_QUOTE_VALUE
||
423 state
== DOUBLE_QUOTE_VALUE_ESCAPE
) {
431 if (last_value_whitespace
!= (size_t) -1)
432 value
[last_value_whitespace
] = 0;
434 /* strip trailing whitespace from key */
435 if (last_key_whitespace
!= (size_t) -1)
436 key
[last_key_whitespace
] = 0;
438 r
= push(key
, value
, userdata
);
450 static int parse_env_file_push(const char *key
, char *value
, void *userdata
) {
452 va_list* ap
= (va_list*) userdata
;
457 while ((k
= va_arg(aq
, const char *))) {
460 v
= va_arg(aq
, char **);
478 const char *newline
, ...) {
486 va_start(ap
, newline
);
487 r
= parse_env_file_internal(fname
, newline
, parse_env_file_push
, &ap
);
493 static int load_env_file_push(const char *key
, char *value
, void *userdata
) {
494 char ***m
= userdata
;
498 p
= strjoin(key
, "=", strempty(value
), NULL
);
512 int load_env_file(const char *fname
, const char *newline
, char ***rl
) {
519 r
= parse_env_file_internal(fname
, newline
, load_env_file_push
, &m
);
529 static void write_env_var(FILE *f
, const char *v
) {
541 fwrite(v
, 1, p
-v
, f
);
543 if (string_has_cc(p
) || chars_intersect(p
, WHITESPACE
"\'\"\\`$")) {
547 if (strchr("\'\"\\`$", *p
))
560 int write_env_file(const char *fname
, char **l
) {
562 _cleanup_free_
char *p
= NULL
;
563 _cleanup_fclose_
FILE *f
= NULL
;
566 r
= fopen_temporary(fname
, &f
, &p
);
570 fchmod_umask(fileno(f
), 0644);
574 write_env_var(f
, *i
);
579 r
= errno
? -errno
: -EIO
;
581 if (rename(p
, fname
) < 0)