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/>.
26 #include "string-util.h"
32 int write_string_stream(FILE *f
, const char *line
, bool enforce_newline
) {
38 if (enforce_newline
&& !endswith(line
, "\n"))
41 return fflush_and_check(f
);
44 static int write_string_file_atomic(const char *fn
, const char *line
, bool enforce_newline
) {
45 _cleanup_fclose_
FILE *f
= NULL
;
46 _cleanup_free_
char *p
= NULL
;
52 r
= fopen_temporary(fn
, &f
, &p
);
56 fchmod_umask(fileno(f
), 0644);
58 r
= write_string_stream(f
, line
, enforce_newline
);
60 if (rename(p
, fn
) < 0)
70 int write_string_file(const char *fn
, const char *line
, WriteStringFileFlags flags
) {
71 _cleanup_fclose_
FILE *f
= NULL
;
76 if (flags
& WRITE_STRING_FILE_ATOMIC
) {
77 assert(flags
& WRITE_STRING_FILE_CREATE
);
79 return write_string_file_atomic(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
82 if (flags
& WRITE_STRING_FILE_CREATE
) {
89 /* We manually build our own version of fopen(..., "we") that
90 * works without O_CREAT */
91 fd
= open(fn
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
102 return write_string_stream(f
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
105 int read_one_line_file(const char *fn
, char **line
) {
106 _cleanup_fclose_
FILE *f
= NULL
;
107 char t
[LINE_MAX
], *c
;
116 if (!fgets(t
, sizeof(t
), f
)) {
119 return errno
? -errno
: -EIO
;
133 int verify_one_line_file(const char *fn
, const char *line
) {
134 _cleanup_free_
char *value
= NULL
;
137 r
= read_one_line_file(fn
, &value
);
141 return streq(value
, line
);
144 int read_full_stream(FILE *f
, char **contents
, size_t *size
) {
146 _cleanup_free_
char *buf
= NULL
;
152 if (fstat(fileno(f
), &st
) < 0)
157 if (S_ISREG(st
.st_mode
)) {
160 if (st
.st_size
> 4*1024*1024)
163 /* Start with the right file size, but be prepared for
164 * files from /proc which generally report a file size
175 t
= realloc(buf
, n
+1);
180 k
= fread(buf
+ l
, 1, n
- l
, f
);
199 buf
= NULL
; /* do not free */
207 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
208 _cleanup_fclose_
FILE *f
= NULL
;
217 return read_full_stream(f
, contents
, size
);
220 static int parse_env_file_internal(
224 int (*push
) (const char *filename
, unsigned line
,
225 const char *key
, char *value
, void *userdata
, int *n_pushed
),
229 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
230 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;
231 char *p
, *value
= NULL
;
242 SINGLE_QUOTE_VALUE_ESCAPE
,
244 DOUBLE_QUOTE_VALUE_ESCAPE
,
252 r
= read_full_stream(f
, &contents
, NULL
);
254 r
= read_full_file(fname
, &contents
, NULL
);
258 for (p
= contents
; *p
; p
++) {
264 if (strchr(COMMENTS
, c
))
266 else if (!strchr(WHITESPACE
, c
)) {
268 last_key_whitespace
= (size_t) -1;
270 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
280 if (strchr(newline
, c
)) {
284 } else if (c
== '=') {
286 last_value_whitespace
= (size_t) -1;
288 if (!strchr(WHITESPACE
, c
))
289 last_key_whitespace
= (size_t) -1;
290 else if (last_key_whitespace
== (size_t) -1)
291 last_key_whitespace
= n_key
;
293 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
304 if (strchr(newline
, c
)) {
312 /* strip trailing whitespace from key */
313 if (last_key_whitespace
!= (size_t) -1)
314 key
[last_key_whitespace
] = 0;
316 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
322 value_alloc
= n_value
= 0;
324 } else if (c
== '\'')
325 state
= SINGLE_QUOTE_VALUE
;
327 state
= DOUBLE_QUOTE_VALUE
;
329 state
= VALUE_ESCAPE
;
330 else if (!strchr(WHITESPACE
, c
)) {
333 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
338 value
[n_value
++] = c
;
344 if (strchr(newline
, c
)) {
353 /* Chomp off trailing whitespace from value */
354 if (last_value_whitespace
!= (size_t) -1)
355 value
[last_value_whitespace
] = 0;
357 /* strip trailing whitespace from key */
358 if (last_key_whitespace
!= (size_t) -1)
359 key
[last_key_whitespace
] = 0;
361 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
367 value_alloc
= n_value
= 0;
369 } else if (c
== '\\') {
370 state
= VALUE_ESCAPE
;
371 last_value_whitespace
= (size_t) -1;
373 if (!strchr(WHITESPACE
, c
))
374 last_value_whitespace
= (size_t) -1;
375 else if (last_value_whitespace
== (size_t) -1)
376 last_value_whitespace
= n_value
;
378 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
383 value
[n_value
++] = c
;
391 if (!strchr(newline
, c
)) {
392 /* Escaped newlines we eat up entirely */
393 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
398 value
[n_value
++] = c
;
402 case SINGLE_QUOTE_VALUE
:
406 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
408 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
413 value
[n_value
++] = c
;
418 case SINGLE_QUOTE_VALUE_ESCAPE
:
419 state
= SINGLE_QUOTE_VALUE
;
421 if (!strchr(newline
, c
)) {
422 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
427 value
[n_value
++] = c
;
431 case DOUBLE_QUOTE_VALUE
:
435 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
437 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
442 value
[n_value
++] = c
;
447 case DOUBLE_QUOTE_VALUE_ESCAPE
:
448 state
= DOUBLE_QUOTE_VALUE
;
450 if (!strchr(newline
, c
)) {
451 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
456 value
[n_value
++] = c
;
462 state
= COMMENT_ESCAPE
;
463 else if (strchr(newline
, c
)) {
475 if (state
== PRE_VALUE
||
477 state
== VALUE_ESCAPE
||
478 state
== SINGLE_QUOTE_VALUE
||
479 state
== SINGLE_QUOTE_VALUE_ESCAPE
||
480 state
== DOUBLE_QUOTE_VALUE
||
481 state
== DOUBLE_QUOTE_VALUE_ESCAPE
) {
489 if (last_value_whitespace
!= (size_t) -1)
490 value
[last_value_whitespace
] = 0;
492 /* strip trailing whitespace from key */
493 if (last_key_whitespace
!= (size_t) -1)
494 key
[last_key_whitespace
] = 0;
496 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
508 static int parse_env_file_push(
509 const char *filename
, unsigned line
,
510 const char *key
, char *value
,
515 va_list aq
, *ap
= userdata
;
517 if (!utf8_is_valid(key
)) {
518 _cleanup_free_
char *p
;
520 p
= utf8_escape_invalid(key
);
521 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename
), line
, p
);
525 if (value
&& !utf8_is_valid(value
)) {
526 _cleanup_free_
char *p
;
528 p
= utf8_escape_invalid(value
);
529 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, p
);
535 while ((k
= va_arg(aq
, const char *))) {
538 v
= va_arg(aq
, char **);
560 const char *newline
, ...) {
568 va_start(ap
, newline
);
569 r
= parse_env_file_internal(NULL
, fname
, newline
, parse_env_file_push
, &ap
, &n_pushed
);
572 return r
< 0 ? r
: n_pushed
;
575 static int load_env_file_push(
576 const char *filename
, unsigned line
,
577 const char *key
, char *value
,
580 char ***m
= userdata
;
584 if (!utf8_is_valid(key
)) {
585 _cleanup_free_
char *t
= utf8_escape_invalid(key
);
587 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename
), line
, t
);
591 if (value
&& !utf8_is_valid(value
)) {
592 _cleanup_free_
char *t
= utf8_escape_invalid(value
);
594 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, t
);
598 p
= strjoin(key
, "=", strempty(value
), NULL
);
602 r
= strv_consume(m
, p
);
613 int load_env_file(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
620 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push
, &m
, NULL
);
630 static int load_env_file_push_pairs(
631 const char *filename
, unsigned line
,
632 const char *key
, char *value
,
635 char ***m
= userdata
;
638 if (!utf8_is_valid(key
)) {
639 _cleanup_free_
char *t
= utf8_escape_invalid(key
);
641 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename
), line
, t
);
645 if (value
&& !utf8_is_valid(value
)) {
646 _cleanup_free_
char *t
= utf8_escape_invalid(value
);
648 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, t
);
652 r
= strv_extend(m
, key
);
657 r
= strv_extend(m
, "");
661 r
= strv_push(m
, value
);
672 int load_env_file_pairs(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
679 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push_pairs
, &m
, NULL
);
689 static void write_env_var(FILE *f
, const char *v
) {
701 fwrite(v
, 1, p
-v
, f
);
703 if (string_has_cc(p
, NULL
) || chars_intersect(p
, WHITESPACE SHELL_NEED_QUOTES
)) {
707 if (strchr(SHELL_NEED_ESCAPE
, *p
))
720 int write_env_file(const char *fname
, char **l
) {
721 _cleanup_fclose_
FILE *f
= NULL
;
722 _cleanup_free_
char *p
= NULL
;
728 r
= fopen_temporary(fname
, &f
, &p
);
732 fchmod_umask(fileno(f
), 0644);
735 write_env_var(f
, *i
);
737 r
= fflush_and_check(f
);
739 if (rename(p
, fname
) >= 0)
749 int executable_is_script(const char *path
, char **interpreter
) {
751 _cleanup_free_
char *line
= NULL
;
757 r
= read_one_line_file(path
, &line
);
761 if (!startswith(line
, "#!"))
764 ans
= strstrip(line
+ 2);
765 len
= strcspn(ans
, " \t");
770 ans
= strndup(ans
, len
);
779 * Retrieve one field from a file like /proc/self/status. pattern
780 * should not include whitespace or the delimiter (':'). pattern matches only
781 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
782 * zeros after the ':' will be skipped. field must be freed afterwards.
783 * terminator specifies the terminating characters of the field value (not
784 * included in the value).
786 int get_proc_field(const char *filename
, const char *pattern
, const char *terminator
, char **field
) {
787 _cleanup_free_
char *status
= NULL
;
797 r
= read_full_file(filename
, &status
, NULL
);
807 t
= strstr(t
, pattern
);
811 /* Check that pattern occurs in beginning of line. */
812 pattern_ok
= (t
== status
|| t
[-1] == '\n');
814 t
+= strlen(pattern
);
816 } while (!pattern_ok
);
818 t
+= strspn(t
, " \t");
827 t
+= strspn(t
, " \t");
829 /* Also skip zeros, because when this is used for
830 * capabilities, we don't want the zeros. This way the
831 * same capability set always maps to the same string,
832 * irrespective of the total capability set size. For
833 * other numbers it shouldn't matter. */
835 /* Back off one char if there's nothing but whitespace
837 if (!*t
|| isspace(*t
))
841 len
= strcspn(t
, terminator
);