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/>.
30 #include <sys/types.h>
33 #include "alloc-util.h"
41 #include "hexdecoct.h"
45 #include "parse-util.h"
46 #include "path-util.h"
47 #include "process-util.h"
48 #include "random-util.h"
49 #include "stdio-util.h"
50 #include "string-util.h"
52 #include "time-util.h"
53 #include "umask-util.h"
56 #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
58 int write_string_stream_ts(
61 WriteStringFileFlags flags
,
62 struct timespec
*ts
) {
68 if (!(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
) && !endswith(line
, "\n"))
72 struct timespec twice
[2] = {*ts
, *ts
};
74 if (futimens(fileno(f
), twice
) < 0)
78 if (flags
& WRITE_STRING_FILE_SYNC
)
79 return fflush_sync_and_check(f
);
81 return fflush_and_check(f
);
84 static int write_string_file_atomic(
87 WriteStringFileFlags flags
,
88 struct timespec
*ts
) {
90 _cleanup_fclose_
FILE *f
= NULL
;
91 _cleanup_free_
char *p
= NULL
;
97 r
= fopen_temporary(fn
, &f
, &p
);
101 (void) fchmod_umask(fileno(f
), 0644);
103 r
= write_string_stream_ts(f
, line
, flags
, ts
);
107 if (rename(p
, fn
) < 0) {
119 int write_string_file_ts(
122 WriteStringFileFlags flags
,
123 struct timespec
*ts
) {
125 _cleanup_fclose_
FILE *f
= NULL
;
131 /* We don't know how to verify whether the file contents was already on-disk. */
132 assert(!((flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
) && (flags
& WRITE_STRING_FILE_SYNC
)));
134 if (flags
& WRITE_STRING_FILE_ATOMIC
) {
135 assert(flags
& WRITE_STRING_FILE_CREATE
);
137 r
= write_string_file_atomic(fn
, line
, flags
, ts
);
145 if (flags
& WRITE_STRING_FILE_CREATE
) {
154 /* We manually build our own version of fopen(..., "we") that
155 * works without O_CREAT */
156 fd
= open(fn
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
162 f
= fdopen(fd
, "we");
170 r
= write_string_stream_ts(f
, line
, flags
, ts
);
177 if (!(flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
))
182 /* OK, the operation failed, but let's see if the right
183 * contents in place already. If so, eat up the error. */
185 q
= verify_file(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
192 int read_one_line_file(const char *fn
, char **line
) {
193 _cleanup_fclose_
FILE *f
= NULL
;
203 r
= read_line(f
, LONG_LINE_MAX
, line
);
204 return r
< 0 ? r
: 0;
207 int verify_file(const char *fn
, const char *blob
, bool accept_extra_nl
) {
208 _cleanup_fclose_
FILE *f
= NULL
;
209 _cleanup_free_
char *buf
= NULL
;
217 if (accept_extra_nl
&& endswith(blob
, "\n"))
218 accept_extra_nl
= false;
220 buf
= malloc(l
+ accept_extra_nl
+ 1);
228 /* We try to read one byte more than we need, so that we know whether we hit eof */
230 k
= fread(buf
, 1, l
+ accept_extra_nl
+ 1, f
);
232 return errno
> 0 ? -errno
: -EIO
;
234 if (k
!= l
&& k
!= l
+ accept_extra_nl
)
236 if (memcmp(buf
, blob
, l
) != 0)
238 if (k
> l
&& buf
[l
] != '\n')
244 int read_full_stream(FILE *f
, char **contents
, size_t *size
) {
246 _cleanup_free_
char *buf
= NULL
;
252 if (fstat(fileno(f
), &st
) < 0)
257 if (S_ISREG(st
.st_mode
)) {
260 if (st
.st_size
> READ_FULL_BYTES_MAX
)
263 /* Start with the right file size, but be prepared for files from /proc which generally report a file
264 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
265 * already makes us notice the EOF. */
275 t
= realloc(buf
, n
+ 1);
281 k
= fread(buf
+ l
, 1, n
- l
, f
);
286 return errno
> 0 ? -errno
: -EIO
;
291 /* We aren't expecting fread() to return a short read outside
292 * of (error && eof), assert buffer is full and enlarge buffer.
297 if (n
>= READ_FULL_BYTES_MAX
)
300 n
= MIN(n
* 2, READ_FULL_BYTES_MAX
);
305 buf
= NULL
; /* do not free */
313 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
314 _cleanup_fclose_
FILE *f
= NULL
;
323 return read_full_stream(f
, contents
, size
);
326 static int parse_env_file_internal(
330 int (*push
) (const char *filename
, unsigned line
,
331 const char *key
, char *value
, void *userdata
, int *n_pushed
),
335 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
336 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;
337 char *p
, *value
= NULL
;
348 SINGLE_QUOTE_VALUE_ESCAPE
,
350 DOUBLE_QUOTE_VALUE_ESCAPE
,
358 r
= read_full_stream(f
, &contents
, NULL
);
360 r
= read_full_file(fname
, &contents
, NULL
);
364 for (p
= contents
; *p
; p
++) {
370 if (strchr(COMMENTS
, c
))
372 else if (!strchr(WHITESPACE
, c
)) {
374 last_key_whitespace
= (size_t) -1;
376 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
386 if (strchr(newline
, c
)) {
390 } else if (c
== '=') {
392 last_value_whitespace
= (size_t) -1;
394 if (!strchr(WHITESPACE
, c
))
395 last_key_whitespace
= (size_t) -1;
396 else if (last_key_whitespace
== (size_t) -1)
397 last_key_whitespace
= n_key
;
399 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
410 if (strchr(newline
, c
)) {
418 /* strip trailing whitespace from key */
419 if (last_key_whitespace
!= (size_t) -1)
420 key
[last_key_whitespace
] = 0;
422 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
428 value_alloc
= n_value
= 0;
430 } else if (c
== '\'')
431 state
= SINGLE_QUOTE_VALUE
;
433 state
= DOUBLE_QUOTE_VALUE
;
435 state
= VALUE_ESCAPE
;
436 else if (!strchr(WHITESPACE
, c
)) {
439 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
444 value
[n_value
++] = c
;
450 if (strchr(newline
, c
)) {
459 /* Chomp off trailing whitespace from value */
460 if (last_value_whitespace
!= (size_t) -1)
461 value
[last_value_whitespace
] = 0;
463 /* strip trailing whitespace from key */
464 if (last_key_whitespace
!= (size_t) -1)
465 key
[last_key_whitespace
] = 0;
467 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
473 value_alloc
= n_value
= 0;
475 } else if (c
== '\\') {
476 state
= VALUE_ESCAPE
;
477 last_value_whitespace
= (size_t) -1;
479 if (!strchr(WHITESPACE
, c
))
480 last_value_whitespace
= (size_t) -1;
481 else if (last_value_whitespace
== (size_t) -1)
482 last_value_whitespace
= n_value
;
484 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
489 value
[n_value
++] = c
;
497 if (!strchr(newline
, c
)) {
498 /* Escaped newlines we eat up entirely */
499 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
504 value
[n_value
++] = c
;
508 case SINGLE_QUOTE_VALUE
:
512 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
514 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
519 value
[n_value
++] = c
;
524 case SINGLE_QUOTE_VALUE_ESCAPE
:
525 state
= SINGLE_QUOTE_VALUE
;
527 if (!strchr(newline
, c
)) {
528 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
533 value
[n_value
++] = c
;
537 case DOUBLE_QUOTE_VALUE
:
541 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
543 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
548 value
[n_value
++] = c
;
553 case DOUBLE_QUOTE_VALUE_ESCAPE
:
554 state
= DOUBLE_QUOTE_VALUE
;
556 if (!strchr(newline
, c
)) {
557 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
562 value
[n_value
++] = c
;
568 state
= COMMENT_ESCAPE
;
569 else if (strchr(newline
, c
)) {
586 SINGLE_QUOTE_VALUE_ESCAPE
,
588 DOUBLE_QUOTE_VALUE_ESCAPE
)) {
596 if (last_value_whitespace
!= (size_t) -1)
597 value
[last_value_whitespace
] = 0;
599 /* strip trailing whitespace from key */
600 if (last_key_whitespace
!= (size_t) -1)
601 key
[last_key_whitespace
] = 0;
603 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
615 static int check_utf8ness_and_warn(
616 const char *filename
, unsigned line
,
617 const char *key
, char *value
) {
619 if (!utf8_is_valid(key
)) {
620 _cleanup_free_
char *p
= NULL
;
622 p
= utf8_escape_invalid(key
);
623 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename
), line
, p
);
627 if (value
&& !utf8_is_valid(value
)) {
628 _cleanup_free_
char *p
= NULL
;
630 p
= utf8_escape_invalid(value
);
631 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, p
);
638 static int parse_env_file_push(
639 const char *filename
, unsigned line
,
640 const char *key
, char *value
,
645 va_list aq
, *ap
= userdata
;
648 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
654 while ((k
= va_arg(aq
, const char *))) {
657 v
= va_arg(aq
, char **);
679 const char *newline
, ...) {
687 va_start(ap
, newline
);
688 r
= parse_env_file_internal(NULL
, fname
, newline
, parse_env_file_push
, &ap
, &n_pushed
);
691 return r
< 0 ? r
: n_pushed
;
694 static int load_env_file_push(
695 const char *filename
, unsigned line
,
696 const char *key
, char *value
,
699 char ***m
= userdata
;
703 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
707 p
= strjoin(key
, "=", value
);
711 r
= strv_env_replace(m
, p
);
724 int load_env_file(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
731 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push
, &m
, NULL
);
741 static int load_env_file_push_pairs(
742 const char *filename
, unsigned line
,
743 const char *key
, char *value
,
746 char ***m
= userdata
;
749 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
753 r
= strv_extend(m
, key
);
758 r
= strv_extend(m
, "");
762 r
= strv_push(m
, value
);
773 int load_env_file_pairs(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
780 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push_pairs
, &m
, NULL
);
790 static int merge_env_file_push(
791 const char *filename
, unsigned line
,
792 const char *key
, char *value
,
796 char ***env
= userdata
;
797 char *expanded_value
;
802 log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename
), line
, key
);
806 if (!env_name_is_valid(key
)) {
807 log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename
), line
, key
);
812 expanded_value
= replace_env(value
, *env
,
813 REPLACE_ENV_USE_ENVIRONMENT
|
814 REPLACE_ENV_ALLOW_BRACELESS
|
815 REPLACE_ENV_ALLOW_EXTENDED
);
819 free_and_replace(value
, expanded_value
);
821 return load_env_file_push(filename
, line
, key
, value
, env
, n_pushed
);
829 /* NOTE: this function supports braceful and braceless variable expansions,
830 * plus "extended" substitutions, unlike other exported parsing functions.
833 return parse_env_file_internal(f
, fname
, NEWLINE
, merge_env_file_push
, env
, NULL
);
836 static void write_env_var(FILE *f
, const char *v
) {
842 fputs_unlocked(v
, f
);
843 fputc_unlocked('\n', f
);
848 fwrite_unlocked(v
, 1, p
-v
, f
);
850 if (string_has_cc(p
, NULL
) || chars_intersect(p
, WHITESPACE SHELL_NEED_QUOTES
)) {
851 fputc_unlocked('\"', f
);
854 if (strchr(SHELL_NEED_ESCAPE
, *p
))
855 fputc_unlocked('\\', f
);
857 fputc_unlocked(*p
, f
);
860 fputc_unlocked('\"', f
);
862 fputs_unlocked(p
, f
);
864 fputc_unlocked('\n', f
);
867 int write_env_file(const char *fname
, char **l
) {
868 _cleanup_fclose_
FILE *f
= NULL
;
869 _cleanup_free_
char *p
= NULL
;
875 r
= fopen_temporary(fname
, &f
, &p
);
879 fchmod_umask(fileno(f
), 0644);
882 write_env_var(f
, *i
);
884 r
= fflush_and_check(f
);
886 if (rename(p
, fname
) >= 0)
896 int executable_is_script(const char *path
, char **interpreter
) {
898 _cleanup_free_
char *line
= NULL
;
904 r
= read_one_line_file(path
, &line
);
908 if (!startswith(line
, "#!"))
911 ans
= strstrip(line
+ 2);
912 len
= strcspn(ans
, " \t");
917 ans
= strndup(ans
, len
);
926 * Retrieve one field from a file like /proc/self/status. pattern
927 * should not include whitespace or the delimiter (':'). pattern matches only
928 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
929 * zeros after the ':' will be skipped. field must be freed afterwards.
930 * terminator specifies the terminating characters of the field value (not
931 * included in the value).
933 int get_proc_field(const char *filename
, const char *pattern
, const char *terminator
, char **field
) {
934 _cleanup_free_
char *status
= NULL
;
944 r
= read_full_file(filename
, &status
, NULL
);
954 t
= strstr(t
, pattern
);
958 /* Check that pattern occurs in beginning of line. */
959 pattern_ok
= (t
== status
|| t
[-1] == '\n');
961 t
+= strlen(pattern
);
963 } while (!pattern_ok
);
965 t
+= strspn(t
, " \t");
974 t
+= strspn(t
, " \t");
976 /* Also skip zeros, because when this is used for
977 * capabilities, we don't want the zeros. This way the
978 * same capability set always maps to the same string,
979 * irrespective of the total capability set size. For
980 * other numbers it shouldn't matter. */
982 /* Back off one char if there's nothing but whitespace
984 if (!*t
|| isspace(*t
))
988 len
= strcspn(t
, terminator
);
998 DIR *xopendirat(int fd
, const char *name
, int flags
) {
1002 assert(!(flags
& O_CREAT
));
1004 nfd
= openat(fd
, name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|flags
, 0);
1017 static int search_and_fopen_internal(const char *path
, const char *mode
, const char *root
, char **search
, FILE **_f
) {
1024 if (!path_strv_resolve_uniq(search
, root
))
1027 STRV_FOREACH(i
, search
) {
1028 _cleanup_free_
char *p
= NULL
;
1032 p
= strjoin(root
, *i
, "/", path
);
1034 p
= strjoin(*i
, "/", path
);
1044 if (errno
!= ENOENT
)
1051 int search_and_fopen(const char *path
, const char *mode
, const char *root
, const char **search
, FILE **_f
) {
1052 _cleanup_strv_free_
char **copy
= NULL
;
1058 if (path_is_absolute(path
)) {
1061 f
= fopen(path
, mode
);
1070 copy
= strv_copy((char**) search
);
1074 return search_and_fopen_internal(path
, mode
, root
, copy
, _f
);
1077 int search_and_fopen_nulstr(const char *path
, const char *mode
, const char *root
, const char *search
, FILE **_f
) {
1078 _cleanup_strv_free_
char **s
= NULL
;
1080 if (path_is_absolute(path
)) {
1083 f
= fopen(path
, mode
);
1092 s
= strv_split_nulstr(search
);
1096 return search_and_fopen_internal(path
, mode
, root
, s
, _f
);
1099 int fopen_temporary(const char *path
, FILE **_f
, char **_temp_path
) {
1108 r
= tempfn_xxxxxx(path
, NULL
, &t
);
1112 fd
= mkostemp_safe(t
);
1118 f
= fdopen(fd
, "we");
1132 int fflush_and_check(FILE *f
) {
1139 return errno
> 0 ? -errno
: -EIO
;
1144 int fflush_sync_and_check(FILE *f
) {
1149 r
= fflush_and_check(f
);
1153 if (fsync(fileno(f
)) < 0)
1159 /* This is much like mkostemp() but is subject to umask(). */
1160 int mkostemp_safe(char *pattern
) {
1161 _cleanup_umask_ mode_t u
= 0;
1168 fd
= mkostemp(pattern
, O_CLOEXEC
);
1175 int tempfn_xxxxxx(const char *p
, const char *extra
, char **ret
) {
1187 * /foo/bar/.#<extra>waldoXXXXXX
1191 if (!filename_is_valid(fn
))
1197 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 6 + 1);
1201 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
), "XXXXXX");
1203 *ret
= path_kill_slashes(t
);
1207 int tempfn_random(const char *p
, const char *extra
, char **ret
) {
1221 * /foo/bar/.#<extra>waldobaa2a261115984a9
1225 if (!filename_is_valid(fn
))
1231 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 16 + 1);
1235 x
= stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
);
1238 for (i
= 0; i
< 16; i
++) {
1239 *(x
++) = hexchar(u
& 0xF);
1245 *ret
= path_kill_slashes(t
);
1249 int tempfn_random_child(const char *p
, const char *extra
, char **ret
) {
1260 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1272 t
= new(char, strlen(p
) + 3 + strlen(extra
) + 16 + 1);
1276 x
= stpcpy(stpcpy(stpcpy(t
, p
), "/.#"), extra
);
1279 for (i
= 0; i
< 16; i
++) {
1280 *(x
++) = hexchar(u
& 0xF);
1286 *ret
= path_kill_slashes(t
);
1290 int write_timestamp_file_atomic(const char *fn
, usec_t n
) {
1291 char ln
[DECIMAL_STR_MAX(n
)+2];
1293 /* Creates a "timestamp" file, that contains nothing but a
1294 * usec_t timestamp, formatted in ASCII. */
1296 if (n
<= 0 || n
>= USEC_INFINITY
)
1299 xsprintf(ln
, USEC_FMT
"\n", n
);
1301 return write_string_file(fn
, ln
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
1304 int read_timestamp_file(const char *fn
, usec_t
*ret
) {
1305 _cleanup_free_
char *ln
= NULL
;
1309 r
= read_one_line_file(fn
, &ln
);
1313 r
= safe_atou64(ln
, &t
);
1317 if (t
<= 0 || t
>= (uint64_t) USEC_INFINITY
)
1324 int fputs_with_space(FILE *f
, const char *s
, const char *separator
, bool *space
) {
1329 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1330 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1331 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1332 * element, but not before the first one. */
1342 r
= fputs(separator
, f
);
1353 int open_tmpfile_unlinkable(const char *directory
, int flags
) {
1358 r
= tmp_dir(&directory
);
1363 /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
1365 /* Try O_TMPFILE first, if it is supported */
1366 fd
= open(directory
, flags
|O_TMPFILE
|O_EXCL
, S_IRUSR
|S_IWUSR
);
1370 /* Fall back to unguessable name + unlinking */
1371 p
= strjoina(directory
, "/systemd-tmp-XXXXXX");
1373 fd
= mkostemp_safe(p
);
1382 int open_tmpfile_linkable(const char *target
, int flags
, char **ret_path
) {
1383 _cleanup_free_
char *tmp
= NULL
;
1389 /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
1390 assert((flags
& O_EXCL
) == 0);
1392 /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
1393 * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
1394 * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
1397 _cleanup_free_
char *dn
= NULL
;
1399 dn
= dirname_malloc(target
);
1403 fd
= open(dn
, O_TMPFILE
|flags
, 0640);
1409 log_debug_errno(errno
, "Failed to use O_TMPFILE on %s: %m", dn
);
1412 r
= tempfn_random(target
, NULL
, &tmp
);
1416 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_NOFOLLOW
|O_NOCTTY
|flags
, 0640);
1426 int open_serialization_fd(const char *ident
) {
1429 fd
= memfd_create(ident
, MFD_CLOEXEC
);
1433 path
= getpid_cached() == 1 ? "/run/systemd" : "/tmp";
1434 fd
= open_tmpfile_unlinkable(path
, O_RDWR
|O_CLOEXEC
);
1438 log_debug("Serializing %s to %s.", ident
, path
);
1440 log_debug("Serializing %s to memfd.", ident
);
1445 int link_tmpfile(int fd
, const char *path
, const char *target
) {
1450 /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
1451 * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
1452 * on the directory, and renameat2() is used instead.
1454 * Note that in both cases we will not replace existing files. This is because linkat() does not support this
1455 * operation currently (renameat2() does), and there is no nice way to emulate this. */
1458 if (rename_noreplace(AT_FDCWD
, path
, AT_FDCWD
, target
) < 0)
1461 char proc_fd_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd
) + 1];
1463 xsprintf(proc_fd_path
, "/proc/self/fd/%i", fd
);
1465 if (linkat(AT_FDCWD
, proc_fd_path
, AT_FDCWD
, target
, AT_SYMLINK_FOLLOW
) < 0)
1472 int read_nul_string(FILE *f
, char **ret
) {
1473 _cleanup_free_
char *x
= NULL
;
1474 size_t allocated
= 0, n
= 0;
1479 /* Reads a NUL-terminated string from the specified file. */
1484 if (!GREEDY_REALLOC(x
, allocated
, n
+2))
1488 if (c
== 0) /* Terminate at NUL byte */
1493 break; /* Terminate at EOF */
1513 int mkdtemp_malloc(const char *template, char **ret
) {
1519 p
= strdup(template);
1532 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile
);
1534 int read_line(FILE *f
, size_t limit
, char **ret
) {
1535 _cleanup_free_
char *buffer
= NULL
;
1536 size_t n
= 0, allocated
= 0, count
= 0;
1540 /* Something like a bounded version of getline().
1542 * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1545 * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1546 * the number of characters in the returned string). When EOF is hit, 0 is returned.
1548 * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1549 * delimiters. If the limit is hit we fail and return -ENOBUFS.
1551 * If a line shall be skipped ret may be initialized as NULL. */
1554 if (!GREEDY_REALLOC(buffer
, allocated
, 1))
1559 _unused_
_cleanup_(funlockfilep
) FILE *flocked
= f
;
1569 c
= fgetc_unlocked(f
);
1571 /* if we read an error, and have no data to return, then propagate the error */
1572 if (ferror_unlocked(f
) && n
== 0)
1573 return errno
> 0 ? -errno
: -EIO
;
1580 if (IN_SET(c
, '\n', 0)) /* Reached a delimiter */
1584 if (!GREEDY_REALLOC(buffer
, allocated
, n
+ 2))
1587 buffer
[n
] = (char) c
;