]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fileio: add new read_boolean_file() helper
authorLennart Poettering <lennart@amutable.com>
Wed, 6 May 2026 13:17:36 +0000 (15:17 +0200)
committerLennart Poettering <lennart@amutable.com>
Mon, 11 May 2026 10:04:02 +0000 (12:04 +0200)
src/basic/fileio.c
src/basic/fileio.h
src/test/test-fileio.c

index 31e9af2e4e03f1212fce0380518f5989969e78fa..8149bb8b0dd442875386bc4675127f29df5d5a29 100644 (file)
@@ -431,6 +431,20 @@ int read_one_line_file_at(int dir_fd, const char *filename, char **ret) {
         return read_line(f, LONG_LINE_MAX, ret);
 }
 
+int read_boolean_file_at(int dir_fd, const char *filename) {
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
+        assert(filename);
+
+        r = read_one_line_file_at(dir_fd, filename, &s);
+        if (r < 0)
+                return r;
+
+        return parse_boolean(s);
+}
+
 int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *buf = NULL;
index 274fdfbd7c89a328defc5f973f77c9f40910d332..5e6e3de1fef5730afeb583a775a666d7b6c5cbbc 100644 (file)
@@ -63,6 +63,10 @@ int read_one_line_file_at(int dir_fd, const char *filename, char **ret);
 static inline int read_one_line_file(const char *filename, char **ret) {
         return read_one_line_file_at(AT_FDCWD, filename, ret);
 }
+int read_boolean_file_at(int dir_fd, const char *filename);
+static inline int read_boolean_file(const char *filename) {
+        return read_boolean_file_at(AT_FDCWD, filename);
+}
 int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
 static inline int read_full_file_at(int dir_fd, const char *filename, char **ret_contents, size_t *ret_size) {
         return read_full_file_full(dir_fd, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
index d27bf7ab5d8243ce9f0782fdd109bf0a8fbb4f0a..d050522028f6d6b9d29210cbfbc4b1a6ff7d8dc1 100644 (file)
@@ -823,4 +823,58 @@ TEST(read_one_line_file_at_xat_fdroot) {
         ASSERT_OK(pidref_wait_for_terminate_and_check("(server)", &pidref, WAIT_LOG));
 }
 
+TEST(read_boolean_file) {
+        _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-read-boolean-file-XXXXXX";
+        _cleanup_close_ int fd = -EBADF, dfd = -EBADF;
+        const char *rel;
+
+        ASSERT_OK(fd = mkostemp_safe(fn));
+
+        ASSERT_OK(write_string_file(fn, "yes", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file(fn), true);
+        ASSERT_OK_EQ(read_boolean_file_at(AT_FDCWD, fn), true);
+
+        ASSERT_OK(write_string_file(fn, "0", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file(fn), false);
+        ASSERT_OK_EQ(read_boolean_file_at(AT_FDCWD, fn), false);
+
+        ASSERT_OK(write_string_file(fn, "true\nignored\n", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file(fn), true);
+
+        ASSERT_OK(write_string_file(fn, "garbage", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_ERROR(read_boolean_file(fn), EINVAL);
+
+        ASSERT_ERROR(read_boolean_file("/tmp/this-file-better-not-exist-XXX"), ENOENT);
+
+        /* Now test XAT_FDROOT: filename is relative, looked up against "/" */
+        ASSERT_TRUE(path_startswith(fn, "/"));
+        rel = fn + 1;
+
+        ASSERT_OK(write_string_file(fn, "on", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file_at(XAT_FDROOT, rel), true);
+
+        ASSERT_OK(write_string_file(fn, "off", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file_at(XAT_FDROOT, rel), false);
+
+        ASSERT_ERROR(read_boolean_file_at(XAT_FDROOT, "tmp/this-file-better-not-exist-XXX"), ENOENT);
+
+        /* And confirm XAT_FDROOT ignores the cwd: chdir somewhere unrelated, then look up
+         * the same relative-to-/ path. */
+        _cleanup_free_ char *cwd = NULL;
+        ASSERT_OK(safe_getcwd(&cwd));
+        ASSERT_OK_ERRNO(chdir("/usr"));
+
+        ASSERT_OK(write_string_file(fn, "yes", WRITE_STRING_FILE_TRUNCATE));
+        ASSERT_OK_EQ(read_boolean_file_at(XAT_FDROOT, rel), true);
+
+        ASSERT_OK_ERRNO(chdir(cwd));
+
+        /* Also test the dir_fd >= 0 path using an actual fd for /tmp. */
+        ASSERT_OK(dfd = open("/tmp", O_DIRECTORY|O_CLOEXEC));
+        ASSERT_OK(write_string_file(fn, "1", WRITE_STRING_FILE_TRUNCATE));
+        _cleanup_free_ char *bn = NULL;
+        ASSERT_OK(path_extract_filename(fn, &bn));
+        ASSERT_OK_EQ(read_boolean_file_at(dfd, bn), true);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);