From 68bb1246bf0dc56f61b6d655694ddd4df647167c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 24 Sep 2017 14:27:21 +0200 Subject: fileio: return 0 from read_one_line_file on success Fixup for f4b51a2d09. Suggested by Evgeny Vereshchagin. --- src/basic/def.h | 2 + src/basic/fileio.c | 160 +++++++++++++++++++++++------------ src/basic/fileio.h | 4 +- src/basic/log.c | 2 +- src/libelogind/sd-event/test-event.c | 3 +- src/sleep/sleep.c | 2 +- src/test/meson.build | 20 ++--- src/test/test-cgroup.c | 3 +- src/test/test-log.c | 3 +- src/test/test-signal-util.c | 3 +- 10 files changed, 130 insertions(+), 72 deletions(-) diff --git a/src/basic/def.h b/src/basic/def.h index d30b4a106..1571f921b 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -96,3 +96,5 @@ "/usr/local/lib/" n "\0" \ "/usr/lib/" n "\0" \ _CONF_PATHS_SPLIT_USR(n) + +#define LONG_LINE_MAX (1U*1024U*1024U) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 333effa5f..3990d4dce 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -30,6 +30,7 @@ #include "alloc-util.h" #include "ctype.h" +#include "def.h" #include "env-util.h" #include "escape.h" #include "fd-util.h" @@ -52,17 +53,13 @@ #define READ_FULL_BYTES_MAX (4U*1024U*1024U) -int write_string_stream_ts( - FILE *f, - const char *line, - WriteStringFileFlags flags, - struct timespec *ts) { +int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts) { assert(f); assert(line); fputs(line, f); - if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n")) + if (enforce_newline && !endswith(line, "\n")) fputc('\n', f); if (ts) { @@ -72,18 +69,10 @@ int write_string_stream_ts( return -errno; } - if (flags & WRITE_STRING_FILE_SYNC) - return fflush_sync_and_check(f); - else - return fflush_and_check(f); + return fflush_and_check(f); } -static int write_string_file_atomic( - const char *fn, - const char *line, - WriteStringFileFlags flags, - struct timespec *ts) { - +static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline, bool do_fsync) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; int r; @@ -97,28 +86,22 @@ static int write_string_file_atomic( (void) fchmod_umask(fileno(f), 0644); - r = write_string_stream_ts(f, line, flags, ts); - if (r < 0) - goto fail; + r = write_string_stream(f, line, enforce_newline); + if (r >= 0 && do_fsync) + r = fflush_sync_and_check(f); - if (rename(p, fn) < 0) { - r = -errno; - goto fail; + if (r >= 0) { + if (rename(p, fn) < 0) + r = -errno; } - return 0; + if (r < 0) + (void) unlink(p); -fail: - (void) unlink(p); return r; } -int write_string_file_ts( - const char *fn, - const char *line, - WriteStringFileFlags flags, - struct timespec *ts) { - +int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts) { _cleanup_fclose_ FILE *f = NULL; int q, r; @@ -131,7 +114,8 @@ int write_string_file_ts( if (flags & WRITE_STRING_FILE_ATOMIC) { assert(flags & WRITE_STRING_FILE_CREATE); - r = write_string_file_atomic(fn, line, flags, ts); + r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE), + flags & WRITE_STRING_FILE_SYNC); if (r < 0) goto fail; @@ -164,10 +148,16 @@ int write_string_file_ts( } } - r = write_string_stream_ts(f, line, flags, ts); + r = write_string_stream_ts(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE), ts); if (r < 0) goto fail; + if (flags & WRITE_STRING_FILE_SYNC) { + r = fflush_sync_and_check(f); + if (r < 0) + return r; + } + return 0; fail: @@ -188,7 +178,7 @@ fail: int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; - char t[LINE_MAX], *c; + int r; assert(fn); assert(line); @@ -197,21 +187,8 @@ int read_one_line_file(const char *fn, char **line) { if (!f) return -errno; - if (!fgets(t, sizeof(t), f)) { - - if (ferror(f)) - return errno > 0 ? -errno : -EIO; - - t[0] = 0; - } - - c = strdup(t); - if (!c) - return -ENOMEM; - truncate_nl(c); - - *line = c; - return 0; + r = read_line(f, LONG_LINE_MAX, line); + return r < 0 ? r : 0; } int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { @@ -270,11 +247,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { if (st.st_size > READ_FULL_BYTES_MAX) return -E2BIG; - /* Start with the right file size, but be prepared for files from /proc which generally report a file - * size of 0. Note that we increase the size to read here by one, so that the first read attempt - * already makes us notice the EOF. */ + /* Start with the right file size, but be prepared for + * files from /proc which generally report a file size + * of 0 */ if (st.st_size > 0) - n = st.st_size + 1; + n = st.st_size; } l = 0; @@ -287,13 +264,12 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { return -ENOMEM; buf = t; - errno = 0; k = fread(buf + l, 1, n - l, f); if (k > 0) l += k; if (ferror(f)) - return errno > 0 ? -errno : -EIO; + return -errno; if (feof(f)) break; @@ -1550,3 +1526,77 @@ int mkdtemp_malloc(const char *template, char **ret) { return 0; } #endif // 0 + +static inline void funlockfilep(FILE **f) { + funlockfile(*f); +} + +int read_line(FILE *f, size_t limit, char **ret) { + _cleanup_free_ char *buffer = NULL; + size_t n = 0, allocated = 0, count = 0; + + assert(f); + + /* Something like a bounded version of getline(). + * + * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string + * returned. + * + * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from + * the number of characters in the returned string). When EOF is hit, 0 is returned. + * + * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding + * delimiters. If the limit is hit we fail and return -ENOBUFS. + * + * If a line shall be skipped ret may be initialized as NULL. */ + + if (ret) { + if (!GREEDY_REALLOC(buffer, allocated, 1)) + return -ENOMEM; + } + + { + _cleanup_(funlockfilep) FILE *flocked = f; + flockfile(f); + + for (;;) { + int c; + + if (n >= limit) + return -ENOBUFS; + + errno = 0; + c = fgetc_unlocked(f); + if (c == EOF) { + /* if we read an error, and have no data to return, then propagate the error */ + if (ferror_unlocked(f) && n == 0) + return errno > 0 ? -errno : -EIO; + + break; + } + + count++; + + if (IN_SET(c, '\n', 0)) /* Reached a delimiter */ + break; + + if (ret) { + if (!GREEDY_REALLOC(buffer, allocated, n + 2)) + return -ENOMEM; + + buffer[n] = (char) c; + } + + n++; + } + } + + if (ret) { + buffer[n] = 0; + + *ret = buffer; + buffer = NULL; + } + + return (int) count; +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index a56887555..1160c5849 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -36,7 +36,7 @@ typedef enum { WRITE_STRING_FILE_SYNC = 1<<4, } WriteStringFileFlags; -int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts); +int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts); static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) { return write_string_stream_ts(f, line, flags, NULL); } @@ -113,3 +113,5 @@ int read_nul_string(FILE *f, char **ret); int mkdtemp_malloc(const char *template, char **ret); #endif // 0 + +int read_line(FILE *f, size_t limit, char **ret); diff --git a/src/basic/log.c b/src/basic/log.c index c02a73a94..21f37c36e 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -494,7 +494,6 @@ static int write_to_kmsg( return 1; } -#if 0 /// UNNEEDED by elogind static int log_do_header( char *header, size_t size, @@ -539,6 +538,7 @@ static int log_do_header( return 0; } +#if 0 /// UNNEEDED by elogind static int write_to_journal( int level, int error, diff --git a/src/libelogind/sd-event/test-event.c b/src/libelogind/sd-event/test-event.c index 656f08d56..d57f5fa8c 100644 --- a/src/libelogind/sd-event/test-event.c +++ b/src/libelogind/sd-event/test-event.c @@ -24,9 +24,10 @@ #include "fd-util.h" #include "log.h" #include "macro.h" -#include "process-util.h" #include "signal-util.h" #include "util.h" +/// Additional includes needed by elogind +#include "process-util.h" static int prepare_handler(sd_event_source *s, void *userdata) { log_info("preparing %c", PTR_TO_INT(userdata)); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index c6dd13197..01fa22349 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -69,7 +69,7 @@ static int write_state(FILE **f, char **states) { STRV_FOREACH(state, states) { int k; - k = write_string_stream(*f, *state, 0); + k = write_string_stream(*f, *state, true); if (k == 0) return 0; log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m", diff --git a/src/test/meson.build b/src/test/meson.build index 6059c2efd..c811dd675 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -365,16 +365,16 @@ tests += [ [libbasic], []], - [['src/test/test-bpf.c', - 'src/test/test-helper.c'], - [libcore, - libshared], - [libmount, - threads, - librt, - libseccomp, - libselinux, - libblkid]], +# [['src/test/test-bpf.c', +# 'src/test/test-helper.c'], +# [libcore, +# libshared], +# [libmount, +# threads, +# librt, +# libseccomp, +# libselinux, +# libblkid]], [['src/test/test-hashmap.c', 'src/test/test-hashmap-plain.c', diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 2ed91c780..509946250 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -22,9 +22,10 @@ #include "cgroup-util.h" #include "path-util.h" -#include "process-util.h" #include "string-util.h" #include "util.h" +/// Additional includes needed by elogind +#include "process-util.h" int main(int argc, char*argv[]) { char *path; diff --git a/src/test/test-log.c b/src/test/test-log.c index ec1bc2a63..2417b3aef 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -22,8 +22,9 @@ #include "format-util.h" #include "log.h" -#include "process-util.h" #include "util.h" +/// Additional includes needed by elogind +#include "process-util.h" assert_cc(LOG_REALM_REMOVE_LEVEL(LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, LOG_FTP | LOG_DEBUG)) == LOG_REALM_SYSTEMD); diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 1830396ac..0db8a1e32 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -21,8 +21,9 @@ #include #include "macro.h" -#include "process-util.h" #include "signal-util.h" +/// Additional includes needed by elogind +#include "process-util.h" static void test_block_signals(void) { sigset_t ss; -- cgit v1.2.3