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) {
68 if (fputs(line, f) == EOF)
71 if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
72 if (fputc('\n', f) == EOF)
76 struct timespec twice[2] = {*ts, *ts};
78 if (futimens(fileno(f), twice) < 0)
82 if (flags & WRITE_STRING_FILE_SYNC)
83 return fflush_sync_and_check(f);
85 return fflush_and_check(f);
88 static int write_string_file_atomic(
91 WriteStringFileFlags flags,
92 struct timespec *ts) {
94 _cleanup_fclose_ FILE *f = NULL;
95 _cleanup_free_ char *p = NULL;
101 r = fopen_temporary(fn, &f, &p);
105 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
106 (void) fchmod_umask(fileno(f), 0644);
108 r = write_string_stream_ts(f, line, flags, ts);
112 if (rename(p, fn) < 0) {
124 int write_string_file_ts(
127 WriteStringFileFlags flags,
128 struct timespec *ts) {
130 _cleanup_fclose_ FILE *f = NULL;
136 /* We don't know how to verify whether the file contents was already on-disk. */
137 assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
139 if (flags & WRITE_STRING_FILE_ATOMIC) {
140 assert(flags & WRITE_STRING_FILE_CREATE);
142 r = write_string_file_atomic(fn, line, flags, ts);
150 if (flags & WRITE_STRING_FILE_CREATE) {
159 /* We manually build our own version of fopen(..., "we") that
160 * works without O_CREAT */
161 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
167 f = fdopen(fd, "we");
175 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
177 if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
178 setvbuf(f, NULL, _IONBF, 0);
180 r = write_string_stream_ts(f, line, flags, ts);
187 if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
192 /* OK, the operation failed, but let's see if the right
193 * contents in place already. If so, eat up the error. */
195 q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
202 int read_one_line_file(const char *fn, char **line) {
203 _cleanup_fclose_ FILE *f = NULL;
213 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
215 r = read_line(f, LONG_LINE_MAX, line);
216 return r < 0 ? r : 0;
219 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
220 _cleanup_fclose_ FILE *f = NULL;
221 _cleanup_free_ char *buf = NULL;
229 if (accept_extra_nl && endswith(blob, "\n"))
230 accept_extra_nl = false;
232 buf = malloc(l + accept_extra_nl + 1);
240 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
242 /* We try to read one byte more than we need, so that we know whether we hit eof */
244 k = fread(buf, 1, l + accept_extra_nl + 1, f);
246 return errno > 0 ? -errno : -EIO;
248 if (k != l && k != l + accept_extra_nl)
250 if (memcmp(buf, blob, l) != 0)
252 if (k > l && buf[l] != '\n')
258 int read_full_stream(FILE *f, char **contents, size_t *size) {
260 _cleanup_free_ char *buf = NULL;
266 if (fstat(fileno(f), &st) < 0)
271 if (S_ISREG(st.st_mode)) {
274 if (st.st_size > READ_FULL_BYTES_MAX)
277 /* Start with the right file size, but be prepared for files from /proc which generally report a file
278 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
279 * already makes us notice the EOF. */
289 t = realloc(buf, n + 1);
295 k = fread(buf + l, 1, n - l, f);
300 return errno > 0 ? -errno : -EIO;
305 /* We aren't expecting fread() to return a short read outside
306 * of (error && eof), assert buffer is full and enlarge buffer.
311 if (n >= READ_FULL_BYTES_MAX)
314 n = MIN(n * 2, READ_FULL_BYTES_MAX);
319 buf = NULL; /* do not free */
327 int read_full_file(const char *fn, char **contents, size_t *size) {
328 _cleanup_fclose_ FILE *f = NULL;
337 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
339 return read_full_stream(f, contents, size);
342 static int parse_env_file_internal(
346 int (*push) (const char *filename, unsigned line,
347 const char *key, char *value, void *userdata, int *n_pushed),
351 _cleanup_free_ char *contents = NULL, *key = NULL;
352 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;
353 char *p, *value = NULL;
364 SINGLE_QUOTE_VALUE_ESCAPE,
366 DOUBLE_QUOTE_VALUE_ESCAPE,
374 r = read_full_stream(f, &contents, NULL);
376 r = read_full_file(fname, &contents, NULL);
380 for (p = contents; *p; p++) {
386 if (strchr(COMMENTS, c))
388 else if (!strchr(WHITESPACE, c)) {
390 last_key_whitespace = (size_t) -1;
392 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
402 if (strchr(newline, c)) {
406 } else if (c == '=') {
408 last_value_whitespace = (size_t) -1;
410 if (!strchr(WHITESPACE, c))
411 last_key_whitespace = (size_t) -1;
412 else if (last_key_whitespace == (size_t) -1)
413 last_key_whitespace = n_key;
415 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
426 if (strchr(newline, c)) {
434 /* strip trailing whitespace from key */
435 if (last_key_whitespace != (size_t) -1)
436 key[last_key_whitespace] = 0;
438 r = push(fname, line, key, value, userdata, n_pushed);
444 value_alloc = n_value = 0;
446 } else if (c == '\'')
447 state = SINGLE_QUOTE_VALUE;
449 state = DOUBLE_QUOTE_VALUE;
451 state = VALUE_ESCAPE;
452 else if (!strchr(WHITESPACE, c)) {
455 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
460 value[n_value++] = c;
466 if (strchr(newline, c)) {
475 /* Chomp off trailing whitespace from value */
476 if (last_value_whitespace != (size_t) -1)
477 value[last_value_whitespace] = 0;
479 /* strip trailing whitespace from key */
480 if (last_key_whitespace != (size_t) -1)
481 key[last_key_whitespace] = 0;
483 r = push(fname, line, key, value, userdata, n_pushed);
489 value_alloc = n_value = 0;
491 } else if (c == '\\') {
492 state = VALUE_ESCAPE;
493 last_value_whitespace = (size_t) -1;
495 if (!strchr(WHITESPACE, c))
496 last_value_whitespace = (size_t) -1;
497 else if (last_value_whitespace == (size_t) -1)
498 last_value_whitespace = n_value;
500 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
505 value[n_value++] = c;
513 if (!strchr(newline, c)) {
514 /* Escaped newlines we eat up entirely */
515 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
520 value[n_value++] = c;
524 case SINGLE_QUOTE_VALUE:
528 state = SINGLE_QUOTE_VALUE_ESCAPE;
530 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
535 value[n_value++] = c;
540 case SINGLE_QUOTE_VALUE_ESCAPE:
541 state = SINGLE_QUOTE_VALUE;
543 if (!strchr(newline, c)) {
544 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
549 value[n_value++] = c;
553 case DOUBLE_QUOTE_VALUE:
557 state = DOUBLE_QUOTE_VALUE_ESCAPE;
559 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
564 value[n_value++] = c;
569 case DOUBLE_QUOTE_VALUE_ESCAPE:
570 state = DOUBLE_QUOTE_VALUE;
572 if (!strchr(newline, c)) {
573 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
578 value[n_value++] = c;
584 state = COMMENT_ESCAPE;
585 else if (strchr(newline, c)) {
602 SINGLE_QUOTE_VALUE_ESCAPE,
604 DOUBLE_QUOTE_VALUE_ESCAPE)) {
612 if (last_value_whitespace != (size_t) -1)
613 value[last_value_whitespace] = 0;
615 /* strip trailing whitespace from key */
616 if (last_key_whitespace != (size_t) -1)
617 key[last_key_whitespace] = 0;
619 r = push(fname, line, key, value, userdata, n_pushed);
631 static int check_utf8ness_and_warn(
632 const char *filename, unsigned line,
633 const char *key, char *value) {
635 if (!utf8_is_valid(key)) {
636 _cleanup_free_ char *p = NULL;
638 p = utf8_escape_invalid(key);
639 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
643 if (value && !utf8_is_valid(value)) {
644 _cleanup_free_ char *p = NULL;
646 p = utf8_escape_invalid(value);
647 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
654 static int parse_env_file_push(
655 const char *filename, unsigned line,
656 const char *key, char *value,
661 va_list aq, *ap = userdata;
664 r = check_utf8ness_and_warn(filename, line, key, value);
670 while ((k = va_arg(aq, const char *))) {
673 v = va_arg(aq, char **);
695 const char *newline, ...) {
703 va_start(ap, newline);
704 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
707 return r < 0 ? r : n_pushed;
710 #if 0 /// UNNEEDED by elogind
711 static int load_env_file_push(
712 const char *filename, unsigned line,
713 const char *key, char *value,
716 char ***m = userdata;
720 r = check_utf8ness_and_warn(filename, line, key, value);
724 p = strjoin(key, "=", value);
728 r = strv_env_replace(m, p);
741 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
748 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
759 static int load_env_file_push_pairs(
760 const char *filename, unsigned line,
761 const char *key, char *value,
764 char ***m = userdata;
767 r = check_utf8ness_and_warn(filename, line, key, value);
771 r = strv_extend(m, key);
776 r = strv_extend(m, "");
780 r = strv_push(m, value);
791 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
798 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
807 #if 0 /// UNNEEDED by elogind
809 static int merge_env_file_push(
810 const char *filename, unsigned line,
811 const char *key, char *value,
815 char ***env = userdata;
816 char *expanded_value;
821 log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
825 if (!env_name_is_valid(key)) {
826 log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
831 expanded_value = replace_env(value, *env,
832 REPLACE_ENV_USE_ENVIRONMENT|
833 REPLACE_ENV_ALLOW_BRACELESS|
834 REPLACE_ENV_ALLOW_EXTENDED);
838 free_and_replace(value, expanded_value);
840 return load_env_file_push(filename, line, key, value, env, n_pushed);
848 /* NOTE: this function supports braceful and braceless variable expansions,
849 * plus "extended" substitutions, unlike other exported parsing functions.
852 return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL);
855 static void write_env_var(FILE *f, const char *v) {
861 fputs_unlocked(v, f);
862 fputc_unlocked('\n', f);
867 fwrite_unlocked(v, 1, p-v, f);
869 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
870 fputc_unlocked('\"', f);
873 if (strchr(SHELL_NEED_ESCAPE, *p))
874 fputc_unlocked('\\', f);
876 fputc_unlocked(*p, f);
879 fputc_unlocked('\"', f);
881 fputs_unlocked(p, f);
883 fputc_unlocked('\n', f);
886 int write_env_file(const char *fname, char **l) {
887 _cleanup_fclose_ FILE *f = NULL;
888 _cleanup_free_ char *p = NULL;
894 r = fopen_temporary(fname, &f, &p);
898 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
899 (void) fchmod_umask(fileno(f), 0644);
902 write_env_var(f, *i);
904 r = fflush_and_check(f);
906 if (rename(p, fname) >= 0)
916 int executable_is_script(const char *path, char **interpreter) {
918 _cleanup_free_ char *line = NULL;
924 r = read_one_line_file(path, &line);
928 if (!startswith(line, "#!"))
931 ans = strstrip(line + 2);
932 len = strcspn(ans, " \t");
937 ans = strndup(ans, len);
947 * Retrieve one field from a file like /proc/self/status. pattern
948 * should not include whitespace or the delimiter (':'). pattern matches only
949 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
950 * zeros after the ':' will be skipped. field must be freed afterwards.
951 * terminator specifies the terminating characters of the field value (not
952 * included in the value).
954 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
955 _cleanup_free_ char *status = NULL;
965 r = read_full_file(filename, &status, NULL);
975 t = strstr(t, pattern);
979 /* Check that pattern occurs in beginning of line. */
980 pattern_ok = (t == status || t[-1] == '\n');
982 t += strlen(pattern);
984 } while (!pattern_ok);
986 t += strspn(t, " \t");
995 t += strspn(t, " \t");
997 /* Also skip zeros, because when this is used for
998 * capabilities, we don't want the zeros. This way the
999 * same capability set always maps to the same string,
1000 * irrespective of the total capability set size. For
1001 * other numbers it shouldn't matter. */
1002 t += strspn(t, "0");
1003 /* Back off one char if there's nothing but whitespace
1005 if (!*t || isspace(*t))
1009 len = strcspn(t, terminator);
1011 f = strndup(t, len);
1019 DIR *xopendirat(int fd, const char *name, int flags) {
1023 assert(!(flags & O_CREAT));
1025 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
1038 #if 0 /// UNNEEDED by elogind
1039 static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
1046 if (!path_strv_resolve_uniq(search, root))
1049 STRV_FOREACH(i, search) {
1050 _cleanup_free_ char *p = NULL;
1054 p = strjoin(root, *i, "/", path);
1056 p = strjoin(*i, "/", path);
1066 if (errno != ENOENT)
1073 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
1074 _cleanup_strv_free_ char **copy = NULL;
1080 if (path_is_absolute(path)) {
1083 f = fopen(path, mode);
1092 copy = strv_copy((char**) search);
1096 return search_and_fopen_internal(path, mode, root, copy, _f);
1099 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1100 _cleanup_strv_free_ char **s = NULL;
1102 if (path_is_absolute(path)) {
1105 f = fopen(path, mode);
1114 s = strv_split_nulstr(search);
1118 return search_and_fopen_internal(path, mode, root, s, _f);
1122 int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1131 r = tempfn_xxxxxx(path, NULL, &t);
1135 fd = mkostemp_safe(t);
1141 f = fdopen(fd, "we");
1155 int fflush_and_check(FILE *f) {
1162 return errno > 0 ? -errno : -EIO;
1167 int fflush_sync_and_check(FILE *f) {
1172 r = fflush_and_check(f);
1176 if (fsync(fileno(f)) < 0)
1182 /* This is much like mkostemp() but is subject to umask(). */
1183 int mkostemp_safe(char *pattern) {
1184 _cleanup_umask_ mode_t u = 0;
1191 fd = mkostemp(pattern, O_CLOEXEC);
1198 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1210 * /foo/bar/.#<extra>waldoXXXXXX
1214 if (!filename_is_valid(fn))
1220 t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1224 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1226 *ret = path_kill_slashes(t);
1230 int tempfn_random(const char *p, const char *extra, char **ret) {
1244 * /foo/bar/.#<extra>waldobaa2a261115984a9
1248 if (!filename_is_valid(fn))
1254 t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1258 x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1261 for (i = 0; i < 16; i++) {
1262 *(x++) = hexchar(u & 0xF);
1268 *ret = path_kill_slashes(t);
1272 #if 0 /// UNNEEDED by elogind
1273 int tempfn_random_child(const char *p, const char *extra, char **ret) {
1284 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1296 t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1300 x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1303 for (i = 0; i < 16; i++) {
1304 *(x++) = hexchar(u & 0xF);
1310 *ret = path_kill_slashes(t);
1314 int write_timestamp_file_atomic(const char *fn, usec_t n) {
1315 char ln[DECIMAL_STR_MAX(n)+2];
1317 /* Creates a "timestamp" file, that contains nothing but a
1318 * usec_t timestamp, formatted in ASCII. */
1320 if (n <= 0 || n >= USEC_INFINITY)
1323 xsprintf(ln, USEC_FMT "\n", n);
1325 return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1328 int read_timestamp_file(const char *fn, usec_t *ret) {
1329 _cleanup_free_ char *ln = NULL;
1333 r = read_one_line_file(fn, &ln);
1337 r = safe_atou64(ln, &t);
1341 if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1348 int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
1353 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1354 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1355 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1356 * element, but not before the first one. */
1366 r = fputs(separator, f);
1378 int open_tmpfile_unlinkable(const char *directory, int flags) {
1383 r = tmp_dir(&directory);
1388 /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
1390 /* Try O_TMPFILE first, if it is supported */
1391 fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1395 /* Fall back to unguessable name + unlinking */
1396 p = strjoina(directory, "/systemd-tmp-XXXXXX");
1398 fd = mkostemp_safe(p);
1407 #if 0 /// UNNEEDED by elogind
1408 int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
1409 _cleanup_free_ char *tmp = NULL;
1415 /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
1416 assert((flags & O_EXCL) == 0);
1418 /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
1419 * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
1420 * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
1423 _cleanup_free_ char *dn = NULL;
1425 dn = dirname_malloc(target);
1429 fd = open(dn, O_TMPFILE|flags, 0640);
1435 log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
1438 r = tempfn_random(target, NULL, &tmp);
1442 fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
1453 int open_serialization_fd(const char *ident) {
1456 fd = memfd_create(ident, MFD_CLOEXEC);
1460 path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
1461 fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
1465 log_debug("Serializing %s to %s.", ident, path);
1467 log_debug("Serializing %s to memfd.", ident);
1472 #if 0 /// UNNEEDED by elogind
1473 int link_tmpfile(int fd, const char *path, const char *target) {
1478 /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
1479 * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
1480 * on the directory, and renameat2() is used instead.
1482 * Note that in both cases we will not replace existing files. This is because linkat() does not support this
1483 * operation currently (renameat2() does), and there is no nice way to emulate this. */
1486 if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
1489 char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
1491 xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
1493 if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
1500 int read_nul_string(FILE *f, char **ret) {
1501 _cleanup_free_ char *x = NULL;
1502 size_t allocated = 0, n = 0;
1507 /* Reads a NUL-terminated string from the specified file. */
1512 if (!GREEDY_REALLOC(x, allocated, n+2))
1516 if (c == 0) /* Terminate at NUL byte */
1521 break; /* Terminate at EOF */
1541 int mkdtemp_malloc(const char *template, char **ret) {
1547 p = strdup(template);
1561 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
1563 int read_line(FILE *f, size_t limit, char **ret) {
1564 _cleanup_free_ char *buffer = NULL;
1565 size_t n = 0, allocated = 0, count = 0;
1569 /* Something like a bounded version of getline().
1571 * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1574 * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1575 * the number of characters in the returned string). When EOF is hit, 0 is returned.
1577 * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1578 * delimiters. If the limit is hit we fail and return -ENOBUFS.
1580 * If a line shall be skipped ret may be initialized as NULL. */
1583 if (!GREEDY_REALLOC(buffer, allocated, 1))
1588 _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
1598 c = fgetc_unlocked(f);
1600 /* if we read an error, and have no data to return, then propagate the error */
1601 if (ferror_unlocked(f) && n == 0)
1602 return errno > 0 ? -errno : -EIO;
1609 if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
1613 if (!GREEDY_REALLOC(buffer, allocated, n + 2))
1616 buffer[n] = (char) c;