From 9a879262a272bd4c6458fcfa07a9289ee41d7220 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 15 Dec 2016 23:04:53 +0000 Subject: [PATCH] Use a POSIX guaranteed way of getting the shell path --- src/shell_manager.cc | 44 +++++++++++++++++++++++++++++++++++++------- src/shell_manager.hh | 2 ++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 2428709a..f7857dab 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -22,9 +22,38 @@ namespace Kakoune ShellManager::ShellManager() { - const char* path = getenv("PATH"); - auto new_path = format("{}:{}", path, split_path(get_kak_binary_path()).first); - setenv("PATH", new_path.c_str(), 1); + // Get a guaranteed to be POSIX shell binary + { + auto size = confstr(_CS_PATH, 0, 0); + String path; path.resize(size, 0); + confstr(_CS_PATH, path.data(), size); + for (auto dir : StringView{path} | split(':')) + { + String candidate = format("{}/sh", dir); + struct stat st; + if (stat(candidate.c_str(), &st)) + continue; + + bool executable = (st.st_mode & S_IXUSR) + | (st.st_mode & S_IXGRP) + | (st.st_mode & S_IXOTH); + if (S_ISREG(st.st_mode) and executable) + { + m_shell = std::move(candidate); + break; + } + } + if (m_shell.empty()) + throw runtime_error{format("unable to find a posix shell in {}", path)}; + } + + // Add Kakoune binary location to the path to guarantee that %sh{ ... } + // have access to the kak command regardless of if the user installed it + { + const char* path = getenv("PATH"); + auto new_path = format("{}:{}", path, split_path(get_kak_binary_path()).first); + setenv("PATH", new_path.c_str(), 1); + } } namespace @@ -52,8 +81,10 @@ private: }; template -pid_t spawn_shell(StringView cmdline, ConstArrayView params, - ConstArrayView kak_env, Func setup_child) +pid_t spawn_shell(const char* shell, StringView cmdline, + ConstArrayView params, + ConstArrayView kak_env, + Func setup_child) { Vector envptrs; for (char** envp = environ; *envp; ++envp) @@ -62,7 +93,6 @@ pid_t spawn_shell(StringView cmdline, ConstArrayView params, envptrs.push_back(env.c_str()); envptrs.push_back(nullptr); - const char* shell = "/bin/sh"; auto cmdlinezstr = cmdline.zstr(); Vector execparams = { shell, "-c", cmdlinezstr }; if (not params.empty()) @@ -129,7 +159,7 @@ std::pair ShellManager::eval( auto spawn_time = profile ? Clock::now() : Clock::time_point{}; Pipe child_stdin{not input.empty()}, child_stdout, child_stderr; - pid_t pid = spawn_shell(cmdline, shell_context.params, kak_env, + pid_t pid = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env, [&child_stdin, &child_stdout, &child_stderr] { auto move = [](int oldfd, int newfd) { dup2(oldfd, newfd); close(oldfd); }; diff --git a/src/shell_manager.hh b/src/shell_manager.hh index 2f2608ef..1336ca9b 100644 --- a/src/shell_manager.hh +++ b/src/shell_manager.hh @@ -43,6 +43,8 @@ public: CandidateList complete_env_var(StringView prefix, ByteCount cursor_pos) const; private: + String m_shell; + struct EnvVarDesc { String str; bool prefix; EnvVarRetriever func; }; Vector m_env_vars; };