From 9bb1720cca710e5954d7084f4a74c8e930aaa156 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 7 Apr 2023 15:39:10 +0200 Subject: [PATCH] libc: Add execvp() and execvpe() --- apps/sh.cpp | 46 +------------------------------------------ libc/include/unistd.h | 6 +++++- libc/src/unistd.cpp | 43 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/apps/sh.cpp b/apps/sh.cpp index 7a8d1a45..2695d33e 100644 --- a/apps/sh.cpp +++ b/apps/sh.cpp @@ -31,50 +31,6 @@ static Result> split_command_into_argv(const char* cmd) return result; } -static Result join_path(const char* str1, const char* str2) -{ - StringBuilder sb; - TRY(sb.add(StringView { str1 })); - TRY(sb.add(StringView { str2 })); - return sb.string(); -} - -static int execute_in_path(const char* dir, char** argv) -{ - String path; - bool ok = join_path(dir, argv[0]).try_move_value_or_error(path, errno); - if (!ok) return -1; - - int err = errno; - - int status = execv(path.chars(), argv); - - if (errno == ENOENT) - { - errno = err; - return 0; - } - - return status; -} - -static int sh_execvp(char** argv) -{ - if (strchr(argv[0], '/')) - { - // Relative paths do not need path resolution. - return execv(argv[0], argv); - } - - if (execute_in_path("/bin/", argv) != 0) return -1; - if (execute_in_path("/sbin/", argv) != 0) return -1; - if (execute_in_path("/usr/bin/", argv) != 0) return -1; - if (execute_in_path("/usr/local/bin/", argv) != 0) return -1; - - errno = ENOENT; - return -1; -} - int main() { while (1) @@ -105,7 +61,7 @@ int main() } if (argv[0] == NULL) return 0; - sh_execvp(argv.data()); + execvp(argv[0], argv.data()); perror(argv[0]); return 1; } diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 859ba4bb..ca851079 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -37,7 +37,11 @@ extern "C" /* Replace the current process with another one. On success, does not return. */ int execve(const char* path, char* const* argv, char* const* envp); - int execvp(const char*, char* const*); + /* Replace the current process with another one. On success, does not return. */ + int execvp(const char* name, char* const* argv); + + /* Replace the current process with another one. On success, does not return. */ + int execvpe(const char* name, char* const* argv, char* const* envp); /* Call the operating system kernel for a specific service. */ long syscall(long num, ...); diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 423bf17b..fba619e9 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include +#include #include #include @@ -40,6 +42,47 @@ extern "C" __errno_return(rc, int); } + int execvpe(const char* name, char* const* argv, char* const* envp) + { + if (strchr(name, '/')) return execve(name, argv, envp); + + char* path = getenv("PATH"); + if (!path) path = const_cast("/bin:/sbin"); + + Vector paths; + bool ok = StringView { path }.split(":").try_move_value_or_error(paths, errno); + if (!ok) return -1; + + for (const auto& dir : paths) + { + // FIXME: Check for errors. + StringBuilder sb; + sb.add(dir); + sb.add('/'); + sb.add(StringView { name }); + + String file; + ok = sb.string().try_move_value_or_error(file, errno); + if (!ok) return -1; + + int err = errno; + execve(file.chars(), argv, envp); + + if (errno != ENOENT && errno != EACCES) return -1; + + // FIXME: POSIX says that if errno == ENOEXEC, we should run /bin/sh . + + if (err == EACCES) errno = err; + } + + return -1; + } + + int execvp(const char* name, char* const* argv) + { + return execvpe(name, argv, environ); + } + int execl(const char* path, const char* arg, ...) { va_list ap;