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/>.
29 #include <sys/types.h>
32 #include "alloc-util.h"
40 #include "hexdecoct.h"
44 #include "parse-util.h"
45 #include "path-util.h"
46 #include "process-util.h"
47 #include "random-util.h"
48 #include "stdio-util.h"
49 #include "string-util.h"
51 #include "time-util.h"
52 #include "umask-util.h"
55 #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
57 int write_string_stream_ts(
60 WriteStringFileFlags flags
,
61 struct timespec
*ts
) {
67 if (!(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
) && !endswith(line
, "\n"))
71 struct timespec twice
[2] = {*ts
, *ts
};
73 if (futimens(fileno(f
), twice
) < 0)
77 if (flags
& WRITE_STRING_FILE_SYNC
)
78 return fflush_sync_and_check(f
);
80 return fflush_and_check(f
);
83 static int write_string_file_atomic(
86 WriteStringFileFlags flags
,
87 struct timespec
*ts
) {
89 _cleanup_fclose_
FILE *f
= NULL
;
90 _cleanup_free_
char *p
= NULL
;
96 r
= fopen_temporary(fn
, &f
, &p
);
100 (void) fchmod_umask(fileno(f
), 0644);
102 r
= write_string_stream_ts(f
, line
, flags
, ts
);
106 if (rename(p
, fn
) < 0) {
118 int write_string_file_ts(
121 WriteStringFileFlags flags
,
122 struct timespec
*ts
) {
124 _cleanup_fclose_
FILE *f
= NULL
;
130 /* We don't know how to verify whether the file contents was already on-disk. */
131 assert(!((flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
) && (flags
& WRITE_STRING_FILE_SYNC
)));
133 if (flags
& WRITE_STRING_FILE_ATOMIC
) {
134 assert(flags
& WRITE_STRING_FILE_CREATE
);
136 r
= write_string_file_atomic(fn
, line
, flags
, ts
);
144 if (flags
& WRITE_STRING_FILE_CREATE
) {
153 /* We manually build our own version of fopen(..., "we") that
154 * works without O_CREAT */
155 fd
= open(fn
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
161 f
= fdopen(fd
, "we");
169 r
= write_string_stream_ts(f
, line
, flags
, ts
);
176 if (!(flags
& WRITE_STRING_FILE_VERIFY_ON_FAILURE
))
181 /* OK, the operation failed, but let's see if the right
182 * contents in place already. If so, eat up the error. */
184 q
= verify_file(fn
, line
, !(flags
& WRITE_STRING_FILE_AVOID_NEWLINE
));
191 int read_one_line_file(const char *fn
, char **line
) {
192 _cleanup_fclose_
FILE *f
= NULL
;
202 r
= read_line(f
, LONG_LINE_MAX
, line
);
203 return r
< 0 ? r
: 0;
206 int verify_file(const char *fn
, const char *blob
, bool accept_extra_nl
) {
207 _cleanup_fclose_
FILE *f
= NULL
;
208 _cleanup_free_
char *buf
= NULL
;
216 if (accept_extra_nl
&& endswith(blob
, "\n"))
217 accept_extra_nl
= false;
219 buf
= malloc(l
+ accept_extra_nl
+ 1);
227 /* We try to read one byte more than we need, so that we know whether we hit eof */
229 k
= fread(buf
, 1, l
+ accept_extra_nl
+ 1, f
);
231 return errno
> 0 ? -errno
: -EIO
;
233 if (k
!= l
&& k
!= l
+ accept_extra_nl
)
235 if (memcmp(buf
, blob
, l
) != 0)
237 if (k
> l
&& buf
[l
] != '\n')
243 int read_full_stream(FILE *f
, char **contents
, size_t *size
) {
245 _cleanup_free_
char *buf
= NULL
;
251 if (fstat(fileno(f
), &st
) < 0)
256 if (S_ISREG(st
.st_mode
)) {
259 if (st
.st_size
> READ_FULL_BYTES_MAX
)
262 /* Start with the right file size, but be prepared for files from /proc which generally report a file
263 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
264 * already makes us notice the EOF. */
274 t
= realloc(buf
, n
+ 1);
280 k
= fread(buf
+ l
, 1, n
- l
, f
);
285 return errno
> 0 ? -errno
: -EIO
;
290 /* We aren't expecting fread() to return a short read outside
291 * of (error && eof), assert buffer is full and enlarge buffer.
296 if (n
>= READ_FULL_BYTES_MAX
)
299 n
= MIN(n
* 2, READ_FULL_BYTES_MAX
);
304 buf
= NULL
; /* do not free */
312 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
313 _cleanup_fclose_
FILE *f
= NULL
;
322 return read_full_stream(f
, contents
, size
);
325 static int parse_env_file_internal(
329 int (*push
) (const char *filename
, unsigned line
,
330 const char *key
, char *value
, void *userdata
, int *n_pushed
),
334 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
335 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;
336 char *p
, *value
= NULL
;
347 SINGLE_QUOTE_VALUE_ESCAPE
,
349 DOUBLE_QUOTE_VALUE_ESCAPE
,
357 r
= read_full_stream(f
, &contents
, NULL
);
359 r
= read_full_file(fname
, &contents
, NULL
);
363 for (p
= contents
; *p
; p
++) {
369 if (strchr(COMMENTS
, c
))
371 else if (!strchr(WHITESPACE
, c
)) {
373 last_key_whitespace
= (size_t) -1;
375 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
385 if (strchr(newline
, c
)) {
389 } else if (c
== '=') {
391 last_value_whitespace
= (size_t) -1;
393 if (!strchr(WHITESPACE
, c
))
394 last_key_whitespace
= (size_t) -1;
395 else if (last_key_whitespace
== (size_t) -1)
396 last_key_whitespace
= n_key
;
398 if (!GREEDY_REALLOC(key
, key_alloc
, n_key
+2)) {
409 if (strchr(newline
, c
)) {
417 /* strip trailing whitespace from key */
418 if (last_key_whitespace
!= (size_t) -1)
419 key
[last_key_whitespace
] = 0;
421 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
427 value_alloc
= n_value
= 0;
429 } else if (c
== '\'')
430 state
= SINGLE_QUOTE_VALUE
;
432 state
= DOUBLE_QUOTE_VALUE
;
434 state
= VALUE_ESCAPE
;
435 else if (!strchr(WHITESPACE
, c
)) {
438 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
443 value
[n_value
++] = c
;
449 if (strchr(newline
, c
)) {
458 /* Chomp off trailing whitespace from value */
459 if (last_value_whitespace
!= (size_t) -1)
460 value
[last_value_whitespace
] = 0;
462 /* strip trailing whitespace from key */
463 if (last_key_whitespace
!= (size_t) -1)
464 key
[last_key_whitespace
] = 0;
466 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
472 value_alloc
= n_value
= 0;
474 } else if (c
== '\\') {
475 state
= VALUE_ESCAPE
;
476 last_value_whitespace
= (size_t) -1;
478 if (!strchr(WHITESPACE
, c
))
479 last_value_whitespace
= (size_t) -1;
480 else if (last_value_whitespace
== (size_t) -1)
481 last_value_whitespace
= n_value
;
483 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
488 value
[n_value
++] = c
;
496 if (!strchr(newline
, c
)) {
497 /* Escaped newlines we eat up entirely */
498 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
503 value
[n_value
++] = c
;
507 case SINGLE_QUOTE_VALUE
:
511 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
513 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
518 value
[n_value
++] = c
;
523 case SINGLE_QUOTE_VALUE_ESCAPE
:
524 state
= SINGLE_QUOTE_VALUE
;
526 if (!strchr(newline
, c
)) {
527 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
532 value
[n_value
++] = c
;
536 case DOUBLE_QUOTE_VALUE
:
540 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
542 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
547 value
[n_value
++] = c
;
552 case DOUBLE_QUOTE_VALUE_ESCAPE
:
553 state
= DOUBLE_QUOTE_VALUE
;
555 if (!strchr(newline
, c
)) {
556 if (!GREEDY_REALLOC(value
, value_alloc
, n_value
+2)) {
561 value
[n_value
++] = c
;
567 state
= COMMENT_ESCAPE
;
568 else if (strchr(newline
, c
)) {
585 SINGLE_QUOTE_VALUE_ESCAPE
,
587 DOUBLE_QUOTE_VALUE_ESCAPE
)) {
595 if (last_value_whitespace
!= (size_t) -1)
596 value
[last_value_whitespace
] = 0;
598 /* strip trailing whitespace from key */
599 if (last_key_whitespace
!= (size_t) -1)
600 key
[last_key_whitespace
] = 0;
602 r
= push(fname
, line
, key
, value
, userdata
, n_pushed
);
614 static int check_utf8ness_and_warn(
615 const char *filename
, unsigned line
,
616 const char *key
, char *value
) {
618 if (!utf8_is_valid(key
)) {
619 _cleanup_free_
char *p
= NULL
;
621 p
= utf8_escape_invalid(key
);
622 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename
), line
, p
);
626 if (value
&& !utf8_is_valid(value
)) {
627 _cleanup_free_
char *p
= NULL
;
629 p
= utf8_escape_invalid(value
);
630 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename
), line
, key
, p
);
637 static int parse_env_file_push(
638 const char *filename
, unsigned line
,
639 const char *key
, char *value
,
644 va_list aq
, *ap
= userdata
;
647 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
653 while ((k
= va_arg(aq
, const char *))) {
656 v
= va_arg(aq
, char **);
678 const char *newline
, ...) {
686 va_start(ap
, newline
);
687 r
= parse_env_file_internal(NULL
, fname
, newline
, parse_env_file_push
, &ap
, &n_pushed
);
690 return r
< 0 ? r
: n_pushed
;
693 static int load_env_file_push(
694 const char *filename
, unsigned line
,
695 const char *key
, char *value
,
698 char ***m
= userdata
;
702 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
706 p
= strjoin(key
, "=", value
);
710 r
= strv_env_replace(m
, p
);
723 int load_env_file(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
730 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push
, &m
, NULL
);
740 static int load_env_file_push_pairs(
741 const char *filename
, unsigned line
,
742 const char *key
, char *value
,
745 char ***m
= userdata
;
748 r
= check_utf8ness_and_warn(filename
, line
, key
, value
);
752 r
= strv_extend(m
, key
);
757 r
= strv_extend(m
, "");
761 r
= strv_push(m
, value
);
772 int load_env_file_pairs(FILE *f
, const char *fname
, const char *newline
, char ***rl
) {
779 r
= parse_env_file_internal(f
, fname
, newline
, load_env_file_push_pairs
, &m
, NULL
);
789 static int merge_env_file_push(
790 const char *filename
, unsigned line
,
791 const char *key
, char *value
,
795 char ***env
= userdata
;
796 char *expanded_value
;
801 log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename
), line
, key
);
805 if (!env_name_is_valid(key
)) {
806 log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename
), line
, key
);
811 expanded_value
= replace_env(value
, *env
,
812 REPLACE_ENV_USE_ENVIRONMENT
|
813 REPLACE_ENV_ALLOW_BRACELESS
|
814 REPLACE_ENV_ALLOW_EXTENDED
);
818 free_and_replace(value
, expanded_value
);
820 return load_env_file_push(filename
, line
, key
, value
, env
, n_pushed
);
828 /* NOTE: this function supports braceful and braceless variable expansions,
829 * plus "extended" substitutions, unlike other exported parsing functions.
832 return parse_env_file_internal(f
, fname
, NEWLINE
, merge_env_file_push
, env
, NULL
);
835 static void write_env_var(FILE *f
, const char *v
) {
841 fputs_unlocked(v
, f
);
842 fputc_unlocked('\n', f
);
847 fwrite_unlocked(v
, 1, p
-v
, f
);
849 if (string_has_cc(p
, NULL
) || chars_intersect(p
, WHITESPACE SHELL_NEED_QUOTES
)) {
850 fputc_unlocked('\"', f
);
853 if (strchr(SHELL_NEED_ESCAPE
, *p
))
854 fputc_unlocked('\\', f
);
856 fputc_unlocked(*p
, f
);
859 fputc_unlocked('\"', f
);
861 fputs_unlocked(p
, f
);
863 fputc_unlocked('\n', f
);
866 int write_env_file(const char *fname
, char **l
) {
867 _cleanup_fclose_
FILE *f
= NULL
;
868 _cleanup_free_
char *p
= NULL
;
874 r
= fopen_temporary(fname
, &f
, &p
);
878 fchmod_umask(fileno(f
), 0644);
881 write_env_var(f
, *i
);
883 r
= fflush_and_check(f
);
885 if (rename(p
, fname
) >= 0)
895 int executable_is_script(const char *path
, char **interpreter
) {
897 _cleanup_free_
char *line
= NULL
;
903 r
= read_one_line_file(path
, &line
);
907 if (!startswith(line
, "#!"))
910 ans
= strstrip(line
+ 2);
911 len
= strcspn(ans
, " \t");
916 ans
= strndup(ans
, len
);
925 * Retrieve one field from a file like /proc/self/status. pattern
926 * should not include whitespace or the delimiter (':'). pattern matches only
927 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
928 * zeros after the ':' will be skipped. field must be freed afterwards.
929 * terminator specifies the terminating characters of the field value (not
930 * included in the value).
932 int get_proc_field(const char *filename
, const char *pattern
, const char *terminator
, char **field
) {
933 _cleanup_free_
char *status
= NULL
;
943 r
= read_full_file(filename
, &status
, NULL
);
953 t
= strstr(t
, pattern
);
957 /* Check that pattern occurs in beginning of line. */
958 pattern_ok
= (t
== status
|| t
[-1] == '\n');
960 t
+= strlen(pattern
);
962 } while (!pattern_ok
);
964 t
+= strspn(t
, " \t");
973 t
+= strspn(t
, " \t");
975 /* Also skip zeros, because when this is used for
976 * capabilities, we don't want the zeros. This way the
977 * same capability set always maps to the same string,
978 * irrespective of the total capability set size. For
979 * other numbers it shouldn't matter. */
981 /* Back off one char if there's nothing but whitespace
983 if (!*t
|| isspace(*t
))
987 len
= strcspn(t
, terminator
);
997 DIR *xopendirat(int fd
, const char *name
, int flags
) {
1001 assert(!(flags
& O_CREAT
));
1003 nfd
= openat(fd
, name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|flags
, 0);
1016 static int search_and_fopen_internal(const char *path
, const char *mode
, const char *root
, char **search
, FILE **_f
) {
1023 if (!path_strv_resolve_uniq(search
, root
))
1026 STRV_FOREACH(i
, search
) {
1027 _cleanup_free_
char *p
= NULL
;
1031 p
= strjoin(root
, *i
, "/", path
);
1033 p
= strjoin(*i
, "/", path
);
1043 if (errno
!= ENOENT
)
1050 int search_and_fopen(const char *path
, const char *mode
, const char *root
, const char **search
, FILE **_f
) {
1051 _cleanup_strv_free_
char **copy
= NULL
;
1057 if (path_is_absolute(path
)) {
1060 f
= fopen(path
, mode
);
1069 copy
= strv_copy((char**) search
);
1073 return search_and_fopen_internal(path
, mode
, root
, copy
, _f
);
1076 int search_and_fopen_nulstr(const char *path
, const char *mode
, const char *root
, const char *search
, FILE **_f
) {
1077 _cleanup_strv_free_
char **s
= NULL
;
1079 if (path_is_absolute(path
)) {
1082 f
= fopen(path
, mode
);
1091 s
= strv_split_nulstr(search
);
1095 return search_and_fopen_internal(path
, mode
, root
, s
, _f
);
1098 int fopen_temporary(const char *path
, FILE **_f
, char **_temp_path
) {
1107 r
= tempfn_xxxxxx(path
, NULL
, &t
);
1111 fd
= mkostemp_safe(t
);
1117 f
= fdopen(fd
, "we");
1131 int fflush_and_check(FILE *f
) {
1138 return errno
> 0 ? -errno
: -EIO
;
1143 int fflush_sync_and_check(FILE *f
) {
1148 r
= fflush_and_check(f
);
1152 if (fsync(fileno(f
)) < 0)
1158 /* This is much like mkostemp() but is subject to umask(). */
1159 int mkostemp_safe(char *pattern
) {
1160 _cleanup_umask_ mode_t u
= 0;
1167 fd
= mkostemp(pattern
, O_CLOEXEC
);
1174 int tempfn_xxxxxx(const char *p
, const char *extra
, char **ret
) {
1186 * /foo/bar/.#<extra>waldoXXXXXX
1190 if (!filename_is_valid(fn
))
1196 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 6 + 1);
1200 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
), "XXXXXX");
1202 *ret
= path_kill_slashes(t
);
1206 int tempfn_random(const char *p
, const char *extra
, char **ret
) {
1220 * /foo/bar/.#<extra>waldobaa2a261115984a9
1224 if (!filename_is_valid(fn
))
1230 t
= new(char, strlen(p
) + 2 + strlen(extra
) + 16 + 1);
1234 x
= stpcpy(stpcpy(stpcpy(mempcpy(t
, p
, fn
- p
), ".#"), extra
), fn
);
1237 for (i
= 0; i
< 16; i
++) {
1238 *(x
++) = hexchar(u
& 0xF);
1244 *ret
= path_kill_slashes(t
);
1248 int tempfn_random_child(const char *p
, const char *extra
, char **ret
) {
1259 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1271 t
= new(char, strlen(p
) + 3 + strlen(extra
) + 16 + 1);
1275 x
= stpcpy(stpcpy(stpcpy(t
, p
), "/.#"), extra
);
1278 for (i
= 0; i
< 16; i
++) {
1279 *(x
++) = hexchar(u
& 0xF);
1285 *ret
= path_kill_slashes(t
);
1289 int write_timestamp_file_atomic(const char *fn
, usec_t n
) {
1290 char ln
[DECIMAL_STR_MAX(n
)+2];
1292 /* Creates a "timestamp" file, that contains nothing but a
1293 * usec_t timestamp, formatted in ASCII. */
1295 if (n
<= 0 || n
>= USEC_INFINITY
)
1298 xsprintf(ln
, USEC_FMT
"\n", n
);
1300 return write_string_file(fn
, ln
, WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
1303 int read_timestamp_file(const char *fn
, usec_t
*ret
) {
1304 _cleanup_free_
char *ln
= NULL
;
1308 r
= read_one_line_file(fn
, &ln
);
1312 r
= safe_atou64(ln
, &t
);
1316 if (t
<= 0 || t
>= (uint64_t) USEC_INFINITY
)
1323 int fputs_with_space(FILE *f
, const char *s
, const char *separator
, bool *space
) {
1328 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1329 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1330 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1331 * element, but not before the first one. */
1341 r
= fputs(separator
, f
);
1352 int open_tmpfile_unlinkable(const char *directory
, int flags
) {
1357 r
= tmp_dir(&directory
);
1362 /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
1364 /* Try O_TMPFILE first, if it is supported */
1365 fd
= open(directory
, flags
|O_TMPFILE
|O_EXCL
, S_IRUSR
|S_IWUSR
);
1369 /* Fall back to unguessable name + unlinking */
1370 p
= strjoina(directory
, "/systemd-tmp-XXXXXX");
1372 fd
= mkostemp_safe(p
);
1381 int open_tmpfile_linkable(const char *target
, int flags
, char **ret_path
) {
1382 _cleanup_free_
char *tmp
= NULL
;
1388 /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
1389 assert((flags
& O_EXCL
) == 0);
1391 /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
1392 * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
1393 * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
1396 _cleanup_free_
char *dn
= NULL
;
1398 dn
= dirname_malloc(target
);
1402 fd
= open(dn
, O_TMPFILE
|flags
, 0640);
1408 log_debug_errno(errno
, "Failed to use O_TMPFILE on %s: %m", dn
);
1411 r
= tempfn_random(target
, NULL
, &tmp
);
1415 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_NOFOLLOW
|O_NOCTTY
|flags
, 0640);
1425 int open_serialization_fd(const char *ident
) {
1428 fd
= memfd_create(ident
, MFD_CLOEXEC
);
1432 path
= getpid_cached() == 1 ? "/run/systemd" : "/tmp";
1433 fd
= open_tmpfile_unlinkable(path
, O_RDWR
|O_CLOEXEC
);
1437 log_debug("Serializing %s to %s.", ident
, path
);
1439 log_debug("Serializing %s to memfd.", ident
);
1444 int link_tmpfile(int fd
, const char *path
, const char *target
) {
1449 /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
1450 * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
1451 * on the directory, and renameat2() is used instead.
1453 * Note that in both cases we will not replace existing files. This is because linkat() does not support this
1454 * operation currently (renameat2() does), and there is no nice way to emulate this. */
1457 if (rename_noreplace(AT_FDCWD
, path
, AT_FDCWD
, target
) < 0)
1460 char proc_fd_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd
) + 1];
1462 xsprintf(proc_fd_path
, "/proc/self/fd/%i", fd
);
1464 if (linkat(AT_FDCWD
, proc_fd_path
, AT_FDCWD
, target
, AT_SYMLINK_FOLLOW
) < 0)
1471 int read_nul_string(FILE *f
, char **ret
) {
1472 _cleanup_free_
char *x
= NULL
;
1473 size_t allocated
= 0, n
= 0;
1478 /* Reads a NUL-terminated string from the specified file. */
1483 if (!GREEDY_REALLOC(x
, allocated
, n
+2))
1487 if (c
== 0) /* Terminate at NUL byte */
1492 break; /* Terminate at EOF */
1512 int mkdtemp_malloc(const char *template, char **ret
) {
1518 p
= strdup(template);
1531 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile
);
1533 int read_line(FILE *f
, size_t limit
, char **ret
) {
1534 _cleanup_free_
char *buffer
= NULL
;
1535 size_t n
= 0, allocated
= 0, count
= 0;
1539 /* Something like a bounded version of getline().
1541 * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1544 * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1545 * the number of characters in the returned string). When EOF is hit, 0 is returned.
1547 * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1548 * delimiters. If the limit is hit we fail and return -ENOBUFS.
1550 * If a line shall be skipped ret may be initialized as NULL. */
1553 if (!GREEDY_REALLOC(buffer
, allocated
, 1))
1558 _unused_
_cleanup_(funlockfilep
) FILE *flocked
= f
;
1568 c
= fgetc_unlocked(f
);
1570 /* if we read an error, and have no data to return, then propagate the error */
1571 if (ferror_unlocked(f
) && n
== 0)
1572 return errno
> 0 ? -errno
: -EIO
;
1579 if (IN_SET(c
, '\n', 0)) /* Reached a delimiter */
1583 if (!GREEDY_REALLOC(buffer
, allocated
, n
+ 2))
1586 buffer
[n
] = (char) c
;