Skip to content

Commit 03b52c7

Browse files
authored
fix: non-interactive bash (#452)
* add shell wrapper * make module conditional
1 parent 0b90c1d commit 03b52c7

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

modules/systemd/native/default.nix

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{ config, pkgs, lib, ... }:
22
with lib; {
33

4+
imports = [
5+
./wrap-shell.nix
6+
];
7+
48
config =
59
let
610
cfg = config.wsl;
7-
nativeUtils = pkgs.callPackage ../../../utils { };
811

912
bashWrapper = pkgs.writeShellScriptBin "sh" ''
1013
export PATH="$PATH:${lib.makeBinPath [ pkgs.systemd pkgs.gnugrep ]}"
@@ -13,6 +16,8 @@ with lib; {
1316
in
1417
mkIf (cfg.enable && cfg.nativeSystemd) {
1518

19+
system.build.nativeUtils = pkgs.callPackage ../../../utils { };
20+
1621
wsl = {
1722
binShPkg = bashWrapper;
1823
wslConf = {
@@ -25,7 +30,7 @@ with lib; {
2530
shimSystemd = stringAfter [ ] ''
2631
echo "setting up /sbin/init shim..."
2732
mkdir -p /sbin
28-
ln -sf ${nativeUtils}/bin/systemd-shim /sbin/init
33+
ln -sf ${config.system.build.nativeUtils}/bin/systemd-shim /sbin/init
2934
'';
3035
setupLogin = lib.mkIf cfg.populateBin (stringAfter [ ] ''
3136
echo "setting up /bin/login..."
@@ -38,7 +43,7 @@ with lib; {
3843
# preserve $PATH from parent
3944
variables.PATH = [ "$PATH" ];
4045
extraInit = ''
41-
eval $(${nativeUtils}/bin/split-path --automount-root="${cfg.wslConf.automount.root}" ${lib.optionalString cfg.interop.includePath "--include-interop"})
46+
eval $(${config.system.build.nativeUtils}/bin/split-path --automount-root="${cfg.wslConf.automount.root}" ${lib.optionalString cfg.interop.includePath "--include-interop"})
4247
'';
4348
};
4449
};

modules/systemd/native/wrap-shell.nix

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{ config, lib, utils, pkgs, modulesPath, ... }:
2+
3+
with lib;
4+
5+
let
6+
cfg = config.wsl;
7+
8+
users-groups-module = import "${modulesPath}/config/users-groups.nix" {
9+
inherit lib utils pkgs;
10+
config = recursiveUpdate config {
11+
users.users = mapAttrs
12+
(n: v: v // {
13+
shell =
14+
let
15+
shellPath = utils.toShellPath v.shell;
16+
wrapper = pkgs.stdenvNoCC.mkDerivation {
17+
name = "wrapped-${last (splitString "/" (shellPath))}";
18+
buildCommand = ''
19+
mkdir -p $out/bin
20+
cp ${config.system.build.nativeUtils}/bin/shell-wrapper $out/wrapper
21+
ln -s ${shellPath} $out/shell
22+
'';
23+
};
24+
in
25+
wrapper.outPath + "/wrapper";
26+
})
27+
config.users.users;
28+
};
29+
};
30+
in
31+
{
32+
config = mkIf (cfg.enable && cfg.nativeSystemd) {
33+
system.activationScripts.users = users-groups-module.config.system.activationScripts.users;
34+
};
35+
}

utils/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ path = "src/shim.rs"
2424
[[bin]]
2525
name = "split-path"
2626
path = "src/split_path.rs"
27+
28+
[[bin]]
29+
name = "shell-wrapper"
30+
path = "src/shell_wrapper.rs"

utils/src/shell_wrapper.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use anyhow::{anyhow, Context};
2+
use std::os::unix::process::CommandExt;
3+
use std::process::Command;
4+
use std::{env, fs::read_link};
5+
6+
fn real_main() -> anyhow::Result<()> {
7+
let exe = read_link("/proc/self/exe").context("when locating the wrapper binary")?;
8+
let exe_dir = exe.parent().ok_or(anyhow!(
9+
"could not locate the wrapper binary's parent directory"
10+
))?;
11+
12+
// Some binaries behave differently depending on the file name they are called with (arg[0]).
13+
// Therefore we dereference our symlink to get whatever it was originally.
14+
let shell = read_link(exe_dir.join("shell")).context("when locating the wrapped shell")?;
15+
16+
// Skip if environment was already set
17+
if env::var_os("__NIXOS_SET_ENVIRONMENT_DONE") != Some("1".into()) {
18+
// Load the environment from /etc/set-environment
19+
let output = Command::new("/bin/sh")
20+
.args(&["-c", ". /etc/set-environment && /usr/bin/env -0"])
21+
.output()
22+
.context("when reading /etc/set-environment")?;
23+
24+
// Parse the output
25+
let output_string =
26+
String::from_utf8(output.stdout).context("when decoding the output of env")?;
27+
let env = output_string
28+
.split('\0')
29+
.filter(|entry| !entry.is_empty())
30+
.map(|entry| {
31+
entry
32+
.split_once("=")
33+
.ok_or(anyhow!("invalid env entry: {}", entry))
34+
})
35+
.collect::<Result<Vec<_>, _>>()
36+
.context("when parsing the output of env")?;
37+
38+
// Apply the environment variables
39+
for &(key, val) in &env {
40+
env::set_var(key, val);
41+
}
42+
}
43+
44+
Err(anyhow!(Command::new(&shell)
45+
.arg0(shell)
46+
.args(env::args_os().skip(1))
47+
.exec())
48+
.context("when trying to exec the wrapped shell"))
49+
}
50+
51+
fn main() {
52+
let result = real_main();
53+
54+
env::set_var("RUST_BACKTRACE", "1");
55+
eprintln!("[shell-wrapper] Error: {:?}", result.unwrap_err());
56+
}

0 commit comments

Comments
 (0)