diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-05-02 12:47:30 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-02 19:46:33 +0200 |
commit | b7fb12338c13f0a521bb7ac5a6faa0812bd04430 (patch) | |
tree | c5ad5387c08c35f3ab6b3f93308f8ab6c843d918 /Userland/Shell | |
parent | bda69a5f59de1d825be0e593c5dee86f40263423 (diff) | |
download | serenity-b7fb12338c13f0a521bb7ac5a6faa0812bd04430.zip |
Shell: Only match entries from PATH when a program name is given
This commit makes the shell:
- highlight executables in the current directory as invalid, unless an
explicit `./' is given (so, `./foo` isn't red, but `foo` is)
- not suggest executables in the current directory unless explicitly
requested (by prepending `./`)
- not attempt to run an executable in the current directory that has
been invoked as a program name and failed execvp().
Note that `./foo` is still executed because it's not invoked as
a name, but rather as a path.
Fixes the other half of #6774.
Diffstat (limited to 'Userland/Shell')
-rw-r--r-- | Userland/Shell/Shell.cpp | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/Userland/Shell/Shell.cpp b/Userland/Shell/Shell.cpp index f2bd7adbd6..6fb94ba7a4 100644 --- a/Userland/Shell/Shell.cpp +++ b/Userland/Shell/Shell.cpp @@ -511,12 +511,14 @@ String Shell::resolve_alias(const String& name) const bool Shell::is_runnable(const StringView& name) { - if (access(name.to_string().characters(), X_OK) == 0) + auto parts = name.split_view('/'); + auto path = name.to_string(); + if (parts.size() > 1 && access(path.characters(), X_OK) == 0) return true; return binary_search( cached_path.span(), - name.to_string(), + path, nullptr, [](auto& name, auto& program) { return strcmp(name.characters(), program.characters()); }); } @@ -856,6 +858,13 @@ void Shell::execute_process(Vector<const char*>&& argv) { int rc = execvp(argv[0], const_cast<char* const*>(argv.data())); if (rc < 0) { + auto parts = StringView { argv[0] }.split_view('/'); + if (parts.size() == 1) { + // If this is a path in the current directory and it caused execvp() to fail, + // simply don't attempt to execute it, see #6774. + warnln("{}: Command not found.", argv[0]); + _exit(127); + } int saved_errno = errno; struct stat st; if (stat(argv[0], &st)) { @@ -1323,6 +1332,8 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, auto init_slash_part = token.substring_view(0, last_slash + 1); auto last_slash_part = token.substring_view(last_slash + 1, token.length() - last_slash - 1); + bool allow_direct_children = true; + // Depending on the base, we will have to prepend cwd. if (base.is_empty()) { // '' /foo -> absolute @@ -1331,6 +1342,8 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, path_builder.append(cwd); path_builder.append('/'); path_builder.append(init_slash_part); + if (executable_only == ExecutableOnly::Yes && init_slash_part.is_empty()) + allow_direct_children = false; } else { // /foo * -> absolute // foo * -> relative @@ -1368,6 +1381,8 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, if (S_ISDIR(program_status.st_mode)) { suggestions.append({ escape_token(file), "/" }); } else { + if (!allow_direct_children && !file.contains("/")) + continue; suggestions.append({ escape_token(file), " " }); } suggestions.last().input_offset = token_length; |