summaryrefslogtreecommitdiff
path: root/Userland/Shell
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-05-02 12:47:30 +0430
committerAndreas Kling <kling@serenityos.org>2021-05-02 19:46:33 +0200
commitb7fb12338c13f0a521bb7ac5a6faa0812bd04430 (patch)
treec5ad5387c08c35f3ab6b3f93308f8ab6c843d918 /Userland/Shell
parentbda69a5f59de1d825be0e593c5dee86f40263423 (diff)
downloadserenity-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.cpp19
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;