1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <stdio_ext.h>
31 #include <sys/types.h>
34 #include "alloc-util.h"
42 #include "hexdecoct.h"
46 #include "parse-util.h"
47 #include "path-util.h"
48 #include "process-util.h"
49 #include "random-util.h"
50 #include "stdio-util.h"
51 #include "string-util.h"
53 #include "time-util.h"
54 #include "umask-util.h"
57 #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
59 int write_string_stream_ts(
62 WriteStringFileFlags flags
,
63 struct timespec
*ts
) {
73 needs_nl
= !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
) && !endswith(line
, "\n");
75 if (needs_nl
&& (flags
& WRITE_STRING_FILE_DISABLE_BUFFER
)) {
76 /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
77 * that the write goes out in one go, instead of two */
79 line
= strjoina(line
, "\n");
83 if (fputs(line
, f
) == EOF
)
87 if (fputc('\n', f
) == EOF
)
91 struct timespec twice
[2] = {*ts
, *ts
};
93 if (futimens(fileno(f
), twice
) < 0)
97 if (flags
& WRITE_STRING_FILE_SYNC
)
98 return fflush_sync_and_check(f
);
100 return fflush_and_check(f
);
103 static int write_string_file_atomic(
106 WriteStringFileFlags flags
,
107 struct timespec
*ts
) {
109 _cleanup_fclose_
FILE *f
= NULL
;
110 _cleanup_free_
char *p
= NULL
;
116 r
= fopen_temporary(fn
, &f
, &p
);
120 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
121 (void) fchmod_umask(fileno(f
), 0644);
123 r
= write_string_stream_ts(f
, line
, flags
, ts
);
127 if (rename(p
, fn
) < 0) {
139 int write_string_file_ts(
142 WriteStringFileFlags flags
,
143 struct timespec
*ts
) {
145 _cleanup_fclose_
FILE *f
= NULL
;
151 /* We don't know how to verify whether the file contents was already on-disk. */
152 assert(!((flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
) && (flags
& WRITE_STRING_FILE_SYNC
)));
154 if (flags
& WRITE_STRING_FILE_ATOMIC
) {
155 assert(flags
& WRITE_STRING_FILE_CREATE
);
157 r
= write_string_file_atomic(fn
, line
, flags
, ts
);
165 if (flags
& WRITE_STRING_FILE_CREATE
) {
174 /* We manually build our own version of fopen(..., "we") that
175 * works without O_CREAT */
176 fd
= open(fn
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
182 f
= fdopen(fd
, "we");
190 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
192 if (flags
& WRITE_STRING_FILE_DISABLE_BUFFER
)
193 setvbuf(f
, NULL
, _IONBF
, 0);
195 r
= write_string_stream_ts(f
, line
, flags
, ts
);
202 if (!(flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
))
207 /* OK, the operation failed, but let's see if the right
208 * contents in place already. If so, eat up the error. */
210 q
= verify_file(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
217 int read_one_line_file(const char *fn
, char **line
) {
218 _cleanup_fclose_
FILE *f
= NULL
;
228 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
230 r
= read_line(f
, LONG_LINE_MAX
, line
);
231 return r
< 0 ? r
: 0;
234 int verify_file(const char *fn
, const char *blob
, bool accept_extra_nl
) {
235 _cleanup_fclose_
FILE *f
= NULL
;
236 _cleanup_free_
char *buf
= NULL
;
244 if (accept_extra_nl
&& endswith(blob
, "\n"))
245 accept_extra_nl
= false;
247 buf
= malloc(l
+ accept_extra_nl
+ 1);
255 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
257 /* We try to read one byte more than we need, so that we know whether we hit eof */
259 k
= fread(buf
, 1, l
+ accept_extra_nl
+ 1, f
);
261 return errno
> 0 ? -errno
: -EIO
;
263 if (k
!= l
&& k
!= l
+ accept_extra_nl
)
265 if (memcmp(buf
, blob
, l
) != 0)
267 if (k
> l
&& buf
[l
] != '\n')
273 int read_full_stream(FILE *f
, char **contents
, size_t *size
) {
275 _cleanup_free_
char *buf
= NULL
;
281 if (fstat(fileno(f
), &st
) < 0)
286 if (S_ISREG(st
.st_mode
)) {
289 if (st
.st_size
> READ_FULL_BYTES_MAX
)
292 /* Start with the right file size, but be prepared for files from /proc which generally report a file
293 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
294 * already makes us notice the EOF. */
304 t
= realloc(buf
, n
+ 1);
310 k
= fread(buf
+ l
, 1, n
- l
, f
);
315 return errno
> 0 ? -errno
: -EIO
;
320 /* We aren't expecting fread() to return a short read outside
321 * of (error && eof), assert buffer is full and enlarge buffer.
326 if (n
>= READ_FULL_BYTES_MAX
)
329 n
= MIN(n
* 2, READ_FULL_BYTES_MAX
);
334 buf
= NULL
; /* do not free */
342 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
343 _cleanup_fclose_
FILE *f
= NULL
;
352 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
354 return read_full_stream(f
, contents
, size
);
357 static int parse_env_file_internal(
361 int (*push
) (const char *filename
, unsigned line
,
362 const char *key
, char *value
, void *userdata
, int *n_pushed
),
366 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
367 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;
368 char *p
, *value
= NULL
;
379 SINGLE_QUOTE_VALUE_ESCAPE
,
381 DOUBLE_QUOTE_VALUE_ESCAPE
,
389 r
= read_full_stream(f
, &contents
, NULL
);
391 r
= read_full_file(fname
, &contents
, NULL
);
395 for (p
= contents
; *p
; p
++) {
401 if (strchr(COMMENTS
, c
))
403 else if (!strchr(WHITESPACE
, c
)) {
405 last_key_whitespace
= (size_t) -1;
407 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
417 if (strchr(newline
, c
)) {
421 } else if (c
== '=') {
423 last_value_whitespace
= (size_t) -1;
425 if (!strchr(WHITESPACE
, c
))
426 last_key_whitespace
= (size_t) -1;
427 else if (last_key_whitespace
== (size_t) -1)
428 last_key_whitespace
= n_key
;
430 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
441 if (strchr(newline
, c
)) {
449 /* strip trailing whitespace from key */
450 if (last_key_whitespace
!= (size_t) -1)
451 key
[last_key_whitespace
] = 0;
453 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
459 value_alloc
= n_value
= 0;
461 } else if (c
== '\'')
462 state
= SINGLE_QUOTE_VALUE
;
464 state
= DOUBLE_QUOTE_VALUE
;
466 state
= VALUE_ESCAPE
;
467 else if (!strchr(WHITESPACE
, c
)) {
470 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
475 value
[n_value
++] = c
;
481 if (strchr(newline
, c
)) {
490 /* Chomp off trailing whitespace from value */
491 if (last_value_whitespace
!= (size_t) -1)
492 value
[last_value_whitespace
] = 0;
494 /* strip trailing whitespace from key */
495 if (last_key_whitespace
!= (size_t) -1)
496 key
[last_key_whitespace
] = 0;
498 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
504 value_alloc
= n_value
= 0;
506 } else if (c
== '\\') {
507 state
= VALUE_ESCAPE
;
508 last_value_whitespace
= (size_t) -1;
510 if (!strchr(WHITESPACE
, c
))
511 last_value_whitespace
= (size_t) -1;
512 else if (last_value_whitespace
== (size_t) -1)
513 last_value_whitespace
= n_value
;
515 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
520 value
[n_value
++] = c
;
528 if (!strchr(newline
, c
)) {
529 /* Escaped newlines we eat up entirely */
530 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
535 value
[n_value
++] = c
;
539 case SINGLE_QUOTE_VALUE
:
543 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
545 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
550 value
[n_value
++] = c
;
555 case SINGLE_QUOTE_VALUE_ESCAPE
:
556 state
= SINGLE_QUOTE_VALUE
;
558 if (!strchr(newline
, c
)) {
559 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
564 value
[n_value
++] = c
;
568 case DOUBLE_QUOTE_VALUE
:
572 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
574 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
579 value
[n_value
++] = c
;
584 case DOUBLE_QUOTE_VALUE_ESCAPE
:
585 state
= DOUBLE_QUOTE_VALUE
;
587 if (!strchr(newline
, c
)) {
588 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
593 value
[n_value
++] = c
;
599 state
= COMMENT_ESCAPE
;
600 else if (strchr(newline
, c
)) {
617 SINGLE_QUOTE_VALUE_ESCAPE
,
619 DOUBLE_QUOTE_VALUE_ESCAPE
)) {
627 if (last_value_whitespace
!= (size_t) -1)
628 value
[last_value_whitespace
] = 0;
630 /* strip trailing whitespace from key */
631 if (last_key_whitespace
!= (size_t) -1)
632 key
[last_key_whitespace
] = 0;
634 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
646 static int check_utf8ness_and_warn(
647 const char *filename
, unsigned line
,
648 const char *key
, char *value
) {
650 if (!utf8_is_valid(key
)) {
651 _cleanup_free_
char *p
= NULL
;
653 p
= utf8_escape_invalid(key
);
654 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename
), line
, p
);
658 if (value
&& !utf8_is_valid(value
)) {
659 _cleanup_free_
char *p
= NULL
;
661 p
= utf8_escape_invalid(value
);
662 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, p
);
669 static int parse_env_file_push(
670 const char *filename
, unsigned line
,
671 const char *key
, char *value
,
676 va_list aq
, *ap
= userdata
;
679 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
685 while ((k
= va_arg(aq
, const char *))) {
688 v
= va_arg(aq
, char **);
710 const char *newline
, ...) {
718 va_start(ap
, newline
);
719 r
= parse_env_file_internal(NULL
, fname
, newline
, parse_env_file_push
, &ap
, &n_pushed
);
722 return r
< 0 ? r
: n_pushed
;
725 static int load_env_file_push(
726 const char *filename
, unsigned line
,
727 const char *key
, char *value
,
730 char ***m
= userdata
;
734 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
738 p
= strjoin(key
, "=", value
);
742 r
= strv_env_replace(m
, p
);
755 int load_env_file(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
762 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push
, &m
, NULL
);
772 static int load_env_file_push_pairs(
773 const char *filename
, unsigned line
,
774 const char *key
, char *value
,
777 char ***m
= userdata
;
780 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
784 r
= strv_extend(m
, key
);
789 r
= strv_extend(m
, "");
793 r
= strv_push(m
, value
);
804 int load_env_file_pairs(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
811 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push_pairs
, &m
, NULL
);
821 static int merge_env_file_push(
822 const char *filename
, unsigned line
,
823 const char *key
, char *value
,
827 char ***env
= userdata
;
828 char *expanded_value
;
833 log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename
), line
, key
);
837 if (!env_name_is_valid(key
)) {
838 log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename
), line
, key
);
843 expanded_value
= replace_env(value
, *env
,
844 REPLACE_ENV_USE_ENVIRONMENT
|
845 REPLACE_ENV_ALLOW_BRACELESS
|
846 REPLACE_ENV_ALLOW_EXTENDED
);
850 free_and_replace(value
, expanded_value
);
852 return load_env_file_push(filename
, line
, key
, value
, env
, n_pushed
);
860 /* NOTE: this function supports braceful and braceless variable expansions,
861 * plus "extended" substitutions, unlike other exported parsing functions.
864 return parse_env_file_internal(f
, fname
, NEWLINE
, merge_env_file_push
, env
, NULL
);
867 static void write_env_var(FILE *f
, const char *v
) {
873 fputs_unlocked(v
, f
);
874 fputc_unlocked('\n', f
);
879 fwrite_unlocked(v
, 1, p
-v
, f
);
881 if (string_has_cc(p
, NULL
) || chars_intersect(p
, WHITESPACE SHELL_NEED_QUOTES
)) {
882 fputc_unlocked('\"', f
);
885 if (strchr(SHELL_NEED_ESCAPE
, *p
))
886 fputc_unlocked('\\', f
);
888 fputc_unlocked(*p
, f
);
891 fputc_unlocked('\"', f
);
893 fputs_unlocked(p
, f
);
895 fputc_unlocked('\n', f
);
898 int write_env_file(const char *fname
, char **l
) {
899 _cleanup_fclose_
FILE *f
= NULL
;
900 _cleanup_free_
char *p
= NULL
;
906 r
= fopen_temporary(fname
, &f
, &p
);
910 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
911 (void) fchmod_umask(fileno(f
), 0644);
914 write_env_var(f
, *i
);
916 r
= fflush_and_check(f
);
918 if (rename(p
, fname
) >= 0)
928 int executable_is_script(const char *path
, char **interpreter
) {
929 _cleanup_free_
char *line
= NULL
;
936 r
= read_one_line_file(path
, &line
);
937 if (r
== -ENOBUFS
) /* First line overly long? if so, then it's not a script */
942 if (!startswith(line
, "#!"))
945 ans
= strstrip(line
+ 2);
946 len
= strcspn(ans
, " \t");
951 ans
= strndup(ans
, len
);
960 * Retrieve one field from a file like /proc/self/status. pattern
961 * should not include whitespace or the delimiter (':'). pattern matches only
962 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
963 * zeros after the ':' will be skipped. field must be freed afterwards.
964 * terminator specifies the terminating characters of the field value (not
965 * included in the value).
967 int get_proc_field(const char *filename
, const char *pattern
, const char *terminator
, char **field
) {
968 _cleanup_free_
char *status
= NULL
;
978 r
= read_full_file(filename
, &status
, NULL
);
988 t
= strstr(t
, pattern
);
992 /* Check that pattern occurs in beginning of line. */
993 pattern_ok
= (t
== status
|| t
[-1] == '\n');
995 t
+= strlen(pattern
);
997 } while (!pattern_ok
);
999 t
+= strspn(t
, " \t");
1003 } while (*t
!= ':');
1008 t
+= strspn(t
, " \t");
1010 /* Also skip zeros, because when this is used for
1011 * capabilities, we don't want the zeros. This way the
1012 * same capability set always maps to the same string,
1013 * irrespective of the total capability set size. For
1014 * other numbers it shouldn't matter. */
1015 t
+= strspn(t
, "0");
1016 /* Back off one char if there's nothing but whitespace
1018 if (!*t
|| isspace(*t
))
1022 len
= strcspn(t
, terminator
);
1024 f
= strndup(t
, len
);
1032 DIR *xopendirat(int fd
, const char *name
, int flags
) {
1036 assert(!(flags
& O_CREAT
));
1038 nfd
= openat(fd
, name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|flags
, 0);
1051 static int search_and_fopen_internal(const char *path
, const char *mode
, const char *root
, char **search
, FILE **_f
) {
1058 if (!path_strv_resolve_uniq(search
, root
))
1061 STRV_FOREACH(i
, search
) {
1062 _cleanup_free_
char *p
= NULL
;
1066 p
= strjoin(root
, *i
, "/", path
);
1068 p
= strjoin(*i
, "/", path
);
1078 if (errno
!= ENOENT
)
1085 int search_and_fopen(const char *path
, const char *mode
, const char *root
, const char **search
, FILE **_f
) {
1086 _cleanup_strv_free_
char **copy
= NULL
;
1092 if (path_is_absolute(path
)) {
1095 f
= fopen(path
, mode
);
1104 copy
= strv_copy((char**) search
);
1108 return search_and_fopen_internal(path
, mode
, root
, copy
, _f
);
1111 int search_and_fopen_nulstr(const char *path
, const char *mode
, const char *root
, const char *search
, FILE **_f
) {
1112 _cleanup_strv_free_
char **s
= NULL
;
1114 if (path_is_absolute(path
)) {
1117 f
= fopen(path
, mode
);
1126 s
= strv_split_nulstr(search
);
1130 return search_and_fopen_internal(path
, mode
, root
, s
, _f
);
1133 int fopen_temporary(const char *path
, FILE **_f
, char **_temp_path
) {
1142 r
= tempfn_xxxxxx(path
, NULL
, &t
);
1146 fd
= mkostemp_safe(t
);
1152 f
= fdopen(fd
, "we");
1166 int fflush_and_check(FILE *f
) {
1173 return errno
> 0 ? -errno
: -EIO
;
1178 int fflush_sync_and_check(FILE *f
) {
1183 r
= fflush_and_check(f
);
1187 if (fsync(fileno(f
)) < 0)
1193 /* This is much like mkostemp() but is subject to umask(). */
1194 int mkostemp_safe(char *pattern
) {
1195 _cleanup_umask_ mode_t u
= 0;
1202 fd
= mkostemp(pattern
, O_CLOEXEC
);
1209 int tempfn_xxxxxx(const char *p
, const char *extra
, char **ret
) {
1221 * /foo/bar/.#<extra>waldoXXXXXX
1225 if (!filename_is_valid(fn
))
1228 extra
= strempty(extra
);
1230 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 6 + 1);
1234 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
), "XXXXXX");
1236 *ret
= path_kill_slashes(t
);
1240 int tempfn_random(const char *p
, const char *extra
, char **ret
) {
1254 * /foo/bar/.#<extra>waldobaa2a261115984a9
1258 if (!filename_is_valid(fn
))
1261 extra
= strempty(extra
);
1263 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 16 + 1);
1267 x
= stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
);
1270 for (i
= 0; i
< 16; i
++) {
1271 *(x
++) = hexchar(u
& 0xF);
1277 *ret
= path_kill_slashes(t
);
1281 int tempfn_random_child(const char *p
, const char *extra
, char **ret
) {
1292 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1301 extra
= strempty(extra
);
1303 t
= new(char, strlen(p
) + 3 + strlen(extra
) + 16 + 1);
1307 x
= stpcpy(stpcpy(stpcpy(t
, p
), "/.#"), extra
);
1310 for (i
= 0; i
< 16; i
++) {
1311 *(x
++) = hexchar(u
& 0xF);
1317 *ret
= path_kill_slashes(t
);
1321 int write_timestamp_file_atomic(const char *fn
, usec_t n
) {
1322 char ln
[DECIMAL_STR_MAX(n
)+2];
1324 /* Creates a "timestamp" file, that contains nothing but a
1325 * usec_t timestamp, formatted in ASCII. */
1327 if (n
<= 0 || n
>= USEC_INFINITY
)
1330 xsprintf(ln
, USEC_FMT
"\n", n
);
1332 return write_string_file(fn
, ln
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
1335 int read_timestamp_file(const char *fn
, usec_t
*ret
) {
1336 _cleanup_free_
char *ln
= NULL
;
1340 r
= read_one_line_file(fn
, &ln
);
1344 r
= safe_atou64(ln
, &t
);
1348 if (t
<= 0 || t
>= (uint64_t) USEC_INFINITY
)
1355 int fputs_with_space(FILE *f
, const char *s
, const char *separator
, bool *space
) {
1360 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1361 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1362 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1363 * element, but not before the first one. */
1373 r
= fputs(separator
, f
);
1384 int open_tmpfile_unlinkable(const char *directory
, int flags
) {
1389 r
= tmp_dir(&directory
);
1394 /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
1396 /* Try O_TMPFILE first, if it is supported */
1397 fd
= open(directory
, flags
|O_TMPFILE
|O_EXCL
, S_IRUSR
|S_IWUSR
);
1401 /* Fall back to unguessable name + unlinking */
1402 p
= strjoina(directory
, "/systemd-tmp-XXXXXX");
1404 fd
= mkostemp_safe(p
);
1413 int open_tmpfile_linkable(const char *target
, int flags
, char **ret_path
) {
1414 _cleanup_free_
char *tmp
= NULL
;
1420 /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
1421 assert((flags
& O_EXCL
) == 0);
1423 /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
1424 * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
1425 * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
1428 _cleanup_free_
char *dn
= NULL
;
1430 dn
= dirname_malloc(target
);
1434 fd
= open(dn
, O_TMPFILE
|flags
, 0640);
1440 log_debug_errno(errno
, "Failed to use O_TMPFILE on %s: %m", dn
);
1443 r
= tempfn_random(target
, NULL
, &tmp
);
1447 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_NOFOLLOW
|O_NOCTTY
|flags
, 0640);
1457 int open_serialization_fd(const char *ident
) {
1460 fd
= memfd_create(ident
, MFD_CLOEXEC
);
1464 path
= getpid_cached() == 1 ? "/run/systemd" : "/tmp";
1465 fd
= open_tmpfile_unlinkable(path
, O_RDWR
|O_CLOEXEC
);
1469 log_debug("Serializing %s to %s.", ident
, path
);
1471 log_debug("Serializing %s to memfd.", ident
);
1476 int link_tmpfile(int fd
, const char *path
, const char *target
) {
1481 /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
1482 * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
1483 * on the directory, and renameat2() is used instead.
1485 * Note that in both cases we will not replace existing files. This is because linkat() does not support this
1486 * operation currently (renameat2() does), and there is no nice way to emulate this. */
1489 if (rename_noreplace(AT_FDCWD
, path
, AT_FDCWD
, target
) < 0)
1492 char proc_fd_path
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd
) + 1];
1494 xsprintf(proc_fd_path
, "/proc/self/fd/%i", fd
);
1496 if (linkat(AT_FDCWD
, proc_fd_path
, AT_FDCWD
, target
, AT_SYMLINK_FOLLOW
) < 0)
1503 int read_nul_string(FILE *f
, char **ret
) {
1504 _cleanup_free_
char *x
= NULL
;
1505 size_t allocated
= 0, n
= 0;
1510 /* Reads a NUL-terminated string from the specified file. */
1515 if (!GREEDY_REALLOC(x
, allocated
, n
+2))
1519 if (c
== 0) /* Terminate at NUL byte */
1524 break; /* Terminate at EOF */
1544 int mkdtemp_malloc(const char *template, char **ret
) {
1550 p
= strdup(template);
1563 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile
);
1565 int read_line(FILE *f
, size_t limit
, char **ret
) {
1566 _cleanup_free_
char *buffer
= NULL
;
1567 size_t n
= 0, allocated
= 0, count
= 0;
1571 /* Something like a bounded version of getline().
1573 * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1576 * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1577 * the number of characters in the returned string). When EOF is hit, 0 is returned.
1579 * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1580 * delimiters. If the limit is hit we fail and return -ENOBUFS.
1582 * If a line shall be skipped ret may be initialized as NULL. */
1585 if (!GREEDY_REALLOC(buffer
, allocated
, 1))
1590 _unused_
_cleanup_(funlockfilep
) FILE *flocked
= f
;
1600 c
= fgetc_unlocked(f
);
1602 /* if we read an error, and have no data to return, then propagate the error */
1603 if (ferror_unlocked(f
) && n
== 0)
1604 return errno
> 0 ? -errno
: -EIO
;
1611 if (IN_SET(c
, '\n', 0)) /* Reached a delimiter */
1615 if (!GREEDY_REALLOC(buffer
, allocated
, n
+ 2))
1618 buffer
[n
] = (char) c
;