]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
os-util: add helpers for finding /etc/os-release
authorLennart Poettering <lennart@poettering.net>
Mon, 26 Mar 2018 14:32:40 +0000 (16:32 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 24 May 2018 15:01:57 +0000 (17:01 +0200)
Place this new helpers in a new source file os-util.[ch], and move the
existing and related call path_is_os_tree() to it as well.

17 files changed:
src/basic/meson.build
src/basic/os-util.c [new file with mode: 0644]
src/basic/os-util.h [new file with mode: 0644]
src/basic/stat-util.c
src/basic/stat-util.h
src/core/dbus-manager.c
src/core/main.c
src/firstboot/firstboot.c
src/hostname/hostnamed.c
src/journal-remote/journal-gatewayd.c
src/machine/machine-dbus.c
src/nspawn/nspawn.c
src/shared/dissect-image.c
src/shared/machine-image.c
src/test/meson.build
src/test/test-os-util.c [new file with mode: 0644]
src/test/test-stat-util.c

index 69c525dcdc23fbae7bb69359584882beb5283e6e..0b2106807c0ac7c6db983972d4f43e30eb70a920 100644 (file)
@@ -131,6 +131,8 @@ basic_sources = files('''
         ordered-set.h
         pager.c
         pager.h
+        os-util.c
+        os-util.h
         parse-util.c
         parse-util.h
         path-util.c
diff --git a/src/basic/os-util.c b/src/basic/os-util.c
new file mode 100644 (file)
index 0000000..207594c
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "macro.h"
+#include "os-util.h"
+#include "strv.h"
+#include "fileio.h"
+#include "string-util.h"
+
+int path_is_os_tree(const char *path) {
+        int r;
+
+        assert(path);
+
+        /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
+         * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
+         * the case where just the os-release file is missing. */
+        if (laccess(path, F_OK) < 0)
+                return -errno;
+
+        /* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */
+        r = open_os_release(path, NULL, NULL);
+        if (r == -ENOENT) /* We got nothing */
+                return 0;
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+int open_os_release(const char *root, char **ret_path, int *ret_fd) {
+        _cleanup_free_ char *q = NULL;
+        const char *p;
+        int k;
+
+        FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
+                k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL));
+                if (k != -ENOENT)
+                        break;
+        }
+        if (k < 0)
+                return k;
+
+        if (ret_fd) {
+                int real_fd;
+
+                /* Convert the O_PATH fd into a proper, readable one */
+                real_fd = fd_reopen(k, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                safe_close(k);
+                if (real_fd < 0)
+                        return real_fd;
+
+                *ret_fd = real_fd;
+        }
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(q);
+
+        return 0;
+}
+
+int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -1;
+        FILE *f;
+        int r;
+
+        if (!ret_file)
+                return open_os_release(root, ret_path, NULL);
+
+        r = open_os_release(root, ret_path ? &p : NULL, &fd);
+        if (r < 0)
+                return r;
+
+        f = fdopen(fd, "re");
+        if (!f)
+                return -errno;
+        fd = -1;
+
+        *ret_file = f;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        return 0;
+}
+
+int parse_os_release(const char *root, ...) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        va_list ap;
+        int r;
+
+        r = fopen_os_release(root, &p, &f);
+        if (r < 0)
+                return r;
+
+        va_start(ap, root);
+        r = parse_env_filev(f, p, NEWLINE, ap);
+        va_end(ap);
+
+        return r;
+}
+
+int load_os_release_pairs(const char *root, char ***ret) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        r = fopen_os_release(root, &p, &f);
+        if (r < 0)
+                return r;
+
+        return load_env_file_pairs(f, p, NEWLINE, ret);
+}
diff --git a/src/basic/os-util.h b/src/basic/os-util.h
new file mode 100644 (file)
index 0000000..6b9e033
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdio.h>
+
+int path_is_os_tree(const char *path);
+
+int open_os_release(const char *root, char **ret_path, int *ret_fd);
+int fopen_os_release(const char *root, char **ret_path, FILE **ret_file);
+
+int parse_os_release(const char *root, ...);
+int load_os_release_pairs(const char *root, char ***ret);
index 61cc6f573815c4f0a57c45592ed5670761a5624c..1f0a75a0e8c80aae80453f7b935901db9c612e5b 100644 (file)
@@ -132,32 +132,6 @@ int path_is_read_only_fs(const char *path) {
         return false;
 }
 
-int path_is_os_tree(const char *path) {
-        int r;
-
-        assert(path);
-
-        /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
-         * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
-         * the case where just the os-release file is missing. */
-        if (laccess(path, F_OK) < 0)
-                return -errno;
-
-        /* We use /usr/lib/os-release as flag file if something is an OS */
-        r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
-        if (r == -ENOENT) {
-
-                /* Also check for the old location in /etc, just in case. */
-                r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
-                if (r == -ENOENT)
-                        return 0; /* We got nothing */
-        }
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
 int files_same(const char *filea, const char *fileb, int flags) {
         struct stat a, b;
 
index d1e8d330017ecefa75520e869fa39fdfa747c00c..02b1c47123bd660916c7d849a09d94cd3b0f4547 100644 (file)
@@ -35,7 +35,6 @@ int null_or_empty_path(const char *fn);
 int null_or_empty_fd(int fd);
 
 int path_is_read_only_fs(const char *path);
-int path_is_os_tree(const char *path);
 
 int files_same(const char *filea, const char *fileb, int flags);
 
index 13d7bd476f8edb619f15f48f4b536c4bdad1260c..f7535e38fc96f8f5a46323bf40cc2342e529124e 100644 (file)
@@ -26,6 +26,7 @@
 #include "fs-util.h"
 #include "install.h"
 #include "log.h"
+#include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "selinux-access.h"
index e7d89be3f4fbf19642ea751b5ce9852a0c6ab8b7..7e5a7c22b7a7df4242b4eceb2b9a61487143d1ff 100644 (file)
@@ -57,6 +57,7 @@
 #include "manager.h"
 #include "missing.h"
 #include "mount-setup.h"
+#include "os-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -1215,23 +1216,18 @@ static int enforce_syscall_archs(Set *archs) {
 
 static int status_welcome(void) {
         _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
-        const char *fn;
         int r;
 
         if (arg_show_status <= 0)
                 return 0;
 
-        FOREACH_STRING(fn, "/etc/os-release", "/usr/lib/os-release") {
-                r = parse_env_file(NULL, fn, NEWLINE,
-                                   "PRETTY_NAME", &pretty_name,
-                                   "ANSI_COLOR", &ansi_color,
-                                   NULL);
-
-                if (r != -ENOENT)
-                        break;
-        }
-        if (r < 0 && r != -ENOENT)
-                log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
+        r = parse_os_release(NULL,
+                             "PRETTY_NAME", &pretty_name,
+                             "ANSI_COLOR", &ansi_color,
+                             NULL);
+        if (r < 0)
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to read os-release file, ignoring: %m");
 
         if (log_get_show_color())
                 return status_printf(NULL, false, false,
index 9b091bf87a56fddb6607d2f840fb32786423b52e..0fc8bb891b4662628b8a284b939a6e302e3d3267 100644 (file)
@@ -33,6 +33,7 @@
 #include "hostname-util.h"
 #include "locale-util.h"
 #include "mkdir.h"
+#include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
@@ -79,27 +80,16 @@ static bool press_any_key(void) {
 
 static void print_welcome(void) {
         _cleanup_free_ char *pretty_name = NULL;
-        const char *os_release = NULL;
         static bool done = false;
         int r;
 
         if (done)
                 return;
 
-        os_release = prefix_roota(arg_root, "/etc/os-release");
-        r = parse_env_file(NULL, os_release, NEWLINE,
-                           "PRETTY_NAME", &pretty_name,
-                           NULL);
-        if (r == -ENOENT) {
-
-                os_release = prefix_roota(arg_root, "/usr/lib/os-release");
-                r = parse_env_file(NULL, os_release, NEWLINE,
-                                   "PRETTY_NAME", &pretty_name,
-                                   NULL);
-        }
-
-        if (r < 0 && r != -ENOENT)
-                log_warning_errno(r, "Failed to read os-release file: %m");
+        r = parse_os_release(arg_root, "PRETTY_NAME", &pretty_name, NULL);
+        if (r < 0)
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to read os-release file, ignoring: %m");
 
         printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n",
                isempty(pretty_name) ? "Linux" : pretty_name);
index db54e472c64039b4747922bc84922ed0ecb7897f..28fc628742a8f074f33eeea9784f476f8897309a 100644 (file)
@@ -16,6 +16,7 @@
 #include "env-util.h"
 #include "fileio-label.h"
 #include "hostname-util.h"
+#include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "selinux-util.h"
@@ -98,18 +99,11 @@ static int context_read_data(Context *c) {
         if (r < 0 && r != -ENOENT)
                 return r;
 
-        r = parse_env_file(NULL, "/etc/os-release", NEWLINE,
-                           "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
-                           "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
-                           "HOME_URL", &c->data[PROP_HOME_URL],
-                           NULL);
-        if (r == -ENOENT)
-                r = parse_env_file(NULL, "/usr/lib/os-release", NEWLINE,
-                                   "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
-                                   "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
-                                   "HOME_URL", &c->data[PROP_HOME_URL],
-                                   NULL);
-
+        r = parse_os_release(NULL,
+                             "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
+                             "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
+                             "HOME_URL", &c->data[PROP_HOME_URL],
+                             NULL);
         if (r < 0 && r != -ENOENT)
                 return r;
 
index f80ca7e671d86a10d635083ad0bea356624f6b22..c29b65764af7b9370a1d299c9dc4f8ea64434b08 100644 (file)
@@ -24,6 +24,7 @@
 #include "log.h"
 #include "logs-show.h"
 #include "microhttpd-util.h"
+#include "os-util.h"
 #include "parse-util.h"
 #include "sigbus.h"
 #include "util.h"
@@ -777,10 +778,8 @@ static int request_handler_machine(
         if (r < 0)
                 return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m");
 
-        if (parse_env_file(NULL, "/etc/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL) == -ENOENT)
-                (void) parse_env_file(NULL, "/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL);
-
-        get_virtualization(&v);
+        (void) parse_os_release(NULL, "PRETTY_NAME", &os_name, NULL);
+        (void) get_virtualization(&v);
 
         r = asprintf(&json,
                      "{ \"machine_id\" : \"" SD_ID128_FORMAT_STR "\","
index 058543fbb21a0312f0b564869fa3978b0096c116..d7921cf8cf24032e4fc514406b5ec49b177fa9cf 100644 (file)
@@ -32,6 +32,7 @@
 #include "machine-dbus.h"
 #include "machine.h"
 #include "mkdir.h"
+#include "os-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
@@ -330,7 +331,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
         switch (m->class) {
 
         case MACHINE_HOST:
-                r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l);
+                r = load_os_release_pairs(NULL, &l);
                 if (r < 0)
                         return r;
 
@@ -361,13 +362,10 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
                         if (r < 0)
                                 _exit(EXIT_FAILURE);
 
-                        fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                        if (fd < 0 && errno == ENOENT) {
-                                fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                                if (fd < 0 && errno == ENOENT)
-                                        _exit(EXIT_NOT_FOUND);
-                        }
-                        if (fd < 0)
+                        r = open_os_release(NULL, NULL, &fd);
+                        if (r == -ENOENT)
+                                _exit(EXIT_NOT_FOUND);
+                        if (r < 0)
                                 _exit(EXIT_FAILURE);
 
                         r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
index 56c26aae8e92aaf32a85aab18f0b0d337aaf2752..4c157cf6544a2730a5064543ce43923edbfe8408 100644 (file)
@@ -77,6 +77,7 @@
 #include "nspawn-settings.h"
 #include "nspawn-setuid.h"
 #include "nspawn-stub-pid1.h"
+#include "os-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
index 608e4b51ac48c440a312d88fd8c647b554920d83..59ee4fe9e589c844198c5c805946011051b163b2 100644 (file)
@@ -30,6 +30,7 @@
 #include "linux-3.13/dm-ioctl.h"
 #include "missing.h"
 #include "mount-util.h"
+#include "os-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
index 440b1f574f44a245adfae1c144edba26c76c2f78..44cb371da611f0963df3255438c430b1049776b3 100644 (file)
@@ -35,6 +35,7 @@
 #include "machine-image.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "os-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "string-table.h"
@@ -923,6 +924,7 @@ int image_read_metadata(Image *i) {
                 sd_id128_t machine_id = SD_ID128_NULL;
                 _cleanup_free_ char *hostname = NULL;
                 _cleanup_free_ char *path = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
 
                 r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
                 if (r < 0 && r != -ENOENT)
@@ -962,18 +964,9 @@ int image_read_metadata(Image *i) {
                                 log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
                 }
 
-                path = mfree(path);
-
-                r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
-                if (r == -ENOENT)
-                        r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
-                if (r < 0 && r != -ENOENT)
-                        log_debug_errno(r, "Failed to chase os-release in image: %m");
-                else if (r >= 0) {
-                        r = load_env_file_pairs(NULL, path, NULL, &os_release);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name);
-                }
+                r = load_os_release_pairs(i->path, &os_release);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to read os-release in image, ignoring: %m");
 
                 free_and_replace(i->hostname, hostname);
                 i->machine_id = machine_id;
index 4a9982240bc004e389b9a54a2897929d57b64aee..619f0cd823b0863c8d8a438b6aafa9a62fcf79cf 100644 (file)
@@ -242,6 +242,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-os-util.c'],
+         [],
+         []],
+
         [['src/test/test-escape.c'],
          [],
          []],
diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c
new file mode 100644 (file)
index 0000000..8d8b52d
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "log.h"
+#include "os-util.h"
+
+static void test_path_is_os_tree(void) {
+        assert_se(path_is_os_tree("/") > 0);
+        assert_se(path_is_os_tree("/etc") == 0);
+        assert_se(path_is_os_tree("/idontexist") == -ENOENT);
+}
+
+int main(int argc, char *argv[]) {
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+        log_open();
+
+        test_path_is_os_tree();
+
+        return 0;
+}
index 6c9c132612a64cf326f72081003324ecc2303763..1697b2d777f99e57c4e5469a8649a7166261db6d 100644 (file)
@@ -52,12 +52,6 @@ static void test_is_symlink(void) {
         unlink(name_link);
 }
 
-static void test_path_is_os_tree(void) {
-        assert_se(path_is_os_tree("/") > 0);
-        assert_se(path_is_os_tree("/etc") == 0);
-        assert_se(path_is_os_tree("/idontexist") == -ENOENT);
-}
-
 static void test_path_is_fs_type(void) {
         /* run might not be a mount point in build chroots */
         if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) {
@@ -81,7 +75,6 @@ static void test_path_is_temporary_fs(void) {
 int main(int argc, char *argv[]) {
         test_files_same();
         test_is_symlink();
-        test_path_is_os_tree();
         test_path_is_fs_type();
         test_path_is_temporary_fs();