Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/libfetchers/git-lfs-fetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ LfsApiInfo getLfsApi(ParsedURL url)
args.push_back(string_to_os_string(url.renderPath(/*encode=*/false)));
args.push_back(OS_STR("download"));

auto [status, output] = runProgram({{.program = "ssh", .args = args}});
auto [status, output] = runProgram({{.program = sshProgram(), .args = args}});

if (output.empty())
throw Error(
"git-lfs-authenticate: no output (cmd: 'ssh %s')",
"git-lfs-authenticate: no output (cmd: '%s %s')",
sshProgram().string(),
concatMapStringsSep(
" ", args, [](const OsString & s) { return escapeShellArgAlways(os_string_to_string(s)); }));

Expand Down
4 changes: 3 additions & 1 deletion src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -391,14 +391,16 @@ RunPager::RunPager()
Pipe toPager;
toPager.create();

const auto & sh = shProgram();

pid = startProcess([&]() {
if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin");
if (!getenv("LESS"))
setEnv("LESS", "FRSXMK");
restoreProcessContext();
if (pager)
execl("/bin/sh", "sh", "-c", pager, nullptr);
execl(sh.c_str(), "sh", "-c", pager, nullptr);
execlp("pager", "pager", nullptr);
execlp("less", "less", nullptr);
execlp("more", "more", nullptr);
Expand Down
7 changes: 7 additions & 0 deletions src/libstore/include/nix/store/ssh.hh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@

namespace nix {

/**
* The ssh program used for all ssh invocations (build-time configurable
* via the `ssh-program` option; either a name resolved via PATH or an
* absolute path).
*/
const std::filesystem::path & sshProgram();

OsStrings getNixSshOpts();

class SSHMaster
Expand Down
2 changes: 1 addition & 1 deletion src/libstore/meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ option(
'ssh-program',
type : 'string',
value : 'ssh',
description : 'the ssh program used for remote stores, remote builders and store copies (a name resolved via PATH, or an absolute path)',
description : 'the ssh program used for remote stores, remote builders, store copies and Git LFS authentication (a name resolved via PATH, or an absolute path)',
)

option(
Expand Down
18 changes: 12 additions & 6 deletions src/libstore/ssh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ static void checkValidAuthority(const ParsedURL::Authority & authority)
}
}

const std::filesystem::path & sshProgram()
{
static const std::filesystem::path program = SSH_PROGRAM;
return program;
}

OsStrings getNixSshOpts()
{
std::string sshOpts = getEnv("NIX_SSHOPTS").value_or("");
Expand Down Expand Up @@ -130,24 +136,24 @@ bool SSHMaster::isMasterRunning()

auto res = runProgram(
RunOptions{
.spawnOptions = {.program = SSH_PROGRAM, .args = std::move(args)},
.spawnOptions = {.program = sshProgram(), .args = std::move(args)},
.mergeStderrToStdout = true,
});
return res.first == 0;
}

static OsStringMap createSSHEnv()
{
// Copy the environment and set SHELL=/bin/sh
// Copy the environment and set SHELL to the configured sh
OsStringMap env = getEnvOs();

// SSH will invoke the "user" shell for -oLocalCommand, but that means
// $SHELL. To keep things simple and avoid potential issues with other
// shells, we set it to /bin/sh.
// shells, we set it to the configured POSIX shell.
// Technically, we don't need that, and we could reinvoke ourselves to print
// "started". Self-reinvocation is tricky with library consumers, but mostly
// solved; refer to the development history of nixExePath in libstore/globals.cc.
env.insert_or_assign(OS_STR("SHELL"), OS_STR("/bin/sh"));
env.insert_or_assign(OS_STR("SHELL"), shProgram().native());

return env;
}
Expand All @@ -171,7 +177,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(OsStrings && comm
std::filesystem::path program;

if (!fakeSSH) {
program = SSH_PROGRAM;
program = sshProgram();
args = {string_to_os_string(hostnameAndUser), OS_STR("-x")};
addCommonSSHOpts(args);
if (!socketPath.empty())
Expand Down Expand Up @@ -262,7 +268,7 @@ std::filesystem::path SSHMaster::startMaster()

state->sshMaster = spawnProgram(
{
.program = SSH_PROGRAM,
.program = sshProgram(),
.lookupPath = true,
.args = std::move(args),
.environment = createSSHEnv(),
Expand Down
6 changes: 6 additions & 0 deletions src/libutil/include/nix/util/processes.hh
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ struct ProcessOptions
pid_t startProcess(fun<void()> processMain, const ProcessOptions & options = ProcessOptions());
#endif

/**
* The POSIX shell used to run command strings with `-c` (build-time
* configurable via the `sh-program` option; always an absolute path).
*/
const std::filesystem::path & shProgram();

/**
* Run a program and return its stdout in a string (i.e., like the
* shell backtick operator).
Expand Down
10 changes: 10 additions & 0 deletions src/libutil/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ deps_public += nlohmann_json

cxx = meson.get_compiler('cpp')

fs = import('fs')

sh_program = get_option('sh-program')
if host_machine.system() != 'windows' and not fs.is_absolute(sh_program)
# sh_program is exec'd directly and handed to ssh as $SHELL,
# neither of which does a PATH lookup. It's only meaningful on Linux.
error('sh-program must be an absolute path, got \'' + sh_program + '\'')
endif
configdata_priv.set_quoted('SH_PROGRAM', sh_program)

config_priv_h = configure_file(
configuration : configdata_priv,
output : 'util-config-private.hh',
Expand Down
7 changes: 7 additions & 0 deletions src/libutil/meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ option(
type : 'feature',
description : 'determine microarchitecture levels with libcpuid (only relevant on x86_64)',
)

option(
'sh-program',
type : 'string',
value : '/bin/sh',
description : 'the POSIX shell used to run command strings such as $PAGER and ssh LocalCommand (must be an absolute path)',
)
Comment thread
xokdvium marked this conversation as resolved.
8 changes: 8 additions & 0 deletions src/libutil/processes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@
#include "nix/util/serialise.hh"
#include "nix/util/signals.hh"

#include "util-config-private.hh"

namespace nix {

void ExecError::anchor() {}

const std::filesystem::path & shProgram()
{
static const std::filesystem::path program = SH_PROGRAM;
return program;
}

Pid & Pid::operator=(Pid && other) noexcept
{
swap(*this, other);
Expand Down
4 changes: 3 additions & 1 deletion src/nix/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <boost/unordered/unordered_flat_set.hpp>

#include "nix/cmd/command.hh"

#include "cli-config-private.hh"
#include "nix/expr/eval.hh"
#include "run.hh"
#include "nix/util/strings.hh"
Expand Down Expand Up @@ -37,7 +39,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment

using InstallablesCommand::run;

std::vector<std::string> command = {getEnv("SHELL").value_or("bash")};
std::vector<std::string> command = {getEnv("SHELL").value_or(FALLBACK_BASH)};

CmdShell()
{
Expand Down
2 changes: 1 addition & 1 deletion src/nix/meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ option(
'bash-program',
type : 'string',
value : 'bash',
description : 'the bash used as the fallback interactive shell for nix develop / nix-shell when bashInteractive from nixpkgs is unavailable (a name resolved via PATH, or an absolute path)',
description : 'the bash used as the fallback interactive shell for nix develop / nix-shell when bashInteractive from nixpkgs is unavailable, and for nix shell when $SHELL is unset (a name resolved via PATH, or an absolute path)',
)
Loading