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/>.
24 #include "alloc-util.h"
30 #include "hexdecoct.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "random-util.h"
34 #include "stdio-util.h"
35 #include "string-util.h"
37 #include "umask-util.h"
41 int write_string_stream(FILE *f
, const char *line
, bool enforce_newline
) {
47 if (enforce_newline
&& !endswith(line
, "\n"))
50 return fflush_and_check(f
);
53 static int write_string_file_atomic(const char *fn
, const char *line
, bool enforce_newline
) {
54 _cleanup_fclose_
FILE *f
= NULL
;
55 _cleanup_free_
char *p
= NULL
;
61 r
= fopen_temporary(fn
, &f
, &p
);
65 (void) fchmod_umask(fileno(f
), 0644);
67 r
= write_string_stream(f
, line
, enforce_newline
);
69 if (rename(p
, fn
) < 0)
79 int write_string_file(const char *fn
, const char *line
, WriteStringFileFlags flags
) {
80 _cleanup_fclose_
FILE *f
= NULL
;
86 if (flags
& WRITE_STRING_FILE_ATOMIC
) {
87 assert(flags
& WRITE_STRING_FILE_CREATE
);
89 r
= write_string_file_atomic(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
96 if (flags
& WRITE_STRING_FILE_CREATE
) {
105 /* We manually build our own version of fopen(..., "we") that
106 * works without O_CREAT */
107 fd
= open(fn
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
113 f
= fdopen(fd
, "we");
121 r
= write_string_stream(f
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
128 if (!(flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
))
133 /* OK, the operation failed, but let's see if the right
134 * contents in place already. If so, eat up the error. */
136 q
= verify_file(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
143 int read_one_line_file(const char *fn
, char **line
) {
144 _cleanup_fclose_
FILE *f
= NULL
;
145 char t
[LINE_MAX
], *c
;
154 if (!fgets(t
, sizeof(t
), f
)) {
157 return errno
? -errno
: -EIO
;
171 int verify_file(const char *fn
, const char *blob
, bool accept_extra_nl
) {
172 _cleanup_fclose_
FILE *f
= NULL
;
173 _cleanup_free_
char *buf
= NULL
;
181 if (accept_extra_nl
&& endswith(blob
, "\n"))
182 accept_extra_nl
= false;
184 buf
= malloc(l
+ accept_extra_nl
+ 1);
192 /* We try to read one byte more than we need, so that we know whether we hit eof */
194 k
= fread(buf
, 1, l
+ accept_extra_nl
+ 1, f
);
196 return errno
> 0 ? -errno
: -EIO
;
198 if (k
!= l
&& k
!= l
+ accept_extra_nl
)
200 if (memcmp(buf
, blob
, l
) != 0)
202 if (k
> l
&& buf
[l
] != '\n')
208 int read_full_stream(FILE *f
, char **contents
, size_t *size
) {
210 _cleanup_free_
char *buf
= NULL
;
216 if (fstat(fileno(f
), &st
) < 0)
221 if (S_ISREG(st
.st_mode
)) {
224 if (st
.st_size
> 4*1024*1024)
227 /* Start with the right file size, but be prepared for
228 * files from /proc which generally report a file size
239 t
= realloc(buf
, n
+1);
244 k
= fread(buf
+ l
, 1, n
- l
, f
);
263 buf
= NULL
; /* do not free */
271 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
272 _cleanup_fclose_
FILE *f
= NULL
;
281 return read_full_stream(f
, contents
, size
);
284 static int parse_env_file_internal(
288 int (*push
) (const char *filename
, unsigned line
,
289 const char *key
, char *value
, void *userdata
, int *n_pushed
),
293 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
294 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;
295 char *p
, *value
= NULL
;
306 SINGLE_QUOTE_VALUE_ESCAPE
,
308 DOUBLE_QUOTE_VALUE_ESCAPE
,
316 r
= read_full_stream(f
, &contents
, NULL
);
318 r
= read_full_file(fname
, &contents
, NULL
);
322 for (p
= contents
; *p
; p
++) {
328 if (strchr(COMMENTS
, c
))
330 else if (!strchr(WHITESPACE
, c
)) {
332 last_key_whitespace
= (size_t) -1;
334 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
344 if (strchr(newline
, c
)) {
348 } else if (c
== '=') {
350 last_value_whitespace
= (size_t) -1;
352 if (!strchr(WHITESPACE
, c
))
353 last_key_whitespace
= (size_t) -1;
354 else if (last_key_whitespace
== (size_t) -1)
355 last_key_whitespace
= n_key
;
357 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
368 if (strchr(newline
, c
)) {
376 /* strip trailing whitespace from key */
377 if (last_key_whitespace
!= (size_t) -1)
378 key
[last_key_whitespace
] = 0;
380 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
386 value_alloc
= n_value
= 0;
388 } else if (c
== '\'')
389 state
= SINGLE_QUOTE_VALUE
;
391 state
= DOUBLE_QUOTE_VALUE
;
393 state
= VALUE_ESCAPE
;
394 else if (!strchr(WHITESPACE
, c
)) {
397 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
402 value
[n_value
++] = c
;
408 if (strchr(newline
, c
)) {
417 /* Chomp off trailing whitespace from value */
418 if (last_value_whitespace
!= (size_t) -1)
419 value
[last_value_whitespace
] = 0;
421 /* strip trailing whitespace from key */
422 if (last_key_whitespace
!= (size_t) -1)
423 key
[last_key_whitespace
] = 0;
425 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
431 value_alloc
= n_value
= 0;
433 } else if (c
== '\\') {
434 state
= VALUE_ESCAPE
;
435 last_value_whitespace
= (size_t) -1;
437 if (!strchr(WHITESPACE
, c
))
438 last_value_whitespace
= (size_t) -1;
439 else if (last_value_whitespace
== (size_t) -1)
440 last_value_whitespace
= n_value
;
442 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
447 value
[n_value
++] = c
;
455 if (!strchr(newline
, c
)) {
456 /* Escaped newlines we eat up entirely */
457 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
462 value
[n_value
++] = c
;
466 case SINGLE_QUOTE_VALUE
:
470 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
472 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
477 value
[n_value
++] = c
;
482 case SINGLE_QUOTE_VALUE_ESCAPE
:
483 state
= SINGLE_QUOTE_VALUE
;
485 if (!strchr(newline
, c
)) {
486 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
491 value
[n_value
++] = c
;
495 case DOUBLE_QUOTE_VALUE
:
499 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
501 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
506 value
[n_value
++] = c
;
511 case DOUBLE_QUOTE_VALUE_ESCAPE
:
512 state
= DOUBLE_QUOTE_VALUE
;
514 if (!strchr(newline
, c
)) {
515 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
520 value
[n_value
++] = c
;
526 state
= COMMENT_ESCAPE
;
527 else if (strchr(newline
, c
)) {
539 if (state
== PRE_VALUE
||
541 state
== VALUE_ESCAPE
||
542 state
== SINGLE_QUOTE_VALUE
||
543 state
== SINGLE_QUOTE_VALUE_ESCAPE
||
544 state
== DOUBLE_QUOTE_VALUE
||
545 state
== DOUBLE_QUOTE_VALUE_ESCAPE
) {
553 if (last_value_whitespace
!= (size_t) -1)
554 value
[last_value_whitespace
] = 0;
556 /* strip trailing whitespace from key */
557 if (last_key_whitespace
!= (size_t) -1)
558 key
[last_key_whitespace
] = 0;
560 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
572 static int parse_env_file_push(
573 const char *filename
, unsigned line
,
574 const char *key
, char *value
,
579 va_list aq
, *ap
= userdata
;
581 if (!utf8_is_valid(key
)) {
582 _cleanup_free_
char *p
;
584 p
= utf8_escape_invalid(key
);
585 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename
), line
, p
);
589 if (value
&& !utf8_is_valid(value
)) {
590 _cleanup_free_
char *p
;
592 p
= utf8_escape_invalid(value
);
593 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, p
);
599 while ((k
= va_arg(aq
, const char *))) {
602 v
= va_arg(aq
, char **);
624 const char *newline
, ...) {
632 va_start(ap
, newline
);
633 r
= parse_env_file_internal(NULL
, fname
, newline
, parse_env_file_push
, &ap
, &n_pushed
);
636 return r
< 0 ? r
: n_pushed
;
639 static int load_env_file_push(
640 const char *filename
, unsigned line
,
641 const char *key
, char *value
,
644 char ***m
= userdata
;
648 if (!utf8_is_valid(key
)) {
649 _cleanup_free_
char *t
= utf8_escape_invalid(key
);
651 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename
), line
, t
);
655 if (value
&& !utf8_is_valid(value
)) {
656 _cleanup_free_
char *t
= utf8_escape_invalid(value
);
658 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, t
);
662 p
= strjoin(key
, "=", strempty(value
), NULL
);
666 r
= strv_consume(m
, p
);
677 int load_env_file(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
684 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push
, &m
, NULL
);
694 static int load_env_file_push_pairs(
695 const char *filename
, unsigned line
,
696 const char *key
, char *value
,
699 char ***m
= userdata
;
702 if (!utf8_is_valid(key
)) {
703 _cleanup_free_
char *t
= utf8_escape_invalid(key
);
705 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename
), line
, t
);
709 if (value
&& !utf8_is_valid(value
)) {
710 _cleanup_free_
char *t
= utf8_escape_invalid(value
);
712 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, t
);
716 r
= strv_extend(m
, key
);
721 r
= strv_extend(m
, "");
725 r
= strv_push(m
, value
);
736 int load_env_file_pairs(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
743 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push_pairs
, &m
, NULL
);
753 static void write_env_var(FILE *f
, const char *v
) {
765 fwrite(v
, 1, p
-v
, f
);
767 if (string_has_cc(p
, NULL
) || chars_intersect(p
, WHITESPACE SHELL_NEED_QUOTES
)) {
771 if (strchr(SHELL_NEED_ESCAPE
, *p
))
784 int write_env_file(const char *fname
, char **l
) {
785 _cleanup_fclose_
FILE *f
= NULL
;
786 _cleanup_free_
char *p
= NULL
;
792 r
= fopen_temporary(fname
, &f
, &p
);
796 fchmod_umask(fileno(f
), 0644);
799 write_env_var(f
, *i
);
801 r
= fflush_and_check(f
);
803 if (rename(p
, fname
) >= 0)
813 int executable_is_script(const char *path
, char **interpreter
) {
815 _cleanup_free_
char *line
= NULL
;
821 r
= read_one_line_file(path
, &line
);
825 if (!startswith(line
, "#!"))
828 ans
= strstrip(line
+ 2);
829 len
= strcspn(ans
, " \t");
834 ans
= strndup(ans
, len
);
843 * Retrieve one field from a file like /proc/self/status. pattern
844 * should not include whitespace or the delimiter (':'). pattern matches only
845 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
846 * zeros after the ':' will be skipped. field must be freed afterwards.
847 * terminator specifies the terminating characters of the field value (not
848 * included in the value).
850 int get_proc_field(const char *filename
, const char *pattern
, const char *terminator
, char **field
) {
851 _cleanup_free_
char *status
= NULL
;
861 r
= read_full_file(filename
, &status
, NULL
);
871 t
= strstr(t
, pattern
);
875 /* Check that pattern occurs in beginning of line. */
876 pattern_ok
= (t
== status
|| t
[-1] == '\n');
878 t
+= strlen(pattern
);
880 } while (!pattern_ok
);
882 t
+= strspn(t
, " \t");
891 t
+= strspn(t
, " \t");
893 /* Also skip zeros, because when this is used for
894 * capabilities, we don't want the zeros. This way the
895 * same capability set always maps to the same string,
896 * irrespective of the total capability set size. For
897 * other numbers it shouldn't matter. */
899 /* Back off one char if there's nothing but whitespace
901 if (!*t
|| isspace(*t
))
905 len
= strcspn(t
, terminator
);
915 DIR *xopendirat(int fd
, const char *name
, int flags
) {
919 assert(!(flags
& O_CREAT
));
921 nfd
= openat(fd
, name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|flags
, 0);
934 static int search_and_fopen_internal(const char *path
, const char *mode
, const char *root
, char **search
, FILE **_f
) {
941 if (!path_strv_resolve_uniq(search
, root
))
944 STRV_FOREACH(i
, search
) {
945 _cleanup_free_
char *p
= NULL
;
949 p
= strjoin(root
, *i
, "/", path
, NULL
);
951 p
= strjoin(*i
, "/", path
, NULL
);
968 int search_and_fopen(const char *path
, const char *mode
, const char *root
, const char **search
, FILE **_f
) {
969 _cleanup_strv_free_
char **copy
= NULL
;
975 if (path_is_absolute(path
)) {
978 f
= fopen(path
, mode
);
987 copy
= strv_copy((char**) search
);
991 return search_and_fopen_internal(path
, mode
, root
, copy
, _f
);
994 int search_and_fopen_nulstr(const char *path
, const char *mode
, const char *root
, const char *search
, FILE **_f
) {
995 _cleanup_strv_free_
char **s
= NULL
;
997 if (path_is_absolute(path
)) {
1000 f
= fopen(path
, mode
);
1009 s
= strv_split_nulstr(search
);
1013 return search_and_fopen_internal(path
, mode
, root
, s
, _f
);
1016 int fopen_temporary(const char *path
, FILE **_f
, char **_temp_path
) {
1025 r
= tempfn_xxxxxx(path
, NULL
, &t
);
1029 fd
= mkostemp_safe(t
, O_WRONLY
|O_CLOEXEC
);
1035 f
= fdopen(fd
, "we");
1049 int fflush_and_check(FILE *f
) {
1056 return errno
? -errno
: -EIO
;
1061 /* This is much like like mkostemp() but is subject to umask(). */
1062 int mkostemp_safe(char *pattern
, int flags
) {
1063 _cleanup_umask_ mode_t u
;
1070 fd
= mkostemp(pattern
, flags
);
1077 int open_tmpfile(const char *path
, int flags
) {
1084 /* Try O_TMPFILE first, if it is supported */
1085 fd
= open(path
, flags
|O_TMPFILE
|O_EXCL
, S_IRUSR
|S_IWUSR
);
1090 /* Fall back to unguessable name + unlinking */
1091 p
= strjoina(path
, "/systemd-tmp-XXXXXX");
1093 fd
= mkostemp_safe(p
, flags
);
1101 int tempfn_xxxxxx(const char *p
, const char *extra
, char **ret
) {
1113 * /foo/bar/.#<extra>waldoXXXXXX
1117 if (!filename_is_valid(fn
))
1123 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 6 + 1);
1127 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
), "XXXXXX");
1129 *ret
= path_kill_slashes(t
);
1133 int tempfn_random(const char *p
, const char *extra
, char **ret
) {
1147 * /foo/bar/.#<extra>waldobaa2a261115984a9
1151 if (!filename_is_valid(fn
))
1157 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 16 + 1);
1161 x
= stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
);
1164 for (i
= 0; i
< 16; i
++) {
1165 *(x
++) = hexchar(u
& 0xF);
1171 *ret
= path_kill_slashes(t
);
1175 int tempfn_random_child(const char *p
, const char *extra
, char **ret
) {
1186 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1192 t
= new(char, strlen(p
) + 3 + strlen(extra
) + 16 + 1);
1196 x
= stpcpy(stpcpy(stpcpy(t
, p
), "/.#"), extra
);
1199 for (i
= 0; i
< 16; i
++) {
1200 *(x
++) = hexchar(u
& 0xF);
1206 *ret
= path_kill_slashes(t
);
1210 int write_timestamp_file_atomic(const char *fn
, usec_t n
) {
1211 char ln
[DECIMAL_STR_MAX(n
)+2];
1213 /* Creates a "timestamp" file, that contains nothing but a
1214 * usec_t timestamp, formatted in ASCII. */
1216 if (n
<= 0 || n
>= USEC_INFINITY
)
1219 xsprintf(ln
, USEC_FMT
"\n", n
);
1221 return write_string_file(fn
, ln
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
1224 int read_timestamp_file(const char *fn
, usec_t
*ret
) {
1225 _cleanup_free_
char *ln
= NULL
;
1229 r
= read_one_line_file(fn
, &ln
);
1233 r
= safe_atou64(ln
, &t
);
1237 if (t
<= 0 || t
>= (uint64_t) USEC_INFINITY
)