Skip to content

Commit

Permalink
feat: rewrite syschdemd
Browse files Browse the repository at this point in the history
Mostly just a big pile of cleanups.

Important changes:
- refactor and clean up the code, fix all the shellcheck complaints
- stop trying to guess paths in scripts and wrap them correctly instead
- use nsfs instead of trying to figure out the right PID to copy namespaces from
- clean up $WSLPATH to remove extra impure entries
- don't try to restart systemd if it died
- make sure the store is read-only before we do anything, so systemd can't mess with it
- reformat shell scripts with shfmt
  • Loading branch information
K900 committed Aug 24, 2022
1 parent 0b29fc7 commit 819b815
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 116 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- uses: actions/download-artifact@v2
with:
name: installer

- name: Generate checksums
run: |
for x in *.tar.gz; do
Expand Down
16 changes: 8 additions & 8 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@
pkgs = import nixpkgs { inherit system; };
in
{
checks.check-format = pkgs.runCommand "check-format"
{
buildInputs = with pkgs; [ nixpkgs-fmt ];
} ''
nixpkgs-fmt --check ${./.}
mkdir $out # success
'';
checks = {
check-format = pkgs.runCommand "check-format" { nativeBuildInputs = with pkgs; [ nixpkgs-fmt shfmt ]; } ''
nixpkgs-fmt --check ${./.}
shfmt -i 2 -d ${./scripts}/*.sh
mkdir $out # success
'';
};

devShell = pkgs.mkShell {
nativeBuildInputs = with pkgs; [ nixpkgs-fmt ];
nativeBuildInputs = with pkgs; [ nixpkgs-fmt shfmt ];
};
}
);
Expand Down
2 changes: 1 addition & 1 deletion modules/wsl-distro.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ with builtins; with lib;
config =
let
cfg = config.wsl;
syschdemd = import ../syschdemd.nix { inherit lib pkgs config; inherit (cfg) automountPath defaultUser; defaultUserHome = config.users.users.${cfg.defaultUser}.home; };
syschdemd = pkgs.callPackage ../scripts/syschdemd.nix { inherit (cfg) automountPath defaultUser; };
in
mkIf cfg.enable {

Expand Down
51 changes: 51 additions & 0 deletions scripts/syschdemd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{ runCommand
, makeWrapper
, lib
, coreutils
, daemonize
, glibc
, gnugrep
, systemd
, util-linux
, defaultUser
, automountPath
,
}:
let
mkWrappedScript =
{ name
, src
, path
, ...
} @ args:
runCommand name ({ nativeBuildInputs = [ makeWrapper ]; } // args) ''
install -Dm755 ${src} $out/bin/${name}
patchShebangs $out/bin/${name}
substituteAllInPlace $out/bin/${name}
wrapProgram $out/bin/${name} --prefix PATH ':' ${lib.escapeShellArg path}
'';

wrapper = mkWrappedScript {
name = "nixos-wsl-systemd-wrapper";
src = ./wrapper.sh;
path = lib.makeSearchPath "" [
"/run/wrappers/bin" # mount
"${systemd}/lib/systemd" # systemd
];
};
in
mkWrappedScript {
name = "syschdemd";
src = ./syschdemd.sh;
path = lib.makeBinPath [
"/run/wrappers" # mount
coreutils
daemonize
glibc # getent
gnugrep
systemd # machinectl
util-linux # nsenter
wrapper
];
inherit defaultUser automountPath;
}
136 changes: 136 additions & 0 deletions scripts/syschdemd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
set -euo pipefail

[ "${NIXOS_WSL_DEBUG:-}" == "1" ] && set -x

rundir="/run/nixos-wsl"
pidfile="$rundir/unshare.pid"

ensure_root() {
if [ $EUID -ne 0 ]; then
echo "[ERROR] Requires root! :( Make sure the WSL default user is set to root" >&2
exit 1
fi
}

activate() {
mount --bind -o ro /nix/store /nix/store
mount --make-rshared /

LANG="C.UTF-8" /nix/var/nix/profiles/system/activate
}

create_rundir() {
if [ ! -d $rundir ]; then
mkdir -p $rundir/ns
touch $rundir/ns/{pid,mount}
fi
}

is_unshare_alive() {
[ -e $pidfile ] && [ -d "/proc/$(<$pidfile)" ]
}

run_in_namespace() {
nsenter \
--pid=$rundir/ns/pid \
--mount=$rundir/ns/mount \
-- "$@"
}

start_systemd() {
daemonize \
-o $rundir/stdout \
-e $rundir/stderr \
-l $rundir/systemd.lock \
-p $pidfile \
-E LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive \
"$(command -v unshare)" \
--fork \
--pid=$rundir/ns/pid \
--mount=$rundir/ns/mount \
--mount-proc=/proc \
nixos-wsl-systemd-wrapper

# Wait for systemd to start
while ! (run_in_namespace systemctl is-system-running -q --wait) &>/dev/null; do
sleep 1

if ! is_unshare_alive; then
echo "[ERROR] systemd startup failed!"

echo "[ERROR] stderr:"
cat $rundir/stderr

echo "[ERROR] stdout:"
cat $rundir/stdout

exit 1
fi
done
}

get_shell() {
getent passwd "$1" | cut -d: -f7
}

get_home() {
getent passwd "$1" | cut -d: -f6
}

is_in_container() {
[ "${INSIDE_NAMESPACE:-}" == "true" ]
}

clean_wslpath() {
echo "$PATH" | tr ':' '\n' | grep -E "^@automountPath@" | tr '\n' ':'
}

main() {
ensure_root

if [ ! -e "/run/current-system" ]; then
activate
fi

if [ ! -e "$rundir" ]; then
create_rundir
fi

if ! is_in_container && ! is_unshare_alive; then
start_systemd
fi

if [ $# -gt 0 ]; then
# wsl seems to prefix with "-c"
shift
command="$*"
else
command=$(get_shell @defaultUser@)
fi

# If we're executed from inside the container, e.g. sudo
if is_in_container; then
exec $command
fi

# If we are currently in /root, this is probably because the directory that WSL was started is inaccessible
# cd to the user's home to prevent a warning about permission being denied on /root
if [ "$PWD" == "/root" ]; then
cd "$(get_home @defaultUser@)"
fi

# Pass external environment but filter variables specific to root user.
exportCmd="$(export -p | grep -vE ' (HOME|LOGNAME|SHELL|USER)=')"

run_in_namespace \
machinectl \
--quiet \
--uid=@defaultUser@ \
--setenv=INSIDE_NAMESPACE=true \
--setenv=WSLPATH="$(clean_wslpath)" \
shell .host \
/bin/sh -c "cd \"$PWD\"; $exportCmd; source /etc/set-environment; exec $command"
}

main "$@"
6 changes: 6 additions & 0 deletions scripts/wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euxo pipefail

mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc

exec systemd
28 changes: 0 additions & 28 deletions syschdemd.nix

This file was deleted.

78 changes: 0 additions & 78 deletions syschdemd.sh

This file was deleted.

0 comments on commit 819b815

Please sign in to comment.