From cc4888fff19ddf81eac53f3760e6798468d55956 Mon Sep 17 00:00:00 2001 From: nzbr Date: Fri, 15 Jul 2022 20:42:08 +0200 Subject: interop: move to its own module, disable by default (#119) --- modules/interop.nix | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ modules/wsl-distro.nix | 70 +-------------------------------------- 2 files changed, 89 insertions(+), 69 deletions(-) create mode 100644 modules/interop.nix (limited to 'modules') diff --git a/modules/interop.nix b/modules/interop.nix new file mode 100644 index 0000000..b7babfb --- /dev/null +++ b/modules/interop.nix @@ -0,0 +1,88 @@ +{ lib, pkgs, config, ... }: + +with builtins; with lib; +{ + imports = [ + (mkRenamedOptionModule [ "wsl" "compatibility" "interopPreserveArgvZero" ] [ "wsl" "interop" "preserveArgvZero" ]) + ]; + + options.wsl.interop = with types; { + register = mkOption { + type = bool; + default = false; # Use the existing registration by default + description = "Explicitly register the binfmt_misc handler for Windows executables"; + }; + + includePath = mkOption { + type = bool; + default = true; + description = "Include Windows PATH in WSL PATH"; + }; + + preserveArgvZero = mkOption { + type = nullOr bool; + default = null; + description = '' + Register binfmt interpreter for Windows executables with 'preserves argv[0]' flag. + + Default (null): autodetect, at some performance cost. + To avoid the performance cost, set this to true for WSL Preview 0.58 and up, + or to false for any older versions, including pre-Microsoft Store and Windows 10. + ''; + }; + }; + + config = + let + cfg = config.wsl.interop; + in + mkIf config.wsl.enable { + + boot.binfmt.registrations = mkIf cfg.register { + WSLInterop = + let + compat = cfg.preserveArgvZero; + + # WSL Preview 0.58 and up registers the /init binfmt interp for Windows executable + # with the "preserve argv[0]" flag, so if you run `./foo.exe`, the interp gets invoked + # as `/init foo.exe ./foo.exe`. + # argv[0] --^ ^-- actual path + # + # Older versions expect to be called without the argv[0] bit, simply as `/init ./foo.exe`. + # + # We detect that by running `/init /known-not-existing-path.exe` and checking the exit code: + # the new style interp expects at least two arguments, so exits with exit code 1, + # presumably meaning "parsing error"; the old style interp attempts to actually run + # the executable, fails to find it, and exits with 255. + compatWrapper = pkgs.writeShellScript "nixos-wsl-binfmt-hack" '' + /init /nixos-wsl-does-not-exist.exe + [ $? -eq 255 ] && shift + exec /init "$@" + ''; + + # use the autodetect hack if unset, otherwise call /init directly + interpreter = if compat == null then compatWrapper else "/init"; + + # enable for the wrapper and autodetect hack + preserveArgvZero = if compat == false then false else true; + in + { + magicOrExtension = "MZ"; + fixBinary = true; + wrapInterpreterInShell = false; + inherit interpreter preserveArgvZero; + }; + }; + + # Include Windows %PATH% in Linux $PATH. + environment.extraInit = mkIf cfg.includePath ''PATH="$PATH:$WSLPATH"''; + + warnings = + let + registrations = config.boot.binfmt.registrations; + in + optional (!(registrations ? WSLInterop) && (length (attrNames config.boot.binfmt.registrations)) != 0) "Having any binfmt registrations without re-registering WSLInterop (wsl.interop.register) will break running .exe files from WSL2"; + }; + + +} diff --git a/modules/wsl-distro.nix b/modules/wsl-distro.nix index 0f7d8b0..e87112a 100644 --- a/modules/wsl-distro.nix +++ b/modules/wsl-distro.nix @@ -28,34 +28,6 @@ with builtins; with lib; type = attrsOf (attrsOf (oneOf [ string int bool ])); description = "Entries that are added to /etc/wsl.conf"; }; - - interop = { - register = mkOption { - type = bool; - default = true; - description = "Explicitly register the binfmt_misc handler for Windows executables"; - }; - - includePath = mkOption { - type = bool; - default = true; - description = "Include Windows PATH in WSL PATH"; - }; - }; - - compatibility = { - interopPreserveArgvZero = mkOption { - type = nullOr bool; - default = null; - description = '' - Register binfmt interpreter for Windows executables with 'preserves argv[0]' flag. - - Default (null): autodetect, at some performance cost. - To avoid the performance cost, set this to true for WSL Preview 0.58 and up, - or to false for any older versions, including pre-Microsoft Store and Windows 10. - ''; - }; - }; }; config = @@ -79,52 +51,12 @@ with builtins; with lib; }; # WSL is closer to a container than anything else - boot = { - isContainer = true; - - binfmt.registrations = mkIf cfg.interop.register { - WSLInterop = - let - compat = cfg.compatibility.interopPreserveArgvZero; - - # WSL Preview 0.58 and up registers the /init binfmt interp for Windows executable - # with the "preserve argv[0]" flag, so if you run `./foo.exe`, the interp gets invoked - # as `/init foo.exe ./foo.exe`. - # argv[0] --^ ^-- actual path - # - # Older versions expect to be called without the argv[0] bit, simply as `/init ./foo.exe`. - # - # We detect that by running `/init /known-not-existing-path.exe` and checking the exit code: - # the new style interp expects at least two arguments, so exits with exit code 1, - # presumably meaning "parsing error"; the old style interp attempts to actually run - # the executable, fails to find it, and exits with 255. - compatWrapper = pkgs.writeShellScript "nixos-wsl-binfmt-hack" '' - /init /nixos-wsl-does-not-exist.exe - [ $? -eq 255 ] && shift - exec /init "$@" - ''; - - # use the autodetect hack if unset, otherwise call /init directly - interpreter = if compat == null then compatWrapper else "/init"; - - # enable for the wrapper and autodetect hack - preserveArgvZero = if compat == false then false else true; - in - { - magicOrExtension = "MZ"; - fixBinary = true; - wrapInterpreterInShell = false; - inherit interpreter preserveArgvZero; - }; - }; - }; + 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 = { - # Include Windows %PATH% in Linux $PATH. - extraInit = mkIf cfg.interop.includePath ''PATH="$PATH:$WSLPATH"''; etc = { "wsl.conf".text = generators.toINI { } cfg.wslConf; -- cgit v1.2.3