diff --git a/Shell/Builtin.cpp b/Shell/Builtin.cpp index e19e8cfce3..3a7e6c884a 100644 --- a/Shell/Builtin.cpp +++ b/Shell/Builtin.cpp @@ -256,6 +256,20 @@ int Shell::builtin_dirs(int argc, const char** argv) return 0; } +int Shell::builtin_exec(int argc, const char** argv) +{ + if (argc < 2) { + fprintf(stderr, "Shell: No command given to exec\n"); + return 1; + } + + Vector argv_vector; + argv_vector.append(argv + 1, argc - 1); + argv_vector.append(nullptr); + + execute_process(move(argv_vector)); +} + int Shell::builtin_exit(int argc, const char** argv) { int exit_code = 0; diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 6ef5a6efa7..2366a7488a 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -789,42 +789,7 @@ RefPtr Shell::run_command(const AST::Command& command) // We no longer need the jobs here. jobs.clear(); - int rc = execvp(argv[0], const_cast(argv.data())); - if (rc < 0) { - int saved_errno = errno; - struct stat st; - if (stat(argv[0], &st)) { - fprintf(stderr, "stat(%s): %s\n", argv[0], strerror(errno)); - _exit(126); - } - if (!(st.st_mode & S_IXUSR)) { - fprintf(stderr, "%s: Not executable\n", argv[0]); - _exit(126); - } - if (saved_errno == ENOENT) { - int shebang_fd = open(argv[0], O_RDONLY); - auto close_argv = ScopeGuard([shebang_fd]() { if (shebang_fd >= 0) close(shebang_fd); }); - char shebang[256] {}; - ssize_t num_read = -1; - if ((shebang_fd >= 0) && ((num_read = read(shebang_fd, shebang, sizeof(shebang))) >= 2) && (StringView(shebang).starts_with("#!"))) { - StringView shebang_path_view(&shebang[2], num_read - 2); - Optional newline_pos = shebang_path_view.find_first_of("\n\r"); - shebang[newline_pos.has_value() ? (newline_pos.value() + 2) : num_read] = '\0'; - argv[0] = shebang; - int rc = execvp(argv[0], const_cast(argv.data())); - if (rc < 0) - fprintf(stderr, "%s: Invalid interpreter \"%s\": %s\n", argv[0], &shebang[2], strerror(errno)); - } else - fprintf(stderr, "%s: Command not found.\n", argv[0]); - } else { - if (S_ISDIR(st.st_mode)) { - fprintf(stderr, "Shell: %s: Is a directory\n", argv[0]); - _exit(126); - } - fprintf(stderr, "execvp(%s): %s\n", argv[0], strerror(saved_errno)); - } - _exit(126); - } + execute_process(move(argv)); ASSERT_NOT_REACHED(); } @@ -893,6 +858,47 @@ RefPtr Shell::run_command(const AST::Command& command) return *job; } +void Shell::execute_process(Vector&& argv) +{ + int rc = execvp(argv[0], const_cast(argv.data())); + if (rc < 0) { + int saved_errno = errno; + struct stat st; + if (stat(argv[0], &st)) { + fprintf(stderr, "stat(%s): %s\n", argv[0], strerror(errno)); + _exit(126); + } + if (!(st.st_mode & S_IXUSR)) { + fprintf(stderr, "%s: Not executable\n", argv[0]); + _exit(126); + } + if (saved_errno == ENOENT) { + int shebang_fd = open(argv[0], O_RDONLY); + auto close_argv = ScopeGuard([shebang_fd]() { if (shebang_fd >= 0) close(shebang_fd); }); + char shebang[256] {}; + ssize_t num_read = -1; + if ((shebang_fd >= 0) && ((num_read = read(shebang_fd, shebang, sizeof(shebang))) >= 2) && (StringView(shebang).starts_with("#!"))) { + StringView shebang_path_view(&shebang[2], num_read - 2); + Optional newline_pos = shebang_path_view.find_first_of("\n\r"); + shebang[newline_pos.has_value() ? (newline_pos.value() + 2) : num_read] = '\0'; + argv[0] = shebang; + int rc = execvp(argv[0], const_cast(argv.data())); + if (rc < 0) + fprintf(stderr, "%s: Invalid interpreter \"%s\": %s\n", argv[0], &shebang[2], strerror(errno)); + } else + fprintf(stderr, "%s: Command not found.\n", argv[0]); + } else { + if (S_ISDIR(st.st_mode)) { + fprintf(stderr, "Shell: %s: Is a directory\n", argv[0]); + _exit(126); + } + fprintf(stderr, "execvp(%s): %s\n", argv[0], strerror(saved_errno)); + } + _exit(126); + } + ASSERT_NOT_REACHED(); +} + void Shell::run_tail(const AST::Command& invoking_command, const AST::NodeWithAction& next_in_chain, int head_exit_code) { if (m_error != ShellError::None) { diff --git a/Shell/Shell.h b/Shell/Shell.h index 05b8797138..1932afe3af 100644 --- a/Shell/Shell.h +++ b/Shell/Shell.h @@ -45,6 +45,7 @@ __ENUMERATE_SHELL_BUILTIN(cd) \ __ENUMERATE_SHELL_BUILTIN(cdh) \ __ENUMERATE_SHELL_BUILTIN(pwd) \ + __ENUMERATE_SHELL_BUILTIN(exec) \ __ENUMERATE_SHELL_BUILTIN(exit) \ __ENUMERATE_SHELL_BUILTIN(export) \ __ENUMERATE_SHELL_BUILTIN(glob) \ @@ -253,6 +254,8 @@ private: void run_tail(RefPtr); void run_tail(const AST::Command&, const AST::NodeWithAction&, int head_exit_code); + [[noreturn]] void execute_process(Vector&& argv); + virtual void custom_event(Core::CustomEvent&) override; #define __ENUMERATE_SHELL_BUILTIN(builtin) \