chiark / gitweb /
fileio: return 0 from read_one_line_file on success
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 24 Sep 2017 12:27:21 +0000 (14:27 +0200)
committerSven Eden <yamakuzure@gmx.net>
Wed, 22 Nov 2017 07:22:23 +0000 (08:22 +0100)
Fixup for f4b51a2d09. Suggested by Evgeny Vereshchagin.

src/basic/def.h
src/basic/fileio.c
src/basic/fileio.h
src/basic/log.c
src/libelogind/sd-event/test-event.c
src/sleep/sleep.c
src/test/meson.build
src/test/test-cgroup.c
src/test/test-log.c
src/test/test-signal-util.c

index d30b4a106b9ba04ee2639a19dbb8a3969e338098..1571f921b739c48ddcd14724f5cfaf5a42c4367d 100644 (file)
@@ -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)
index 333effa5ffbefd6a4bb3b1965e21b8ae23fe01bd..3990d4dcef6093bcae8d8c27b1e73d9f406567f7 100644 (file)
@@ -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"
 
 #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;
+}
index a56887555d015b63019fa0ad68d51d152799d0ff..1160c58495b9d07e462eba903c6094ae3ce67c88 100644 (file)
@@ -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);
index c02a73a947ab0f4d9e50602a497f8b43634f0157..21f37c36e50d58770eadfe94359f62d275471f98 100644 (file)
@@ -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,
index 656f08d5618ffdecc6c61016028b94705f517096..d57f5fa8cf25615ed42ff5634a0efaed406952e6 100644 (file)
 #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));
index c6dd13197eb46a0b10f4b2aea602e6fda18ee289..01fa223490e2fd84b7150909c9819419e2594a06 100644 (file)
@@ -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",
index 6059c2efd53091c019628570993e53ee9ea5fa86..c811dd675caa0e82f58ab38bbcb70a5e2f1a4dbe 100644 (file)
@@ -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',
index 2ed91c78098f0f37ad1233f37cb4a2b97a6157fc..509946250840106abb0da00d39262653ee9b7a7b 100644 (file)
 
 #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;
index ec1bc2a635389222424ede4cdcbfa6fab7199ba8..2417b3aefcad60fd4cbb26b961c40018258fb736 100644 (file)
@@ -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);
index 1830396acfa85741c6577ca014af599ed5efd85b..0db8a1e32180d13893bd90ec2de577c7fb453df9 100644 (file)
@@ -21,8 +21,9 @@
 #include <unistd.h>
 
 #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;