diff --git a/libc/include/unistd.h b/libc/include/unistd.h index bf985d82..b3145c73 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -64,6 +64,9 @@ extern "C" /* Replace the current process with another one. On success, does not return. */ int execl(const char* path, const char* arg, ...); + /* Replace the current process with another one. On success, does not return. */ + int execle(const char* path, const char* arg, ...); + /* Replace the current process with another one. On success, does not return. */ int execve(const char* path, char* const* argv, char* const* envp); diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 5f0d1fa1..d192ec90 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -15,6 +15,71 @@ extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintp extern char** environ; +static Result try_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 = TRY(StringView { path }.split(":")); + + for (const auto& dir : paths) + { + StringBuilder sb; + TRY(sb.add(dir)); + TRY(sb.add('/')); + TRY(sb.add(StringView { name })); + + String file = TRY(sb.string()); + + int err = errno; + execve(file.chars(), argv, envp); + + if (errno != ENOENT && errno != EACCES && errno != ENOEXEC) return -1; + + if (errno == ENOEXEC) + { + Vector shell_argv; + TRY(shell_argv.try_append(const_cast("sh"))); + char* const* arg = argv; + do { + TRY(shell_argv.try_append(*arg)); + } while (*(arg++)); + + execve("/bin/sh", shell_argv.data(), envp); + errno = ENOEXEC; + return -1; + } + + if (err == EACCES) errno = err; + } + + return -1; +} + +static Result try_execl(const char* path, const char* arg, bool use_environ, va_list ap) +{ + Vector args; + TRY(args.try_append(const_cast(arg))); + + while (true) + { + char* str = va_arg(ap, char*); + TRY(args.try_append(str)); + if (!str) break; + } + + if (use_environ) + { + char* const* envp = va_arg(ap, char* const*); + + return execve(path, args.data(), envp); + } + + return execv(path, args.data()); +} + extern "C" { pid_t fork(void) @@ -102,50 +167,13 @@ extern "C" 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) + auto rc = try_execvpe(name, argv, envp); + if (rc.has_error()) { - // 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 && errno != ENOEXEC) return -1; - - if (errno == ENOEXEC) - { - Vector shell_argv; - shell_argv.try_append(const_cast("sh")); - char* const* arg = argv; - do { - shell_argv.try_append(*arg); - } while (*(arg++)); - - execve("/bin/sh", shell_argv.data(), envp); - errno = ENOEXEC; - return -1; - } - - if (err == EACCES) errno = err; + errno = rc.error(); + return -1; } - - return -1; + return rc.value(); } int execvp(const char* name, char* const* argv) @@ -158,19 +186,33 @@ extern "C" va_list ap; va_start(ap, arg); - Vector args; - if (args.try_append(const_cast(arg)).has_error()) return -1; - - while (true) - { - char* str = va_arg(ap, char*); - if (args.try_append(str).has_error()) return -1; - if (!str) break; - } + auto rc = try_execl(path, arg, false, ap); va_end(ap); - return execv(path, args.data()); + if (rc.has_error()) + { + errno = rc.error(); + return -1; + } + return rc.value(); + } + + int execle(const char* path, const char* arg, ...) + { + va_list ap; + va_start(ap, arg); + + auto rc = try_execl(path, arg, true, ap); + + va_end(ap); + + if (rc.has_error()) + { + errno = rc.error(); + return -1; + } + return rc.value(); } long syscall(long num, ...)