Browse Source

LibCore: Add function for searching a file in $PATH

This extracts the logic of searching for a file in $PATH from
System::exec to a separate function.
Itamar 3 years ago
parent
commit
91a03bc6ae
2 changed files with 21 additions and 21 deletions
  1. 20 21
      Userland/Libraries/LibCore/System.cpp
  2. 1 0
      Userland/Libraries/LibCore/System.h

+ 20 - 21
Userland/Libraries/LibCore/System.cpp

@@ -12,6 +12,7 @@
 #include <AK/StdLibExtras.h>
 #include <AK/String.h>
 #include <AK/Vector.h>
+#include <LibCore/File.h>
 #include <LibCore/System.h>
 #include <limits.h>
 #include <stdarg.h>
@@ -931,6 +932,22 @@ ErrorOr<void> adjtime(const struct timeval* delta, struct timeval* old_delta)
 }
 #endif
 
+ErrorOr<String> find_file_in_path(StringView filename)
+{
+    auto const* path_ptr = getenv("PATH");
+    StringView path { path_ptr, strlen(path_ptr) };
+    if (path.is_empty())
+        path = "/bin:/usr/bin"sv;
+    auto parts = path.split_view(':');
+    for (auto& part : parts) {
+        auto candidate = String::formatted("{}/{}", part, filename);
+        if (Core::File::exists(candidate)) {
+            return candidate;
+        }
+    }
+    return Error::from_errno(ENOENT);
+}
+
 ErrorOr<void> exec(StringView filename, Span<StringView> arguments, SearchInPath search_in_path, Optional<Span<StringView>> environment)
 {
 #ifdef __serenity__
@@ -971,28 +988,10 @@ ErrorOr<void> exec(StringView filename, Span<StringView> arguments, SearchInPath
         return {};
     };
 
-    if (search_in_path == SearchInPath::Yes && !filename.contains('/')) {
-        auto const* path_ptr = getenv("PATH");
-        StringView path { path_ptr, strlen(path_ptr) };
-        if (path.is_empty())
-            path = "/bin:/usr/bin"sv;
-        auto parts = path.split_view(':');
-        for (auto& part : parts) {
-            auto candidate = String::formatted("{}/{}", part, filename);
-            params.path = { candidate.characters(), candidate.length() };
-            auto result = run_exec(params);
-            if (result.is_error()) {
-                if (result.error().code() != ENOENT)
-                    return result.error();
-            } else {
-                VERIFY_NOT_REACHED();
-            }
-        }
-        return Error::from_syscall("exec"sv, -ENOENT);
-    } else {
-        params.path = { filename.characters_without_null_termination(), filename.length() };
-    }
+    bool should_search_in_path = search_in_path == SearchInPath::Yes && !filename.contains('/');
+    String exec_filename = should_search_in_path ? TRY(find_file_in_path(filename)) : filename.to_string();
 
+    params.path = { exec_filename.characters(), exec_filename.length() };
     TRY(run_exec(params));
     VERIFY_NOT_REACHED();
 #else

+ 1 - 0
Userland/Libraries/LibCore/System.h

@@ -160,6 +160,7 @@ ErrorOr<Array<int, 2>> pipe2(int flags);
 #ifndef AK_OS_ANDROID
 ErrorOr<void> adjtime(const struct timeval* delta, struct timeval* old_delta);
 #endif
+ErrorOr<String> find_file_in_path(StringView filename);
 enum class SearchInPath {
     No,
     Yes,