summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2016-12-15 23:04:53 +0000
committerMaxime Coste <mawww@kakoune.org>2016-12-15 23:04:53 +0000
commit9a879262a272bd4c6458fcfa07a9289ee41d7220 (patch)
treef8f681890023aeb27f93f36302c8d57bc0b82e85 /src
parent414808ccf640797675e0d84eaa7e247bc64e5d68 (diff)
Use a POSIX guaranteed way of getting the shell path
Diffstat (limited to 'src')
-rw-r--r--src/shell_manager.cc44
-rw-r--r--src/shell_manager.hh2
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<StringView>(':'))
+ {
+ 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<typename Func>
-pid_t spawn_shell(StringView cmdline, ConstArrayView<String> params,
- ConstArrayView<String> kak_env, Func setup_child)
+pid_t spawn_shell(const char* shell, StringView cmdline,
+ ConstArrayView<String> params,
+ ConstArrayView<String> kak_env,
+ Func setup_child)
{
Vector<const char*> envptrs;
for (char** envp = environ; *envp; ++envp)
@@ -62,7 +93,6 @@ pid_t spawn_shell(StringView cmdline, ConstArrayView<String> params,
envptrs.push_back(env.c_str());
envptrs.push_back(nullptr);
- const char* shell = "/bin/sh";
auto cmdlinezstr = cmdline.zstr();
Vector<const char*> execparams = { shell, "-c", cmdlinezstr };
if (not params.empty())
@@ -129,7 +159,7 @@ std::pair<String, int> 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<EnvVarDesc, MemoryDomain::EnvVars> m_env_vars;
};