From d3656e93112fb3602d6d5d8c242c415b297fc0f4 Mon Sep 17 00:00:00 2001 From: K900 Date: Fri, 23 Sep 2022 22:06:07 +0300 Subject: [PATCH] feat: native systemd support wip --- .gitignore | 1 + modules/wsl-distro.nix | 190 +++++++++++++++++++++----------------- scripts/yoink/Cargo.lock | 145 +++++++++++++++++++++++++++++ scripts/yoink/Cargo.toml | 10 ++ scripts/yoink/src/main.rs | 38 ++++++++ scripts/yoink/yoink.nix | 8 ++ 6 files changed, 307 insertions(+), 85 deletions(-) create mode 100644 scripts/yoink/Cargo.lock create mode 100644 scripts/yoink/Cargo.toml create mode 100644 scripts/yoink/src/main.rs create mode 100644 scripts/yoink/yoink.nix diff --git a/.gitignore b/.gitignore index 750baebf..d0e3eb93 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ result result-* +scripts/yoink/target diff --git a/modules/wsl-distro.nix b/modules/wsl-distro.nix index b3437d71..97422d5c 100644 --- a/modules/wsl-distro.nix +++ b/modules/wsl-distro.nix @@ -8,6 +8,11 @@ with builtins; with lib; in { enable = mkEnableOption "support for running NixOS as a WSL distribution"; + nativeSystemd = mkOption { + type = bool; + default = false; + description = "Use native WSL systemd support"; + }; automountPath = mkOption { type = str; default = "/mnt"; @@ -34,106 +39,121 @@ with builtins; with lib; let cfg = config.wsl; syschdemd = pkgs.callPackage ../scripts/syschdemd.nix { inherit (cfg) automountPath defaultUser; }; + yoink = pkgs.callPackage ../scripts/yoink/yoink.nix {}; in - mkIf cfg.enable { - - wsl.wslConf = { - automount = { - enabled = true; - mountFsTab = true; - root = "${cfg.automountPath}/"; - options = cfg.automountOptions; - }; - network = { - generateResolvConf = mkDefault true; - generateHosts = mkDefault true; + mkMerge [ + (mkIf cfg.enable { + wsl.wslConf = { + automount = { + enabled = true; + mountFsTab = true; + root = "${cfg.automountPath}/"; + options = cfg.automountOptions; + }; + network = { + generateResolvConf = mkDefault true; + generateHosts = mkDefault true; + }; }; - }; - # WSL is closer to a container than anything else - boot.isContainer = true; + # WSL is closer to a container than anything else + boot.isContainer = true; - environment.noXlibs = lib.mkForce false; # override xlibs not being installed (due to isContainer) to enable the use of GUI apps - hardware.opengl.enable = true; # Enable GPU acceleration + environment.noXlibs = lib.mkForce false; # override xlibs not being installed (due to isContainer) to enable the use of GUI apps + hardware.opengl.enable = true; # Enable GPU acceleration - environment = { + environment = { - etc = { - "wsl.conf".text = generators.toINI { } cfg.wslConf; + etc = { + "wsl.conf".text = generators.toINI { } cfg.wslConf; - # DNS settings are managed by WSL - hosts.enable = !config.wsl.wslConf.network.generateHosts; - "resolv.conf".enable = !config.wsl.wslConf.network.generateResolvConf; - }; + # DNS settings are managed by WSL + hosts.enable = !config.wsl.wslConf.network.generateHosts; + "resolv.conf".enable = !config.wsl.wslConf.network.generateResolvConf; + }; - systemPackages = [ - (pkgs.runCommand "wslpath" { } '' - mkdir -p $out/bin - ln -s /init $out/bin/wslpath - '') - ]; - }; + systemPackages = [ + (pkgs.runCommand "wslpath" { } '' + mkdir -p $out/bin + ln -s /init $out/bin/wslpath + '') + ]; + }; - networking.dhcpcd.enable = false; + networking.dhcpcd.enable = false; - users.users.${cfg.defaultUser} = { - isNormalUser = true; - uid = 1000; - extraGroups = [ "wheel" ]; # Allow the default user to use sudo - }; + users.users.${cfg.defaultUser} = { + isNormalUser = true; + uid = 1000; + extraGroups = [ "wheel" ]; # Allow the default user to use sudo + }; - users.users.root = { - shell = "${syschdemd}/bin/syschdemd"; # Otherwise WSL fails to login as root with "initgroups failed 5" - extraGroups = [ "root" ]; - }; + users.users.root.extraGroups = [ "root" ]; + + security.sudo.wheelNeedsPassword = mkDefault false; # The default user will not have a password by default + + system.activationScripts = { + copy-launchers = mkIf cfg.startMenuLaunchers ( + stringAfter [ ] '' + for x in applications icons; do + echo "Copying /usr/share/$x" + mkdir -p /usr/share/$x + ${pkgs.rsync}/bin/rsync -ar --delete $systemConfig/sw/share/$x/. /usr/share/$x + done + '' + ); + populateBin = stringAfter [ ] '' + echo "setting up /bin..." + ln -sf /init /bin/wslpath + ln -sf ${pkgs.bashInteractive}/bin/bash /bin/sh + ln -sf ${pkgs.util-linux}/bin/mount /bin/mount + ''; + }; - security.sudo = { - extraConfig = '' - Defaults env_keep+=INSIDE_NAMESPACE - ''; - wheelNeedsPassword = mkDefault false; # The default user will not have a password by default - }; + systemd = { + # Disable systemd units that don't make sense on WSL + services = { + "serial-getty@ttyS0".enable = false; + "serial-getty@hvc0".enable = false; + "getty@tty1".enable = false; + "autovt@".enable = false; + firewall.enable = false; + systemd-resolved.enable = false; + systemd-udevd.enable = false; + }; + + tmpfiles.rules = [ + # Don't remove the X11 socket + "d /tmp/.X11-unix 1777 root root" + ]; + + # Don't allow emergency mode, because we don't have a console. + enableEmergencyMode = false; + }; - system.activationScripts = { - copy-launchers = mkIf cfg.startMenuLaunchers ( - stringAfter [ ] '' - for x in applications icons; do - echo "Copying /usr/share/$x" - mkdir -p /usr/share/$x - ${pkgs.rsync}/bin/rsync -ar --delete $systemConfig/sw/share/$x/. /usr/share/$x - done - '' - ); - populateBin = stringAfter [ ] '' - echo "setting up /bin..." - ln -sf /init /bin/wslpath - ln -sf ${pkgs.bashInteractive}/bin/bash /bin/sh - ln -sf ${pkgs.util-linux}/bin/mount /bin/mount + warnings = (optional (config.systemd.services.systemd-resolved.enable && config.wsl.wslConf.network.generateResolvConf) "systemd-resolved is enabled, but resolv.conf is managed by WSL"); + }) + (mkIf (!cfg.nativeSystemd) { + users.users.root.shell = "${syschdemd}/bin/syschdemd"; + security.sudo.extraConfig = '' + Defaults env_keep+=INSIDE_NAMESPACE ''; - }; - - systemd = { - # Disable systemd units that don't make sense on WSL - services = { - "serial-getty@ttyS0".enable = false; - "serial-getty@hvc0".enable = false; - "getty@tty1".enable = false; - "autovt@".enable = false; - firewall.enable = false; - systemd-resolved.enable = false; - systemd-udevd.enable = false; + wsl.wslConf.users.default = "root"; + }) + (mkIf cfg.nativeSystemd { + wsl.wslConf = { + user.default = cfg.defaultUser; + boot.systemd = true; }; - tmpfiles.rules = [ - # Don't remove the X11 socket - "d /tmp/.X11-unix 1777 root root" - ]; - - # Don't allow emergency mode, because we don't have a console. - enableEmergencyMode = false; - }; - - warnings = (optional (config.systemd.services.systemd-resolved.enable && config.wsl.wslConf.network.generateResolvConf) "systemd-resolved is enabled, but resolv.conf is managed by WSL"); - }; + system.activationScripts = { + shimSystemd = stringAfter [ ] '' + echo "setting up /lib/systemd/systemd shim..." + mkdir -p /lib/systemd + ln -sf ${yoink}/bin/yoink /lib/systemd/systemd + ''; + }; + }) + ]; } diff --git a/scripts/yoink/Cargo.lock b/scripts/yoink/Cargo.lock new file mode 100644 index 00000000..6b668da5 --- /dev/null +++ b/scripts/yoink/Cargo.lock @@ -0,0 +1,145 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +dependencies = [ + "backtrace", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" + +[[package]] +name = "libc" +version = "0.2.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "nix" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "yoink" +version = "0.1.0" +dependencies = [ + "anyhow", + "nix", +] diff --git a/scripts/yoink/Cargo.toml b/scripts/yoink/Cargo.toml new file mode 100644 index 00000000..0db4c89f --- /dev/null +++ b/scripts/yoink/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "yoink" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { version = "1.0.65", features = ["backtrace"] } +nix = { version = "0.25.0", features = ["process"] } diff --git a/scripts/yoink/src/main.rs b/scripts/yoink/src/main.rs new file mode 100644 index 00000000..bc0d7e54 --- /dev/null +++ b/scripts/yoink/src/main.rs @@ -0,0 +1,38 @@ +use nix::mount::{mount, MsFlags}; +use nix::unistd::execv; +use std::env; +use std::ffi::CString; +use std::fs::write; +use std::os::unix::ffi::OsStrExt; +use std::process::{id, Command}; + +fn real_main() -> anyhow::Result<()> { + env::set_var("RUST_BACKTRACE", "full"); + + let args: Result, _> = env::args_os().map(|x| CString::new(x.as_bytes())).collect(); + + mount( + Some("/nix/store"), + "/nix/store", + None::<&str>, + MsFlags::MS_RDONLY | MsFlags::MS_BIND, + None::<&str>, + )?; + + Command::new("/nix/var/nix/profiles/system/activate") + .env("LANG", "C.UTF-8") + .spawn()?; + + execv( + CString::new("/nix/var/nix/profiles/system/systemd/lib/systemd/systemd")?.as_c_str(), + &args?, + )?; + + Ok(()) +} + +fn main() { + let result = real_main(); + // we will only get here if something fails + write(format!("/yoink.{}.err", id()), format!("{:?}", result)).unwrap(); +} diff --git a/scripts/yoink/yoink.nix b/scripts/yoink/yoink.nix new file mode 100644 index 00000000..67c94b15 --- /dev/null +++ b/scripts/yoink/yoink.nix @@ -0,0 +1,8 @@ +{ rustPlatform }: +rustPlatform.buildRustPackage rec { + name = "yoink"; + version = "1.0.0"; + + src = ./.; + cargoLock.lockFile = ./Cargo.lock; +} \ No newline at end of file