]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/path-util.c
path-util: rework find_binary(), fsck_exists() and mkfs_exists()
[thirdparty/systemd.git] / src / basic / path-util.c
index 5cbfc145a48c843131b7ec5305abcfd326b73eaa..9aeb8c23fd8bc269dc6dee6be64bd8e299083ba3 100644 (file)
@@ -698,7 +698,6 @@ int path_is_os_tree(const char *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;
 
@@ -709,56 +708,67 @@ int path_is_os_tree(const char *path) {
         return r >= 0;
 }
 
-int find_binary(const char *name, bool local, char **filename) {
+int find_binary(const char *name, char **ret) {
+        int last_error, r;
+        const char *p;
+
         assert(name);
 
         if (is_path(name)) {
-                if (local && access(name, X_OK) < 0)
+                if (access(name, X_OK) < 0)
                         return -errno;
 
-                if (filename) {
-                        char *p;
+                if (ret) {
+                        char *rs;
 
-                        p = path_make_absolute_cwd(name);
-                        if (!p)
+                        rs = path_make_absolute_cwd(name);
+                        if (!rs)
                                 return -ENOMEM;
 
-                        *filename = p;
+                        *ret = rs;
                 }
 
                 return 0;
-        } else {
-                const char *path;
-                const char *word, *state;
-                size_t l;
-
-                /**
-                 * Plain getenv, not secure_getenv, because we want
-                 * to actually allow the user to pick the binary.
-                 */
-                path = getenv("PATH");
-                if (!path)
-                        path = DEFAULT_PATH;
-
-                FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
-                        _cleanup_free_ char *p = NULL;
-
-                        if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
-                                return -ENOMEM;
+        }
 
-                        if (access(p, X_OK) < 0)
-                                continue;
+        /**
+         * Plain getenv, not secure_getenv, because we want
+         * to actually allow the user to pick the binary.
+         */
+        p = getenv("PATH");
+        if (!p)
+                p = DEFAULT_PATH;
+
+        last_error = -ENOENT;
+
+        for (;;) {
+                _cleanup_free_ char *j = NULL, *element = NULL;
 
-                        if (filename) {
-                                *filename = path_kill_slashes(p);
-                                p = NULL;
+                r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                j = strjoin(element, "/", name, NULL);
+                if (!j)
+                        return -ENOMEM;
+
+                if (access(j, X_OK) >= 0) {
+                        /* Found it! */
+
+                        if (ret) {
+                                *ret = path_kill_slashes(j);
+                                j = NULL;
                         }
 
                         return 0;
                 }
 
-                return -ENOENT;
+                last_error = -errno;
         }
+
+        return last_error;
 }
 
 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
@@ -796,14 +806,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
         return changed;
 }
 
-int fsck_exists(const char *fstype) {
+static int binary_is_good(const char *binary) {
         _cleanup_free_ char *p = NULL, *d = NULL;
-        const char *checker;
         int r;
 
-        checker = strjoina("fsck.", fstype);
-
-        r = find_binary(checker, true, &p);
+        r = find_binary(binary, &p);
+        if (r == -ENOENT)
+                return 0;
         if (r < 0)
                 return r;
 
@@ -811,13 +820,39 @@ int fsck_exists(const char *fstype) {
          * fsck */
 
         r = readlink_malloc(p, &d);
-        if (r >= 0 &&
-            (path_equal(d, "/bin/true") ||
-             path_equal(d, "/usr/bin/true") ||
-             path_equal(d, "/dev/null")))
-                return -ENOENT;
+        if (r == -EINVAL) /* not a symlink */
+                return 1;
+        if (r < 0)
+                return r;
 
-        return 0;
+        return !path_equal(d, "true") &&
+               !path_equal(d, "/bin/true") &&
+               !path_equal(d, "/usr/bin/true") &&
+               !path_equal(d, "/dev/null");
+}
+
+int fsck_exists(const char *fstype) {
+        const char *checker;
+
+        assert(fstype);
+
+        if (streq(fstype, "auto"))
+                return -EINVAL;
+
+        checker = strjoina("fsck.", fstype);
+        return binary_is_good(checker);
+}
+
+int mkfs_exists(const char *fstype) {
+        const char *mkfs;
+
+        assert(fstype);
+
+        if (streq(fstype, "auto"))
+                return -EINVAL;
+
+        mkfs = strjoina("mkfs.", fstype);
+        return binary_is_good(mkfs);
 }
 
 char *prefix_root(const char *root, const char *path) {