From 17e1e1f1147e28702790b2b7d65d5753364a9d2d Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Wed, 9 Dec 2020 01:49:58 +0330 Subject: [PATCH] Shell: Actually make shebangs work Also check for executable permissions before actually trying to run, and print a helpful message if not executable. Fixes #4358 --- Shell/Shell.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 2f23c02ff6b..6d4123b21f5 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -787,7 +787,17 @@ RefPtr Shell::run_command(const AST::Command& command) int rc = execvp(argv[0], const_cast(argv.data())); if (rc < 0) { - if (errno == ENOENT) { + 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] {}; @@ -796,13 +806,14 @@ RefPtr Shell::run_command(const AST::Command& command) 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'; - fprintf(stderr, "%s: Invalid interpreter \"%s\": %s\n", argv[0], &shebang[2], strerror(ENOENT)); + 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 { - int saved_errno = errno; - struct stat st; - if (stat(argv[0], &st) == 0 && S_ISDIR(st.st_mode)) { + if (S_ISDIR(st.st_mode)) { fprintf(stderr, "Shell: %s: Is a directory\n", argv[0]); _exit(126); }