Compare commits

..

12 Commits

13 changed files with 183 additions and 294 deletions

View File

@ -6,7 +6,7 @@ WFVM
A Nix library to create and manage virtual machines running Windows, a medieval operating system found on most computers in 2020. The F stands for "Functional" or a four-letter word of your choice.
* Reproducible - everything runs in the Nix sandbox with no tricks.
* Fully automatic, parameterizable Windows 11 installation.
* Fully automatic, parameterizable Windows 10 installation.
* Uses QEMU with KVM.
* Supports incremental installation (using "layers") of additional software via QEMU copy-on-write backing chains. For example, ``wfvm.makeWindowsImage { installCommands = [ wfvm.layers.anaconda3 ]; };`` gives you a VM image with Anaconda3 installed, and ``wfvm.makeWindowsImage { installCommands = [ wfvm.layers.anaconda3 wfvm.layers.msys2 ]; };`` gives you one with both Anaconda3 and MSYS2 installed. The base Windows installation and the Anaconda3 data are shared between both images, and only the MSYS2 installation is performed when building the second image after the first one has been built.
* Included layers: Anaconda3, a software installer chock full of bugs that pretends to be a package manager, Visual Studio, a spamming system for Microsoft accounts that includes a compiler, and MSYS2, which is the only sane component in the whole lot.
@ -28,21 +28,14 @@ How to use
Install a Windows image
-----------------------
1. Adjust demo-image.nix accordingly
1. Adjust demo-image in ``flake.nix`` accordingly
2. Run:
If in impure mode
```shell
nix-build demo-image.nix
nix build .#demo-image
./result
```
Results in a file called c.img
If in pure mode
```shell
nix-build demo-image.nix
ls -la ./result
```
Results in a symlink to the image in the nix store
@ -53,29 +46,4 @@ Sometimes it can be useful to build the image _outside_ of the Nix sandbox for d
For this purpose we have an attribute called `impureMode` which outputs the shell script used by Nix inside the sandbox to build the image.
Usage with Nix Flakes
---------------------
Build the demo by running:
```shell
nix build .#demoImage
```
This project's **flake.nix** exposes its functions under `lib`. To use
in your own project, setup your flake like this:
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
wfvm.url = "git+https://git.m-labs.hk/m-labs/wfvm";
};
outputs = { self, nixpkgs, wfvm }: {
packages."x86_64-linux".flaky-os = wfvm.lib.makeWindowsImage {
# configuration parameters go here
};
};
}
```
When building an image with flakes, use ``nix build .#demo-image-impure`` instead.

8
flake.lock generated
View File

@ -2,17 +2,17 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1685004253,
"narHash": "sha256-AbVL1nN/TDicUQ5wXZ8xdLERxz/eJr7+o8lqkIOVuaE=",
"lastModified": 1593034146,
"narHash": "sha256-EypP7RyPq5Yv05VgsQoIkdn26KJUIgQCItHgVY1MMQE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e01645c40b92d29f3ae76344a6d654986a91a91",
"rev": "f8248ab6d9e69ea9c07950d73d48807ec595e923",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"rev": "f8248ab6d9e69ea9c07950d73d48807ec595e923",
"type": "github"
}
},

144
flake.nix
View File

@ -1,37 +1,129 @@
{
description = "WFVM: Windows Functional Virtual Machine";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";
};
description = "A Nix library to create and manage virtual machines running Windows.";
inputs.nixpkgs.url = github:NixOS/nixpkgs/f8248ab6d9e69ea9c07950d73d48807ec595e923;
outputs = { self, nixpkgs }:
let
# only x64 is supported
system = "x86_64-linux";
pkgs = import nixpkgs { system = "x86_64-linux"; };
lib = pkgs.lib;
# utils
utils = (import wfvm/utils.nix { inherit pkgs; });
# layers
layers = (import wfvm/layers { inherit pkgs; }); # end of layers
pkgs = nixpkgs.legacyPackages.${system};
in rec {
lib = import ./wfvm {
inherit pkgs;
};
packages.${system} = rec {
demoImage = import ./wfvm/demo-image.nix {
inherit self;
# makeWindowsImage
makeWindowsImage = attrs: import wfvm/win.nix ({ inherit pkgs; } // attrs );
build-demo-image = { impureMode ? false }: makeWindowsImage {
# Build install script & skip building iso
inherit impureMode;
# Custom base iso
# windowsImage = pkgs.requireFile rec {
# name = "Win10_21H1_English_x64.iso";
# sha256 = "1sl51lnx4r6ckh5fii7m2hi15zh8fh7cf7rjgjq9kacg8hwyh4b9";
# message = "Get ${name} from https://www.microsoft.com/en-us/software-download/windows10ISO";
# };
# impureShellCommands = [
# "powershell.exe echo Hello"
# ];
# User accounts
# users = {
# artiq = {
# password = "1234";
# # description = "Default user";
# # displayName = "Display name";
# groups = [
# "Administrators"
# ];
# };
# };
# Auto login
# defaultUser = "artiq";
# fullName = "M-Labs";
# organization = "m-labs";
# administratorPassword = "12345";
# Imperative installation commands, to be installed incrementally
installCommands = if impureMode then [] else (with layers; [
(collapseLayers [
disable-autosleep
disable-autolock
disable-firewall
])
anaconda3 msys2 msvc msvc-ide-unbreak
]);
# services = {
# # Enable remote management
# WinRm = {
# Status = "Running";
# PassThru = true;
# };
# };
# License key (required)
# productKey = throw "Search the f* web"
# imageSelection = "1";
# Locales
# uiLanguage = "en-US";
# inputLocale = "en-US";
# userLocale = "en-US";
# systemLocale = "en-US";
};
default = lib.utils.wfvm-run {
name = "demo";
image = demoImage;
script =
''
echo "Windows booted. Press Enter to terminate VM."
read
'';
display = true;
in {
# bundle dev env
devShell.x86_64-linux = pkgs.mkShell {
name = "wfvm-dev-shell";
buildInputs = with pkgs; [
go
];
shellHook = ''
unset GOPATH
'';
};
inherit utils;
inherit makeWindowsImage;
inherit layers;
demo-ssh = utils.wfvm-run {
name = "demo-ssh";
image = build-demo-image {};
isolateNetwork = false;
script = ''
${pkgs.sshpass}/bin/sshpass -p1234 -- ${pkgs.openssh}/bin/ssh -p 2022 wfvm@localhost -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
'';
};
packages.x86_64-linux = {
demo-image = build-demo-image {};
demo-image-impure = build-demo-image { impureMode = true; };
make-msys-packages = utils.wfvm-run {
name = "get-msys-packages";
image = makeWindowsImage { installCommands = [ layers.msys2 ]; };
script = ''
cat > getmsyspackages.bat << EOF
set MSYS=C:\\MSYS64
set TOOLPREF=mingw-w64-x86_64-
set PATH=%MSYS%\usr\bin;%MSYS%\mingw64\bin;%PATH%
pacman -Sp %TOOLPREF%gcc %TOOLPREF%binutils make autoconf automake libtool texinfo > packages.txt
EOF
\${utils.win-put}/bin/win-put getmsyspackages.bat
\${utils.win-exec}/bin/win-exec getmsyspackages
\${utils.win-get}/bin/win-get packages.txt
'';
};
};
};
}
}

View File

@ -15,8 +15,7 @@
, impureShellCommands ? []
, driveLetter ? "D:"
, efi ? true
, imageSelection ? "Windows 11 Pro N"
, enableTpm
, imageSelection ? "1"
, ...
}:
@ -59,16 +58,18 @@ let
assertCommand = c: builtins.typeOf c == "string" || builtins.typeOf c == "set" && builtins.hasAttr "Path" c && builtins.hasAttr "Description" c;
commands = builtins.map (x: assert assertCommand x; if builtins.typeOf x == "string" then { Path = x; Description = x; } else x) (
[ {
Path = "powershell.exe Set-ExecutionPolicy -Force Unrestricted";
Description = "Allow unsigned powershell scripts.";
} {
Path = ''powershell.exe ${driveLetter}\win-bundle-installer.exe'';
Description = "Install any declared packages.";
} {
Path = "net accounts /maxpwage:unlimited";
Description = "Disable forced password expiry.";
} ]
[
{
Path = "powershell.exe Set-ExecutionPolicy -Force Unrestricted";
Description = "Allow unsigned powershell scripts.";
}
]
++ [
{
Path = ''powershell.exe ${driveLetter}\win-bundle-installer.exe'';
Description = "Install any declared packages.";
}
]
++ setupCommands
++ [
{
@ -147,14 +148,6 @@ let
</DriverPaths>
</component>
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
${lib.optionalString (!enableTpm) ''
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>reg add HKLM\System\Setup\LabConfig /v BypassTPMCheck /t reg_dword /d 0x00000001 /f</Path>
</RunSynchronousCommand>
</RunSynchronous>
''}
<DiskConfiguration>
<Disk wcm:action="add">
@ -206,9 +199,8 @@ let
<PartitionID>3</PartitionID>
</InstallTo>
<InstallFrom>
<Path>\install.swm</Path>
<MetaData wcm:action="add">
<Key>/IMAGE/NAME</Key>
<Key>/IMAGE/INDEX</Key>
<Value>${imageSelection}</Value>
</MetaData>
</InstallFrom>
@ -217,7 +209,7 @@ let
<UserData>
<ProductKey>
${if productKey != null then "<Key>${productKey}</Key>" else "<Key/>"}
${if productKey != null then "<Key>${productKey}</Key>" else ""}
<WillShowUI>OnError</WillShowUI>
</ProductKey>
<AcceptEula>true</AcceptEula>
@ -307,13 +299,13 @@ let
</component>
</settings>
<cpi:offlineImage cpi:source="wim:c:/wim/windows-11/install.wim#${imageSelection}" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
<cpi:offlineImage cpi:source="wim:c:/wim/windows-10/install.wim#${imageSelection}" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>
'';
in {
# Lint and format as a sanity check
autounattendXML = pkgs.runCommand "autounattend.xml" {} ''
autounattendXML = pkgs.runCommandNoCC "autounattend.xml" {} ''
${pkgs.libxml2}/bin/xmllint --format ${autounattendXML} > $out
'';

View File

@ -1,10 +0,0 @@
{ pkgs }:
pkgs.runCommand "win-bundle-installer.exe" {} ''
mkdir bundle
cd bundle
cp ${./go.mod} go.mod
cp ${./main.go} main.go
env HOME=$(mktemp -d) GOOS=windows GOARCH=amd64 ${pkgs.go}/bin/go build
mv bundle.exe $out
''

View File

@ -1,13 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.go
];
shellHook = ''
unset GOPATH
'';
}

View File

@ -1,7 +0,0 @@
{ pkgs }:
{
makeWindowsImage = attrs: import ./win.nix ({ inherit pkgs; } // attrs);
layers = import ./layers { inherit pkgs; };
utils = import ./utils.nix { inherit pkgs; };
}

View File

@ -1,82 +0,0 @@
{ pkgs ? import <nixpkgs> {}
# Whether to generate just a script to start and debug the windows installation
, impureMode ? false
# Flake input `self`
, self ? null
}:
let
wfvm =
if self == null
# nix-build
then (import ./default.nix { inherit pkgs; })
# built from flake.nix
else self.lib;
in
wfvm.makeWindowsImage {
# Build install script & skip building iso
inherit impureMode;
# Custom base iso
# windowsImage = pkgs.requireFile rec {
# name = "Win11_22H2_English_x64v1.iso";
# sha256 = "08mbppsm1naf73z8fjyqkf975nbls7xj9n4fq0yp802dv1rz3whd";
# message = "Get disk image ${name} from https://www.microsoft.com/en-us/software-download/windows11/";
# };
# impureShellCommands = [
# "powershell.exe echo Hello"
# ];
# User accounts
# users = {
# artiq = {
# password = "1234";
# # description = "Default user";
# # displayName = "Display name";
# groups = [
# "Administrators"
# ];
# };
# };
# Auto login
# defaultUser = "artiq";
# fullName = "M-Labs";
# organization = "m-labs";
# administratorPassword = "12345";
# Imperative installation commands, to be installed incrementally
installCommands =
if impureMode
then []
else with wfvm.layers; [
(collapseLayers [
disable-autosleep
disable-autolock
disable-firewall
])
anaconda3 msys2
];
# services = {
# # Enable remote management
# WinRm = {
# Status = "Running";
# PassThru = true;
# };
# };
# License key (required)
# productKey = throw "Search the f* web"
imageSelection = "Windows 11 Pro N";
# Locales
# uiLanguage = "en-US";
# inputLocale = "en-US";
# userLocale = "en-US";
# systemLocale = "en-US";
}

View File

@ -1,13 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
let
wfvm = (import ./default.nix { inherit pkgs; });
in
wfvm.utils.wfvm-run {
name = "demo-ssh";
image = import ./demo-image.nix { inherit pkgs; };
isolateNetwork = false;
script = ''
${pkgs.sshpass}/bin/sshpass -p1234 -- ${pkgs.openssh}/bin/ssh -p 2022 wfvm@localhost -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
'';
}

View File

@ -1,6 +1,7 @@
{ pkgs }:
let
wfvm = import ../. { inherit pkgs; };
makeWindowsImage = attrs: import ../win.nix ({ inherit pkgs; } // attrs );
utils = import ../utils.nix { inherit pkgs; };
in
{
anaconda3 = {
@ -72,20 +73,20 @@ in
bootstrapper = pkgs.fetchurl {
name = "RESTRICTDIST-vs_Community.exe";
url = "https://aka.ms/vs/16/release/vs_community.exe";
sha256 = "sha256-l4ZKFZTgHf3BmD0eFWyGwsvb4lqB/LiQYizAABOs3gg=";
sha256 = "sha256-bxi8LsvNxSZshkTbhK/FEmMx84NKYB7TUNOm9sAKXS8=";
};
# This touchy-feely "community" piece of trash seems deliberately crafted to break Wine, so we use the VM to run it.
download-vs = wfvm.utils.wfvm-run {
download-vs = utils.wfvm-run {
name = "download-vs";
image = wfvm.makeWindowsImage { };
image = makeWindowsImage { };
isolateNetwork = false;
script =
''
ln -s ${bootstrapper} vs_Community.exe
${wfvm.utils.win-put}/bin/win-put vs_Community.exe
${utils.win-put}/bin/win-put vs_Community.exe
rm vs_Community.exe
${wfvm.utils.win-exec}/bin/win-exec "vs_Community.exe --quiet --norestart --layout c:\vslayout --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended --lang en-US"
${wfvm.utils.win-get}/bin/win-get /c:/vslayout
${utils.win-exec}/bin/win-exec "vs_Community.exe --quiet --norestart --layout c:\vslayout --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended --lang en-US"
${utils.win-get}/bin/win-get /c:/vslayout
'';
};
cache = pkgs.stdenv.mkDerivation {
@ -93,7 +94,7 @@ in
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-GoOKzln8DXVMx52jWGEjwkOFkpSW+wEffAVmBVugIyk=";
outputHash = "0ic3jvslp2y9v8yv9mfr2mafkvj2q5frmcyhmlbxj71si1x3kpag";
phases = [ "buildPhase" ];
buildInputs = [ download-vs ];

View File

@ -2,27 +2,7 @@
set -e
nix-build -E "
let
pkgs = import <nixpkgs> {};
wfvm = import ../default.nix { inherit pkgs; };
in
wfvm.utils.wfvm-run {
name = \"get-msys-packages\";
image = wfvm.makeWindowsImage { installCommands = [ wfvm.layers.msys2 ]; };
script = ''
cat > getmsyspackages.bat << EOF
set MSYS=C:\\MSYS64
set TOOLPREF=mingw-w64-x86_64-
set PATH=%MSYS%\usr\bin;%MSYS%\mingw64\bin;%PATH%
pacman -Sp %TOOLPREF%gcc %TOOLPREF%binutils make autoconf automake libtool texinfo > packages.txt
EOF
\${wfvm.utils.win-put}/bin/win-put getmsyspackages.bat
\${wfvm.utils.win-exec}/bin/win-exec getmsyspackages
\${wfvm.utils.win-get}/bin/win-get packages.txt
'';
}
"
nix build .#make-msys-packages
./result/bin/wfvm-run-get-msys-packages

View File

@ -1,45 +1,23 @@
{ pkgs
, baseRtc ? "2022-10-10T10:10:10"
, cores ? "4"
, qemuMem ? "4G"
, efi ? true
, enableTpm ? false
, ...
}:
{ pkgs, baseRtc ? "2020-04-20T14:21:42", cores ? "4", qemuMem ? "4G", efi ? true }:
rec {
# qemu_test is a smaller closure only building for a single system arch
qemu = pkgs.qemu;
OVMF = pkgs.OVMF.override {
secureBoot = true;
};
mkQemuFlags = extraFlags: [
"-enable-kvm"
"-cpu host"
"-smp ${cores}"
"-m ${qemuMem}"
"-M q35,smm=on"
"-M q35"
"-vga qxl"
"-rtc base=${baseRtc}"
"-device qemu-xhci"
"-device virtio-net-pci,netdev=n1"
] ++ pkgs.lib.optionals efi [
"-bios ${OVMF.fd}/FV/OVMF.fd"
] ++ pkgs.lib.optionals enableTpm [
"-chardev" "socket,id=chrtpm,path=tpm.sock"
"-tpmdev" "emulator,id=tpm0,chardev=chrtpm"
"-device" "tpm-tis,tpmdev=tpm0"
"-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"
] ++ extraFlags;
tpmStartCommands = pkgs.lib.optionalString enableTpm ''
mkdir -p tpmstate
${pkgs.swtpm}/bin/swtpm socket \
--tpmstate dir=tpmstate \
--ctrl type=unixio,path=tpm.sock &
'';
# Pass empty config file to prevent ssh from failing to create ~/.ssh
sshOpts = "-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=1";
win-exec = pkgs.writeShellScriptBin "win-exec" ''
@ -115,7 +93,6 @@ rec {
]);
in pkgs.writeShellScriptBin "wfvm-run-${name}" ''
set -e -m
${tpmStartCommands}
${qemu}/bin/qemu-system-x86_64 ${pkgs.lib.concatStringsSep " " qemuParams} &
${win-wait}/bin/win-wait

View File

@ -5,17 +5,17 @@
, impureMode ? false
, installCommands ? []
, users ? {}
, enableTpm ? true
# autounattend always installs index 1, so this default is backward-compatible
, imageSelection ? "Windows 11 Pro N"
, imageSelection ? "Windows 10 Pro"
, efi ? true
, bundleInstaller ? {}
, ...
}@attrs:
let
lib = pkgs.lib;
utils = import ./utils.nix ({ inherit pkgs efi enableTpm; } // attrs);
inherit (pkgs) guestfs-tools;
utils = import ./utils.nix { inherit pkgs efi; };
libguestfs = pkgs.libguestfs-with-appliance;
# p7zip on >20.03 has known vulns but we have no better option
p7zip = pkgs.p7zip.overrideAttrs(old: {
@ -24,8 +24,18 @@ let
};
});
# bundle
bundleInstaller = pkgs.runCommandNoCC "win-bundle-installer.exe" {} ''
mkdir bundle
cd bundle
cp ${bundle/go.mod} go.mod
cp ${bundle/main.go} main.go
env HOME=$(mktemp -d) GOOS=windows GOARCH=amd64 ${pkgs.go}/bin/go build
mv bundle.exe $out
'';
runQemuCommand = name: command: (
pkgs.runCommand name { buildInputs = [ p7zip utils.qemu guestfs-tools ]; }
pkgs.runCommandNoCC name { buildInputs = [ p7zip utils.qemu libguestfs ]; }
(
''
if ! test -f; then
@ -37,14 +47,15 @@ let
);
windowsIso = if windowsImage != null then windowsImage else pkgs.requireFile rec {
name = "Win11_22H2_English_x64v2.iso";
sha256 = "0xhhxy47yaf1jsfmskym5f65hljw8q0aqs70my86m402i6dsjnc0";
message = "Get disk image ${name} from https://www.microsoft.com/en-us/software-download/windows11/";
name = "xks67i4frg8k7rmlv5298aac0s4n5nih-RESTRICTDIST-release_svc_refresh_CLIENT_LTSC_EVAL_x64FRE_en-us.iso";
sha256 = "0fmw30g7959bh47z8xi5pmmxq4kb0sxs1qxf51il3xy2f2py33v6";
message = "Get ${name} from https://www.microsoft.com/en-us/software-download/windows10ISO";
};
# stable as of 2021-04-08
virtioWinIso = pkgs.fetchurl {
url = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.229-1/virtio-win.iso";
sha256 = "1q5vrcd70kya4nhlbpxmj7mwmwra1hm3x7w8rzkawpk06kg0v2n8";
url = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/virtio-win-0.1.185.iso";
sha256 = "11n3kjyawiwacmi3jmfmn311g9xvfn6m0ccdwnjxw1brzb4kqaxg";
};
openSshServerPackage = pkgs.fetchurl {
@ -54,7 +65,7 @@ let
autounattend = import ./autounattend.nix (
attrs // {
inherit pkgs enableTpm;
inherit pkgs;
users = users // {
wfvm = {
password = "1234";
@ -67,8 +78,6 @@ let
}
);
bundleInstaller = pkgs.callPackage ./bundle {};
# Packages required to drive installation of other packages
bootstrapPkgs =
runQemuCommand "bootstrap-win-pkgs.img" ''
@ -109,7 +118,7 @@ let
''
#!${pkgs.runtimeShell}
set -euxo pipefail
export PATH=${lib.makeBinPath [ p7zip utils.qemu guestfs-tools pkgs.wimlib ]}:$PATH
export PATH=${lib.makeBinPath [ p7zip utils.qemu libguestfs pkgs.wimlib ]}:$PATH
# Create a bootable "USB" image
# Booting in USB mode circumvents the "press any key to boot from cdrom" prompt
@ -120,7 +129,7 @@ let
7z x -y ${windowsIso} -owin
# Split image so it fits in FAT32 partition
wimsplit win/sources/install.wim win/sources/install.swm 4070
wimsplit win/sources/install.wim win/sources/install.swm 4090
rm win/sources/install.wim
cp ${autounattend.autounattendXML} win/autounattend.xml
@ -132,20 +141,18 @@ let
''}
rm -rf win
${utils.tpmStartCommands}
# Qemu requires files to be rw
qemu-img create -f qcow2 c.img ${diskImageSize}
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams}
''
);
baseImage = pkgs.runCommand "RESTRICTDIST-windows.img" {} ''
baseImage = pkgs.runCommandNoCC "RESTRICTDIST-windows.img" {} ''
${installScript}
mv c.img $out
'';
finalImage = builtins.foldl' (acc: v: pkgs.runCommand "RESTRICTDIST-${v.name}.img" {
finalImage = builtins.foldl' (acc: v: pkgs.runCommandNoCC "RESTRICTDIST-${v.name}.img" {
buildInputs = with utils; [
qemu win-wait win-exec win-put
] ++ (v.buildInputs or []);
@ -160,11 +167,8 @@ let
]);
in ''
set -x
${utils.tpmStartCommands}
# Create an image referencing the previous image in the chain
qemu-img create -F qcow2 -f qcow2 -b ${acc} c.img
qemu-img create -f qcow2 -b ${acc} c.img
set -m
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams} &