util-lib: beef path_is_os_tree() up a bit
authorLennart Poettering <lennart@poettering.net>
Thu, 8 Dec 2016 16:19:27 +0000 (17:19 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 20 Dec 2016 19:00:08 +0000 (20:00 +0100)
Let's use chase_symlinks() when looking for /etc/os-release and
/usr/lib/os-release as these files might be symlinks (and actually are IRL on
some distros).

src/basic/stat-util.c
src/test/test-stat-util.c

index 309e84b..5663a29 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "dirent-util.h"
 #include "fd-util.h"
+#include "fs-util.h"
 #include "macro.h"
 #include "missing.h"
 #include "stat-util.h"
@@ -143,22 +144,29 @@ int path_is_read_only_fs(const char *path) {
 }
 
 int path_is_os_tree(const char *path) {
-        char *p;
         int r;
 
         assert(path);
 
-        /* We use /usr/lib/os-release as flag file if something is an OS */
-        p = strjoina(path, "/usr/lib/os-release");
-        r = access(p, F_OK);
-        if (r >= 0)
-                return 1;
+        /* 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;
 
-        /* Also check for the old location in /etc, just in case. */
-        p = strjoina(path, "/etc/os-release");
-        r = access(p, F_OK);
+        /* 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 r >= 0;
+        return 1;
 }
 
 int files_same(const char *filea, const char *fileb) {
index 6c34250..10fc4af 100644 (file)
@@ -60,9 +60,16 @@ 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);
+}
+
 int main(int argc, char *argv[]) {
         test_files_same();
         test_is_symlink();
+        test_path_is_os_tree();
 
         return 0;
 }