Compare commits

..

25 commits

Author SHA1 Message Date
Val Packett
a7fe813f17 Add wl-backdrop (WIP) --bg-color option 2026-03-06 06:45:39 -03:00
Val Packett
38a96b79b3 [BREAKING] Provide runtime environment systemd services from munix
These services evolve as munix evolves, so they should not be part of
the system closures themselves. Mount them into /run/systemd instead.

(Yes, making /run/systemd/system a symlink to RO files is unfortunate,
 that could be changed in the future. FS prep code is annoying too..)
2026-03-06 06:09:48 -03:00
Val Packett
604ebc1356 [BREAKING] Switch to virtgpu-based D-Bus tunneling
This introduces support for drag&drop and printing portals, and later
camera/screencasting should be possible as well. However we break
backwards compatibility with already built closures because the
nixosModule needs to be changed.

In the next commit, the runtime environment related services will be
removed from the nixosModule to prevent unnecessary future breakage.
2026-03-06 05:09:55 -03:00
Val Packett
e00609ce73 nix: add some camera/pw testing tools to testvm 2026-02-27 02:50:54 -03:00
Val Packett
beeb5f5d9f Fork libkrun again to fix buffer mapping permission issue (fix #18)
Initial D-Bus WIP is also there..
2026-02-27 02:48:17 -03:00
zimbatm
adf2d24b60 fix(template): use structured settings for MPD audio output
Replace deprecated extraConfig with settings.audio_output
2026-02-24 11:08:53 +01:00
Val Packett
981393443b Set up a monotonic clock boot time offset in the VM 2026-02-20 05:17:13 -03:00
Val Packett
8c3878f117 Pass timezone through to the VM
What a way to discover that this was missing- PipeWire camera was
freezing unless something on the host was already streaming it…

gstclock.c:1086:gst_clock_get_internal_time:<pipewireclock0> internal time 1:01:04.622699903
gstclock.c:1129:gst_clock_get_time:<pipewireclock0> adjusted time 5123776:20:12.866176008

Well, that wasn't even caused by the TZ but it made me think to fix it..

NOTE for local dev, rebuild micro-activate now
2026-02-20 04:19:18 -03:00
Val Packett
322b6efc1c nix: testvm: update stateVersion, add rewaita (theme coloring for demos) 2026-02-13 14:55:42 -03:00
Val Packett
820fcd3da1 nix: chase removal of etc overlay symlinks, fixes #14 2026-02-13 14:55:09 -03:00
Val Packett
53f827553f nix: add nautilus to testvm
Will be useful for testing drag-out
2026-02-07 01:24:55 -03:00
Val Packett
09f1eb76de nix: comment out libkrun(fw) source overrides
As we're currently using entirely upstream ones right now. Let's reuse
the cache.nixos.org builds.
2026-02-07 01:24:44 -03:00
Val Packett
9708e5fb64 nix: update nixpkgs
now includes the most recent libkrun(fw) releases
2026-02-07 00:21:19 -03:00
Val Packett
67666b8f46 nix: update sidebus and flake-parts
sidebus now uses flake-parts too
2026-02-07 00:17:26 -03:00
Val Packett
585970fe92 munix: do not set display from the script
It is now entirely managed by systemd.
2026-01-30 06:12:35 -03:00
Val Packett
a82b0de310 munix: set wayland/pw/portal enablement variables for toolkits by default 2026-01-30 06:10:48 -03:00
Val Packett
8113c269cb munix: add more arg shorthands 2026-01-30 05:47:22 -03:00
Val Packett
38213f4ada munix: add publish argument for port forwarding, fix #11
TODO: fix https://github.com/AsahiLinux/muvm/issues/178 as well
2026-01-30 05:44:13 -03:00
Val Packett
425ff896c8 nix: deorbit virtwl-proxy 2026-01-30 04:35:20 -03:00
Val Packett
9911b15fb7 nix: switch to wl-cross-domain-proxy 2026-01-30 04:27:22 -03:00
Val Packett
13b2afcc14 nix: add package for wl-cross-domain-proxy 2026-01-30 03:16:39 -03:00
Val Packett
c89c9e4d9b nix: testvm: more test apps 2026-01-30 03:15:49 -03:00
Val Packett
40d82a0fd8 nix: use static userborn
as it's upstream now
2026-01-30 01:39:17 -03:00
Val Packett
c11c6c6292 nix: update inputs 2026-01-30 00:02:31 -03:00
Val Packett
447ccad362 nix: devShell: add packages for proxy development 2026-01-29 20:54:07 -03:00
24 changed files with 441 additions and 366 deletions

View file

@ -1,17 +1,49 @@
{ mkShell, lib, systemd, cargo, rust-analyzer, rustfmt, passt, bubblewrap, libkrun, muvm, sidebus-broker }: {
mkShell,
lib,
systemd,
cargo,
rust-analyzer,
rustfmt,
passt,
bubblewrap,
libkrun,
muvm,
sidebus-broker,
wl-cross-domain-proxy,
wl-backdrop,
pkgs,
}:
let let
projects = [ libkrun muvm ]; projects = [
in mkShell { libkrun
muvm
];
in
mkShell {
MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd"; MUVM_UDEVD_PATH = "${systemd}/lib/systemd/systemd-udevd";
nativeBuildInputs = lib.concatMap (pkg: pkg.nativeBuildInputs) projects; nativeBuildInputs = lib.concatMap (pkg: pkg.nativeBuildInputs) projects;
buildInputs = (lib.concatMap (pkg: pkg.buildInputs) projects) ++ [ buildInputs =
# virglrenderer (lib.concatMap (pkg: pkg.buildInputs) projects)
cargo ++ [
rust-analyzer # virglrenderer
rustfmt cargo
passt rust-analyzer
bubblewrap rustfmt
sidebus-broker passt
]; bubblewrap
sidebus-broker
wl-cross-domain-proxy
wl-backdrop
]
++ (with pkgs; [
meson
wayland
wayland-protocols
wayland-scanner
cairo
libgbm
]);
# Enough things to compile wl-cross-domain-proxy, muvm, etc. in development
} }

206
flake.lock generated
View file

@ -7,11 +7,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1768135262, "lastModified": 1769996383,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", "rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -20,100 +20,47 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"libkrun-src": { "libkrun-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1764837222, "lastModified": 1772170018,
"narHash": "sha256-Q4uFc3gvo6AuN1fAuUWU8k/+idOuDEj8Pkhm80wE798=", "narHash": "sha256-pi4Mrx9wFE8zT8lx+0su2bP1tTkJBh5FaGNQjAFUAx4=",
"owner": "containers", "owner": "valpackett",
"repo": "libkrun", "repo": "libkrun",
"rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", "rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "containers", "owner": "valpackett",
"repo": "libkrun", "repo": "libkrun",
"rev": "b250ee6fff7d959da3d55bb62ffe09d87248651c", "rev": "eeafbc55379b60379414168e7a22d5f95b73d7a0",
"type": "github"
}
},
"libkrunfw-src": {
"flake": false,
"locked": {
"lastModified": 1762790667,
"narHash": "sha256-tVQ0jGef8uJNo2L4Pmhy3ajVRKJ2Gs9oi44eOYAnmds=",
"owner": "containers",
"repo": "libkrunfw",
"rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5",
"type": "github"
},
"original": {
"owner": "containers",
"repo": "libkrunfw",
"rev": "8a8c33f24f72aa6ca017347dc2be45b6fa612af5",
"type": "github" "type": "github"
} }
}, },
"muvm-src": { "muvm-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1763708092, "lastModified": 1772176363,
"narHash": "sha256-8K9XDnQbl/fh1Bsx1SwFuo5WVy5BztCjMPT6NW01lXQ=", "narHash": "sha256-aSWulv3ml4XmMYnFOkZCd2YBLIY0Rr8CUHK1NDYk5jw=",
"owner": "valpackett", "owner": "valpackett",
"repo": "muvm", "repo": "muvm",
"rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", "rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "valpackett", "owner": "valpackett",
"repo": "muvm", "repo": "muvm",
"rev": "3ec4c90bbfb6d0111f91b898a7f17deb562f4f92", "rev": "c68742bcedb96deb6f23ed5a83188022d1cdf71d",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1764242076, "lastModified": 1770197578,
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -127,111 +74,60 @@
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts",
"libkrun-src": "libkrun-src", "libkrun-src": "libkrun-src",
"libkrunfw-src": "libkrunfw-src",
"muvm-src": "muvm-src", "muvm-src": "muvm-src",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"sidebus": "sidebus", "sidebus": "sidebus",
"virtwl": "virtwl" "wl-backdrop": "wl-backdrop"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"sidebus",
"nixpkgs"
]
},
"locked": {
"lastModified": 1763087910,
"narHash": "sha256-eB9Z1mWd1U6N61+F8qwDggX0ihM55s4E0CluwNukJRU=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "cf4a68749733d45c0420726596367acd708eb2e8",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
} }
}, },
"sidebus": { "sidebus": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-parts": [
"nixpkgs": [ "flake-parts"
"nixpkgs"
], ],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1765527875,
"narHash": "sha256-QKsl+TAjdd1qk8Nd9mlByz07S+kGi8voSxxTdUNjt6A=",
"ref": "main",
"rev": "c9095421c6ec33e7293879d2df9d050991200803",
"shallow": true,
"type": "git",
"url": "https://git.clan.lol/clan/sidebus"
},
"original": {
"ref": "main",
"shallow": true,
"type": "git",
"url": "https://git.clan.lol/clan/sidebus"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"virtwl": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1758075582, "lastModified": 1772183103,
"narHash": "sha256-o2lpXQLaM9QcZVr+sAxvh83CqJW1QkFhfja6K40ndmA=", "narHash": "sha256-9jbqBtaLUdOeT95PVUMz45JdUpVeJ25ZYZHEOQn9XsI=",
"ref": "wip", "ref": "main",
"rev": "5a5df73a11b2f6bf671a8fc89926ac993e0fbb78", "rev": "c42eaef55440e2594677ede5279bd8c3eaf128f2",
"shallow": true, "shallow": true,
"submodules": true,
"type": "git", "type": "git",
"url": "https://github.com/valpackett/wayland-proxy-virtwl" "url": "https://git.clan.lol/clan/sidebus"
}, },
"original": { "original": {
"ref": "wip", "ref": "main",
"shallow": true, "shallow": true,
"submodules": true,
"type": "git", "type": "git",
"url": "https://github.com/valpackett/wayland-proxy-virtwl" "url": "https://git.clan.lol/clan/sidebus"
}
},
"wl-backdrop": {
"inputs": {
"flake-parts": [
"flake-parts"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1772781884,
"narHash": "sha256-epVLmAHnJi4EoZea5DUmxB3r6SPSMu3Nzki7JzbK0sA=",
"ref": "main",
"rev": "20e3910ef60aa627933a5d750b60cc3dcd0653cf",
"shallow": true,
"type": "git",
"url": "https://git.clan.lol/valpackett/wl-backdrop"
},
"original": {
"ref": "main",
"shallow": true,
"type": "git",
"url": "https://git.clan.lol/valpackett/wl-backdrop"
} }
} }
}, },

View file

@ -10,25 +10,27 @@
flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
virtwl.url = "git+https://github.com/valpackett/wayland-proxy-virtwl?shallow=1&submodules=1&ref=wip";
virtwl.inputs.nixpkgs.follows = "nixpkgs";
sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main"; sidebus.url = "git+https://git.clan.lol/clan/sidebus?shallow=1&ref=main";
sidebus.inputs.nixpkgs.follows = "nixpkgs"; sidebus.inputs.nixpkgs.follows = "nixpkgs";
sidebus.inputs.flake-parts.follows = "flake-parts";
wl-backdrop.url = "git+https://git.clan.lol/valpackett/wl-backdrop?shallow=1&ref=main";
wl-backdrop.inputs.nixpkgs.follows = "nixpkgs";
wl-backdrop.inputs.flake-parts.follows = "flake-parts";
# To override with local checkouts during development, use the --override-input CLI flag! # To override with local checkouts during development, use the --override-input CLI flag!
muvm-src = { muvm-src = {
url = "github:valpackett/muvm/3ec4c90bbfb6d0111f91b898a7f17deb562f4f92"; url = "github:valpackett/muvm/c68742bcedb96deb6f23ed5a83188022d1cdf71d"; # v0.5.0+custom-init+dbus
flake = false; flake = false;
}; };
libkrun-src = { libkrun-src = {
url = "github:containers/libkrun/b250ee6fff7d959da3d55bb62ffe09d87248651c"; url = "github:valpackett/libkrun/eeafbc55379b60379414168e7a22d5f95b73d7a0"; # PR #558 (map permission fix) + D-Bus WIP
flake = false;
};
libkrunfw-src = {
url = "github:containers/libkrunfw/8a8c33f24f72aa6ca017347dc2be45b6fa612af5";
flake = false; flake = false;
}; };
# libkrunfw-src = {
# url = "github:containers/libkrunfw/20484a2e60290acb74c43ccfd6e1ea4caf41d470"; # v5.1.0
# flake = false;
# };
}; };
outputs = outputs =
@ -36,11 +38,11 @@
self, self,
nixpkgs, nixpkgs,
flake-parts, flake-parts,
virtwl,
sidebus, sidebus,
wl-backdrop,
muvm-src, muvm-src,
libkrun-src, libkrun-src,
libkrunfw-src, # libkrunfw-src,
... ...
}: }:
flake-parts.lib.mkFlake { inherit inputs; } { flake-parts.lib.mkFlake { inherit inputs; } {
@ -50,9 +52,9 @@
]; ];
flake = { flake = {
nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { inherit virtwl; }; nixosModules.testvm = nixpkgs.lib.modules.importApply ./nixosModules/testvm.nix { };
nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix { nixosModules.default = nixpkgs.lib.modules.importApply ./nixosModules/default.nix {
inherit self virtwl sidebus; inherit self;
}; };
templates.musictest = { templates.musictest = {
@ -106,7 +108,7 @@
# Packages support variant parameter: null (default), "sev", or "tdx" # Packages support variant parameter: null (default), "sev", or "tdx"
# To build a variant: packages.libkrunfw.override { variant = "sev"; } # To build a variant: packages.libkrunfw.override { variant = "sev"; }
libkrunfw = pkgs.callPackage ./packages/libkrunfw { libkrunfw = pkgs.callPackage ./packages/libkrunfw {
libkrunfw-src = libkrunfw-src; # libkrunfw-src = libkrunfw-src;
}; };
libkrun = pkgs.callPackage ./packages/libkrun { libkrun = pkgs.callPackage ./packages/libkrun {
@ -124,15 +126,19 @@
munix = pkgs.callPackage ./packages/munix { munix = pkgs.callPackage ./packages/munix {
mesa = self'.packages.mesa; mesa = self'.packages.mesa;
muvm = self'.packages.muvm; muvm = self'.packages.muvm;
wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy;
wl-backdrop = wl-backdrop.packages.${system}.wl-backdrop;
sidebus-broker = sidebus.packages.${system}.sidebus-broker; sidebus-broker = sidebus.packages.${system}.sidebus-broker;
}; };
sidebus-agent = sidebus.packages.${system}.sidebus-agent; wl-cross-domain-proxy = pkgs.callPackage ./packages/wl-cross-domain-proxy { };
}; };
devShells.default = pkgs.callPackage ./devShells { devShells.default = pkgs.callPackage ./devShells {
libkrun = self'.packages.libkrun; libkrun = self'.packages.libkrun;
muvm = self'.packages.muvm; muvm = self'.packages.muvm;
wl-cross-domain-proxy = self'.packages.wl-cross-domain-proxy;
wl-backdrop = wl-backdrop.packages.${system}.wl-backdrop;
sidebus-broker = sidebus.packages.${system}.sidebus-broker; sidebus-broker = sidebus.packages.${system}.sidebus-broker;
}; };
}; };

View file

@ -8,6 +8,8 @@ const MS_NODEV: c_ulong = 0x04;
const MS_RELATIME: c_ulong = 0x200000; const MS_RELATIME: c_ulong = 0x200000;
const MS_STRICTATIME: c_ulong = 0x1000000; const MS_STRICTATIME: c_ulong = 0x1000000;
const CLONE_NEWTIME: c_int = 0x80;
unsafe extern "C" { unsafe extern "C" {
fn mount( fn mount(
src: *const c_char, src: *const c_char,
@ -17,6 +19,7 @@ unsafe extern "C" {
data: *const c_void, data: *const c_void,
) -> c_int; ) -> c_int;
fn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> c_int; fn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> c_int;
fn unshare(flags: c_int) -> c_int;
} }
fn gen_machine_id() -> String { fn gen_machine_id() -> String {
@ -71,6 +74,7 @@ fn main() -> Result<(), std::io::Error> {
// //
// Let's preserve the fixed passed-in files and set up the NixOS symlinks in the new mount. // Let's preserve the fixed passed-in files and set up the NixOS symlinks in the new mount.
let resolv_conf = std::fs::read("/run/resolv.conf")?; let resolv_conf = std::fs::read("/run/resolv.conf")?;
let localtime = std::fs::read("/run/localtime")?;
assert_eq!( assert_eq!(
unsafe { unsafe {
mount( mount(
@ -83,8 +87,11 @@ fn main() -> Result<(), std::io::Error> {
}, },
0 0
); );
std::fs::write("/run/localtime", &localtime)?;
std::fs::write("/run/resolv.conf", &resolv_conf)?; std::fs::write("/run/resolv.conf", &resolv_conf)?;
std::fs::write("/run/machine-id", &gen_machine_id())?; std::fs::write("/run/machine-id", &gen_machine_id())?;
std::fs::create_dir("/run/systemd")?;
std::os::unix::fs::symlink("/opt/systemd", "/run/systemd/system")?;
std::os::unix::fs::symlink(&closure, "/run/current-system")?; std::os::unix::fs::symlink(&closure, "/run/current-system")?;
if let Ok(tmp_graphics) = if let Ok(tmp_graphics) =
std::fs::read(format!("{closure}/etc/tmpfiles.d/graphics-driver.conf")) std::fs::read(format!("{closure}/etc/tmpfiles.d/graphics-driver.conf"))
@ -131,6 +138,17 @@ fn main() -> Result<(), std::io::Error> {
); );
} }
if let Ok(offset) = std::env::var("BOOT_TIME_OFFSET") {
if unsafe { unshare(CLONE_NEWTIME) } != 0 {
eprintln!("[micro-activate] Could not unshare time!");
} else {
std::fs::write(
"/proc/self/timens_offsets",
format!("monotonic {offset}\nboottime {offset}\n"),
)?;
}
}
let mut args = std::env::args_os().skip(1); let mut args = std::env::args_os().skip(1);
let cmd = args.next().unwrap(); let cmd = args.next().unwrap();
Err(std::process::Command::new(cmd).args(args).exec()) Err(std::process::Command::new(cmd).args(args).exec())

97
munix
View file

@ -2,24 +2,46 @@
SCRIPT_PATH=$(dirname $(realpath -s $0)) SCRIPT_PATH=$(dirname $(realpath -s $0))
MUVM_PATH=$(dirname $(which muvm)) MUVM_PATH=$(dirname $(which muvm))
PASST_PATH=$(dirname $(which passt)) PASST_PATH=$(dirname $(which passt))
WL_PROXY_PATH=$(dirname $(which wl-cross-domain-proxy))
WL_BACKDROP_PATH=$(dirname $(which wl-backdrop))
HOST_OPENGL_DRIVER=/run/opengl-driver HOST_OPENGL_DRIVER=/run/opengl-driver
: "${MICROVM_DEFAULT_COMMAND:=bash}" : "${MICROVM_DEFAULT_COMMAND:=bash}"
: "${MUNIX_SYSTEMD_UNITS:="${SCRIPT_PATH}/systemd"}"
MICROVM_CLOSURE= MICROVM_CLOSURE=
MICROVM_COMMAND=() MICROVM_COMMAND=()
MICROVM_UID=1337 MICROVM_UID=1337
MICROVM_GID=1337 MICROVM_GID=1337
BWRAP_ARGS=() BWRAP_ARGS=()
MUVM_ARGS=() MUVM_ARGS=()
SIDEBUS_ARGS=()
GPU=1 GPU=1
WAYLAND=1 WAYLAND=1
PIPEWIRE=1 PIPEWIRE=1
X11=0 X11=0
ENV_DEFAULTS=1
USING_PUBLISH=0
export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C export TMP=/tmp TMPDIR=/tmp TEMP=/tmp TEMPDIR=/tmp LC_ALL=C
if [ ! -e "$HOST_OPENGL_DRIVER" ]; then if [ ! -e "$HOST_OPENGL_DRIVER" ]; then
HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER" HOST_OPENGL_DRIVER="$FALLBACK_OPENGL_DRIVER"
fi fi
# A little bit cursed: pre-pass to relaunch with new env var..
BG_COLOR=
pargs=()
while [ "$#" -gt 0 ]; do
case "$1" in
--bg-color) BG_COLOR="$2"; shift 2;;
--wl-backdrop-bin-dir) WL_BACKDROP_PATH="$2"; shift 2;;
*) pargs+=("$1"); shift;;
esac
done
if [ "$BG_COLOR" = "" ]; then
set -- "${pargs[@]}"
else
exec "$WL_BACKDROP_PATH/wl-backdrop" --background "$BG_COLOR" -- "$(readlink -f "$0")" "${pargs[@]}"
fi
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
case "$1" in case "$1" in
-u|--uid) MICROVM_UID="$2"; shift 2;; -u|--uid) MICROVM_UID="$2"; shift 2;;
@ -27,15 +49,19 @@ while [ "$#" -gt 0 ]; do
--no-gpu) GPU=0; shift 1;; --no-gpu) GPU=0; shift 1;;
--no-wayland) WAYLAND=0; shift 1;; --no-wayland) WAYLAND=0; shift 1;;
--no-pipewire) PIPEWIRE=0; shift 1;; --no-pipewire) PIPEWIRE=0; shift 1;;
--no-env-defaults) ENV_DEFAULTS=0; shift 1;;
--x11) X11=1; shift 1;; --x11) X11=1; shift 1;;
--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); shift 3;; -b|--bind) BWRAP_ARGS+=("--bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;;
--ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); shift 3;; --ro-bind) BWRAP_ARGS+=("--ro-bind" "$2" "$3"); SIDEBUS_ARGS+=("--path-mapping" "$3=$2"); shift 3;;
--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); shift 2;; -e|--expose) BWRAP_ARGS+=("--bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;;
--ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); shift 2;; --ro-expose) BWRAP_ARGS+=("--ro-bind" "$2" "$2"); SIDEBUS_ARGS+=("--path-mapping" "$2=$2"); shift 2;;
-p|--publish) USING_PUBLISH=1; MUVM_ARGS+=("--publish=$2"); shift 2;;
--host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;; --host-opengl-driver) HOST_OPENGL_DRIVER="$2"; shift 2;;
--munix-bin-dir) SCRIPT_PATH="$2"; shift 2;; --munix-bin-dir) SCRIPT_PATH="$2"; shift 2;;
--muvm-bin-dir) MUVM_PATH="$2"; shift 2;; --muvm-bin-dir) MUVM_PATH="$2"; shift 2;;
--passt-bin-dir) PASST_PATH="$2"; shift 2;; --passt-bin-dir) PASST_PATH="$2"; shift 2;;
--wl-proxy-bin-dir) WL_PROXY_PATH="$2"; shift 2;;
--wl-backdrop-bin-dir) shift 2;;
--) shift 1; MICROVM_COMMAND+=("$@"); break;; --) shift 1; MICROVM_COMMAND+=("$@"); break;;
-*) echo "munix: unknown option: $1" >&2; exit 1;; -*) echo "munix: unknown option: $1" >&2; exit 1;;
*) *)
@ -63,6 +89,16 @@ if [ "$PASST_PATH" = "" ]; then
exit 1 exit 1
fi fi
if [ "$WL_PROXY_PATH" = "" ]; then
echo "munix: wl-cross-domain-proxy not found, provide a --wl-proxy-bin-dir or fix \$PATH" >&2
exit 1
fi
if [ "$WL_BACKDROP_PATH" = "" ]; then
echo "munix: wl-backdrop not found, provide a --wl-backdrop-bin-dir or fix \$PATH" >&2
exit 1
fi
if [ ! -e "$HOST_OPENGL_DRIVER" ]; then if [ ! -e "$HOST_OPENGL_DRIVER" ]; then
echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2 echo "munix: host graphics driver not found, provide a --host-opengl-driver" >&2
exit 1 exit 1
@ -122,7 +158,15 @@ if [ "$WAYLAND" -eq 1 ]; then
"--bind" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "--bind" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"
"--setenv" "WAYLAND_DISPLAY" "$WAYLAND_DISPLAY" "--setenv" "WAYLAND_DISPLAY" "$WAYLAND_DISPLAY"
) )
MUVM_ARGS+=("-e" "WAYLAND_DISPLAY=wayland-1") # the proxy is managed by us, not muvm if [ "$ENV_DEFAULTS" -eq 1 ]; then
MUVM_ARGS+=(
"-e" "XDG_SESSION_TYPE=wayland"
"-e" "SDL_VIDEODRIVER=wayland"
"-e" "QT_QPA_PLATFORM=wayland"
"-e" "_JAVA_AWT_WM_NONREPARENTING=1" # e.g. with xwayland-satellite
"-e" "ELECTRON_OZONE_PLATFORM_HINT=wayland" # 28 < Electron < 39; newer should work by default
)
fi
fi fi
if [ "$PIPEWIRE" -eq 1 ]; then if [ "$PIPEWIRE" -eq 1 ]; then
@ -140,6 +184,11 @@ if [ "$PIPEWIRE" -eq 1 ]; then
PIPEWIRE_REMOTE=pipewire-0 PIPEWIRE_REMOTE=pipewire-0
fi fi
BWRAP_ARGS+=("--bind" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE") BWRAP_ARGS+=("--bind" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE" "$PIPEWIRE_RUNTIME_DIR/$PIPEWIRE_REMOTE")
if [ "$ENV_DEFAULTS" -eq 1 ]; then
MUVM_ARGS+=(
"-e" "SDL_AUDIO_DRIVER=pipewire"
)
fi
fi fi
if [ "$X11" -eq 1 ]; then if [ "$X11" -eq 1 ]; then
@ -169,13 +218,35 @@ trap cleanup EXIT INT TERM
HOST_RUNTIME_DIR="$XDG_RUNTIME_DIR/munix.$$" HOST_RUNTIME_DIR="$XDG_RUNTIME_DIR/munix.$$"
mkdir -p $HOST_RUNTIME_DIR mkdir -p $HOST_RUNTIME_DIR
rm $HOST_RUNTIME_DIR/* rm $HOST_RUNTIME_DIR/*
sidebus-broker --guest-mountpoint /mnt/munix-doc-portal/doc --runtime-dir "$HOST_RUNTIME_DIR" --unix-path "$HOST_RUNTIME_DIR/port.sock" >/dev/null 2>&1 & mkdir -p "$HOST_RUNTIME_DIR/home"
RUST_LOG=debug sidebus-broker \
--path-mapping "/home=$HOST_RUNTIME_DIR/home" \
"${SIDEBUS_ARGS[@]}" \
--guest-mountpoint /mnt/munix-doc-portal/doc \
--runtime-dir "$HOST_RUNTIME_DIR" \
--unix-path "$HOST_RUNTIME_DIR/port.sock" & # >/dev/null 2>&1 &
BG_PIDS+=("$!") BG_PIDS+=("$!")
while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done while [ ! -S "$HOST_RUNTIME_DIR/port.sock" ]; do sleep 0.1; done
BWRAP_ARGS+=( BWRAP_ARGS=( # prepend home mount before other mounts to not override custom bind mounts under /home
--bind "$HOST_RUNTIME_DIR/home" /home
"${BWRAP_ARGS[@]}"
--bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal --bind "$HOST_RUNTIME_DIR" /mnt/munix-doc-portal
--bind "$HOST_RUNTIME_DIR/port.sock" "$XDG_RUNTIME_DIR/krun/socket/port-50000" --setenv "RUTABAGA_DBUS_CLIENT_SOCKET" /mnt/munix-doc-portal/port.sock
) )
if [ "$ENV_DEFAULTS" -eq 1 ]; then
MUVM_ARGS+=(
"-e" "GTK_USE_PORTAL=1" # GTK 3 including Firefox
"-e" "QT_QPA_PLATFORMTHEME=xdgdesktopportal"
)
fi
if [ "$USING_PUBLISH" -eq 1 ]; then
printf "\n\n\n\e[1mNote: due to a \e[31mBUG\e[39m with port publishing (-p) you have to send the first outgoing packet (e.g. ping -c1 8.8.8.8) before your ports start receiving traffic. Sorry for the inconvenience!\e[39;0m\n\n\n\n" >&2
fi
# xxx: some time is lost to the starting process..
[[ "$(</proc/uptime)" =~ ([0-9]+)\.([0-9]+) ]]
BOOT_TIME_OFFSET="${BASH_REMATCH[1]} $(( ${BASH_REMATCH[2]} * 1000000 ))"
# do not 'exec' because of cleanup :) # do not 'exec' because of cleanup :)
bwrap --unshare-all --share-net \ bwrap --unshare-all --share-net \
@ -187,23 +258,29 @@ bwrap --unshare-all --share-net \
--ro-bind "$MUVM_PATH" /run/munix/muvm \ --ro-bind "$MUVM_PATH" /run/munix/muvm \
--ro-bind "$PASST_PATH" /run/munix/passt \ --ro-bind "$PASST_PATH" /run/munix/passt \
--ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \ --ro-bind "$SCRIPT_PATH/micro-activate" /opt/bin/micro-activate \
--ro-bind "$WL_PROXY_PATH/wl-cross-domain-proxy" /opt/bin/wl-cross-domain-proxy \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-remote \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-configure-network \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \ --ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-pwbridge \
--ro-bind "$MUVM_PATH/muvm-guest" /opt/bin/muvm-dbusbridge \
--ro-bind "$MUNIX_SYSTEMD_UNITS" /opt/systemd \
--symlink "$MICROVM_CLOSURE/etc" /etc \ --symlink "$MICROVM_CLOSURE/etc" /etc \
--symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \ --symlink "$MICROVM_CLOSURE/sw/bin/sh" /bin/sh \
--symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \ --symlink "$MICROVM_CLOSURE/sw/bin/env" /usr/bin/env \
--symlink "$MICROVM_CLOSURE" /run/current-system \ --symlink "$MICROVM_CLOSURE" /run/current-system \
--ro-bind /nix/store /nix/store \ --ro-bind /nix/store /nix/store \
--file 13 /run/resolv.conf \ --file 13 /run/resolv.conf \
--file 14 /run/localtime \
--dir "$XDG_RUNTIME_DIR" \ --dir "$XDG_RUNTIME_DIR" \
--setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \ --setenv PATH "/run/munix/muvm:/run/munix/passt:$MICROVM_CLOSURE/sw/bin" \
"${BWRAP_ARGS[@]}" \ "${BWRAP_ARGS[@]}" \
muvm \ muvm \
--custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console systemd.set_credential=sidebus.port:50000" \ --custom-init-cmdline "/opt/bin/micro-activate $MICROVM_CLOSURE/sw/sbin/init --log-target=console" \
"${MUVM_ARGS[@]}" \ "${MUVM_ARGS[@]}" \
-e container=munix \ -e container=munix \
-e MICROVM_CLOSURE="$MICROVM_CLOSURE" \ -e MICROVM_CLOSURE="$MICROVM_CLOSURE" \
-e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \ -e MICROVM_UID="$MICROVM_UID" -e MICROVM_GID="$MICROVM_GID" \
-e BOOT_TIME_OFFSET="$BOOT_TIME_OFFSET" \
-i -t -- "${MICROVM_COMMAND[@]}" \ -i -t -- "${MICROVM_COMMAND[@]}" \
13< /etc/resolv.conf 13< /etc/resolv.conf \
14< /etc/localtime

View file

@ -1,7 +1,5 @@
{ {
self, self,
virtwl,
sidebus,
}: }:
{ {
pkgs, pkgs,
@ -11,38 +9,7 @@
... ...
}: }:
let let
useTTY = {
TTYPath = "/dev/hvc0";
StandardOutput = "tty";
StandardInput = "tty";
StandardError = "tty";
};
runtimeDir = "/run/vm-user"; runtimeDir = "/run/vm-user";
userbornConfig = {
groups = lib.mapAttrsToList (username: opts: {
inherit (opts) name gid members;
}) config.users.groups;
users = lib.mapAttrsToList (username: opts: {
inherit (opts)
name
uid
group
description
home
password
hashedPassword
hashedPasswordFile
initialPassword
initialHashedPassword
;
isNormal = opts.isNormalUser;
shell = utils.toShellPath opts.shell;
}) (lib.filterAttrs (_: u: u.enable) config.users.users);
};
userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig);
userbornResults =
pkgs.runCommand "baked userborn" { }
"mkdir -p $out; ${lib.getExe pkgs.userborn} ${userbornConfigJson} $out";
system = pkgs.stdenv.hostPlatform.system; system = pkgs.stdenv.hostPlatform.system;
in in
{ {
@ -79,12 +46,18 @@ in
boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd
system.etc.overlay.enable = true; # erofs system.etc.overlay.enable = true; # erofs
system.etc.overlay.mutable = false; system.etc.overlay.mutable = false;
system.systemBuilderCommands = # XXX: removed with the introduction of nixos-init
''
ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image
ln -s ${config.system.build.etcBasedir} $out/etc-basedir
'';
system.switch.enable = false; system.switch.enable = false;
services.udev.enable = lib.mkDefault true; services.udev.enable = lib.mkDefault true;
services.udev.packages = lib.mkDefault [ ]; services.udev.packages = lib.mkDefault [ ];
services.resolved.enable = false; services.resolved.enable = false;
environment.etc."resolv.conf".source = "/run/resolv.conf"; environment.etc."resolv.conf".source = "/run/resolv.conf";
environment.etc."machine-id".source = "/run/machine-id"; environment.etc."machine-id".source = "/run/machine-id";
environment.etc."localtime".source = "/run/localtime";
environment.etc."systemd/system".source = lib.mkForce ( environment.etc."systemd/system".source = lib.mkForce (
utils.systemdUtils.lib.generateUnits { utils.systemdUtils.lib.generateUnits {
type = "system"; type = "system";
@ -166,23 +139,9 @@ in
}; };
# Configure user accounts # Configure user accounts
# The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service.
# So we can just run userborn at system closure build time!
systemd.sysusers.enable = false; systemd.sysusers.enable = false;
services.userborn.enable = true; services.userborn.enable = true;
systemd.services.userborn.enable = false; services.userborn.static = true;
environment.etc."passwd" = lib.mkForce {
source = "${userbornResults}/passwd";
mode = "0444";
};
environment.etc."group" = lib.mkForce {
source = "${userbornResults}/group";
mode = "0444";
};
environment.etc."shadow" = lib.mkForce {
source = "${userbornResults}/shadow";
mode = "0440";
};
users.mutableUsers = false; users.mutableUsers = false;
users.users.appvm = { users.users.appvm = {
uid = 1337; uid = 1337;
@ -206,86 +165,6 @@ in
systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}"; systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}";
systemd.services.muvm-remote = {
enable = true;
description = "microVM Application runner";
onFailure = [ "exit.target" ];
onSuccess = [ "exit.target" ];
wants = [ "sockets.target" ];
after = [ "sockets.target" ];
wantedBy = [ "microvm.target" ];
serviceConfig = {
Type = "exec";
PassEnvironment = [
"TERM"
"MESA_LOADER_DRIVER_OVERRIDE"
"MUVM_REMOTE_CONFIG"
]; # "KRUN_CONFIG"];
Environment = [
"WAYLAND_DISPLAY=wayland-1"
"DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"
"PATH=/run/current-system/sw/bin"
];
User = "appvm";
Group = "appvm";
ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}";
ExecStart = "/opt/bin/muvm-remote";
ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"'';
}
// useTTY;
};
systemd.services.muvm-configure-network = {
enable = true;
description = "microVM Network configuration";
wantedBy = [ "microvm.target" ];
serviceConfig.Type = "oneshot";
serviceConfig.ExecStart = "/opt/bin/muvm-configure-network";
};
systemd.sockets.muvm-pwbridge = {
enable = true;
description = "PipeWire cross-domain proxy socket";
wantedBy = [ "microvm.target" ];
partOf = [ "muvm-pwbridge.service" ];
listenStreams = [ "${runtimeDir}/pipewire-0" ];
socketConfig = {
SocketUser = "appvm";
SocketGroup = "appvm";
};
};
systemd.services.muvm-pwbridge = {
enable = true;
description = "PipeWire cross-domain proxy";
requires = [ "muvm-pwbridge.socket" ];
serviceConfig.Type = "exec";
serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge";
};
systemd.sockets.wayland-proxy-virtwl = {
enable = true;
description = "Wayland cross-domain proxy socket";
wantedBy = [ "microvm.target" ];
partOf = [ "wayland-proxy-virtwl.service" ];
listenStreams = [ "${runtimeDir}/wayland-1" ];
socketConfig = {
SocketUser = "appvm";
SocketGroup = "appvm";
FileDescriptorName = "wayland";
};
};
systemd.services.wayland-proxy-virtwl = {
enable = true;
description = "Wayland cross-domain proxy";
requires = [ "wayland-proxy-virtwl.socket" ];
serviceConfig = {
ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128";
ExecStart = "${virtwl.packages.${system}.proxy}/bin/wayland-proxy-virtwl --virtio-gpu";
User = "appvm";
Group = "appvm";
};
};
systemd.sockets.session-bus = { systemd.sockets.session-bus = {
enable = true; enable = true;
description = "D-Bus session bus socket"; description = "D-Bus session bus socket";
@ -307,20 +186,6 @@ in
Group = "appvm"; Group = "appvm";
}; };
}; };
systemd.services.sidebus-agent = {
enable = true;
description = "D-Bus session bus";
wantedBy = ["microvm.target"];
requires = ["session-bus.socket" "session-bus.service"];
after = ["session-bus.service"];
serviceConfig = {
ImportCredential = "sidebus.port";
Environment = ["DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"];
ExecStart = "${sidebus.packages.${system}.sidebus-agent}/bin/sidebus-agent";
User = "appvm";
Group = "appvm";
};
};
hardware.graphics.enable = true; hardware.graphics.enable = true;
hardware.graphics.package = self.packages.${system}.mesa; hardware.graphics.package = self.packages.${system}.mesa;

View file

@ -1,13 +1,12 @@
{ virtwl }: { }:
{ pkgs, ... }: { { pkgs, ... }: {
system.stateVersion = "25.11"; system.stateVersion = "26.05";
fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ]; fonts.packages = [ pkgs.adwaita-fonts pkgs.dejavu_fonts ];
programs.dconf.enable = true; programs.dconf.enable = true;
environment.systemPackages = [ environment.systemPackages = [
pkgs.fastfetch pkgs.fastfetch
pkgs.htop pkgs.htop
virtwl.packages.${pkgs.stdenv.hostPlatform.system}.proxy
pkgs.wayland-utils pkgs.wayland-utils
pkgs.weston pkgs.weston
pkgs.waycheck pkgs.waycheck
@ -16,8 +15,8 @@
pkgs.mesa-demos pkgs.mesa-demos
pkgs.xorg.xeyes pkgs.xorg.xeyes
pkgs.xterm pkgs.xterm
# pkgs.vkquake # build broken: Program 'spirv-remap' not found pkgs.vkquake
# pkgs.veloren # broken after update? # pkgs.veloren
pkgs.kdePackages.kate pkgs.kdePackages.kate
pkgs.adwaita-icon-theme pkgs.adwaita-icon-theme
pkgs.amberol pkgs.amberol
@ -33,5 +32,13 @@
pkgs.zerotierone pkgs.zerotierone
pkgs.localsend pkgs.localsend
pkgs.ashpd-demo pkgs.ashpd-demo
pkgs.nautilus
pkgs.rewaita
pkgs.wl-clipboard-rs
pkgs.snapshot
pkgs.gst_all_1.gst-plugins-base
pkgs.gst_all_1.gst-plugins-good
pkgs.gst_all_1.gst-plugins-bad
pkgs.gst_all_1.gstreamer
]; ];
} }

View file

@ -1,18 +1,32 @@
{ libkrun, libkrunfw, libkrun-src, rustPlatform, variant ? null, ... }: {
libkrun,
libkrunfw,
libkrun-src,
rustPlatform,
libcap_ng,
variant ? null,
...
}:
let let
libkrunfw' = libkrunfw.override { inherit variant; }; libkrunfw' = libkrunfw.override { inherit variant; };
libkrun' = libkrun.override {
withBlk = true;
withNet = true;
withGpu = true;
# --- stick to the override used in nixpkgs' muvm package to reuse nixos.org cache when not overriding src ---
# withSound = true; # not for pipewire forwarding, anyway
# withTimesync = true; # why not?..
# ---------
inherit variant;
libkrunfw = libkrunfw';
};
in in
(libkrun.override { # libkrun'
withBlk = true; libkrun'.overrideAttrs (old: {
withGpu = true;
withSound = true;
withNet = true;
inherit variant;
libkrunfw = libkrunfw';
}).overrideAttrs (old: {
src = libkrun-src; src = libkrun-src;
cargoDeps = rustPlatform.importCargoLock { cargoDeps = rustPlatform.importCargoLock {
lockFile = "${libkrun-src}/Cargo.lock"; lockFile = "${libkrun-src}/Cargo.lock";
}; };
buildInputs = old.buildInputs ++ [ libcap_ng ]; # new dep
}) })

View file

@ -1,12 +1,22 @@
{ libkrunfw, libkrunfw-src, fetchurl, variant ? null, ... }: {
libkrunfw,
# libkrunfw-src,
# fetchurl,
variant ? null,
...
}:
(libkrunfw.override { let
inherit variant; libkrunfw' = libkrunfw.override {
}).overrideAttrs (old: { inherit variant;
version = "5.0.0";
src = libkrunfw-src;
kernelSrc = fetchurl {
url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.44.tar.xz";
hash = "sha256-tlAhDtMCeyJJadFIqjd0Uqmq065/KFGr7dMa3+8Wva4=";
}; };
}) in
libkrunfw'
# libkrunfw'.overrideAttrs (old: {
# version = "5.1.0";
# src = libkrunfw-src;
# kernelSrc = fetchurl {
# url = "mirror://kernel/linux/kernel/v6.x/linux-6.12.62.tar.xz";
# hash = "sha256-E+LGhayPq13Zkt0QVzJVTa5RSu81DCqMdBjnt062LBM=";
# };
# })

View file

@ -1,9 +1,18 @@
{ stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, mesa, rustc }: { stdenv, writeScriptBin, symlinkJoin, makeWrapper, muvm, passt, bubblewrap, sidebus-broker, wl-cross-domain-proxy, wl-backdrop, mesa, rustc }:
let let
munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: { munixScript = (writeScriptBin "munix" (builtins.readFile ../../munix)).overrideAttrs(old: {
buildCommand = "${old.buildCommand}\n patchShebangs $out"; buildCommand = "${old.buildCommand}\n patchShebangs $out";
}); });
munixSystemd = stdenv.mkDerivation {
name = "munix-systemd";
src = ../../systemd;
dontUnpack = true;
installPhase = ''
mkdir -p $out
cp -aR $src/* $out
'';
};
microActivate = stdenv.mkDerivation { microActivate = stdenv.mkDerivation {
name = "micro-activate"; name = "micro-activate";
src = ../../micro-activate.rs; src = ../../micro-activate.rs;
@ -19,9 +28,9 @@ let
}; };
in symlinkJoin { in symlinkJoin {
name = "munix"; name = "munix";
paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker ]; paths = [ munixScript microActivate muvm passt bubblewrap sidebus-broker wl-cross-domain-proxy wl-backdrop ];
buildInputs = [ makeWrapper ]; buildInputs = [ makeWrapper ];
postBuild = '' postBuild = ''
wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} wrapProgram $out/bin/munix --prefix PATH : $out/bin --set FALLBACK_OPENGL_DRIVER ${mesa} --set MUNIX_SYSTEMD_UNITS ${munixSystemd}
''; '';
} }

View file

@ -0,0 +1,44 @@
{
lib,
rustPlatform,
# fetchpatch,
fetchFromGitea,
pkg-config,
libdrm,
}:
# TODO: upstream
rustPlatform.buildRustPackage {
pname = "wl-cross-domain-proxy";
version = "0-unstable-2026-01-30";
src = fetchFromGitea {
domain = "codeberg.org";
owner = "drakulix";
repo = "wl-cross-domain-proxy";
rev = "c6ce1ca89fb4d6f4f18d3aaf88324d40d4589177";
hash = "sha256-ydyT4DFzWzhzOZR591UOgLjVQt/v6hRSNjzM3QtohlU=";
};
nativeBuildInputs = [ pkg-config ];
buildInputs = [ libdrm ];
cargoHash = "sha256-k3dmxIuCQoOrn/VwauTdzuRw/XKQB6LPLgO5ql0rE7E=";
cargoPatches = [
# (fetchpatch {
# name = "XXX.patch";
# url = "https://codeberg.org/drakulix/wl-cross-domain-proxy/pulls/XXX.patch";
# hash = lib.fakeHash;
# })
];
meta = {
homepage = "https://codeberg.org/drakulix/wl-cross-domain-proxy";
description = "Proxy for the wayland protocol across virtio-gpu cross-domain context";
mainProgram = "wl-cross-domain-proxy";
platforms = lib.platforms.linux;
license = [ lib.licenses.mit ];
maintainers = [ lib.maintainers.valpackett ];
};
}

View file

@ -0,0 +1 @@
../muvm-configure-network.service

View file

@ -0,0 +1 @@
../muvm-remote.service

View file

@ -0,0 +1 @@
../pipewire-bridge.socket

View file

@ -0,0 +1 @@
../session-bus-bridge.service

View file

@ -0,0 +1 @@
../wayland-bridge.socket

View file

@ -0,0 +1,6 @@
[Unit]
Description=microVM Network configuration
[Service]
Type=oneshot
ExecStart=/opt/bin/muvm-configure-network

View file

@ -0,0 +1,33 @@
[Unit]
After=sockets.target
Description=microVM Application runner
OnFailure=exit.target
OnSuccess=exit.target
Wants=sockets.target
[Service]
Type=exec
# Environment="LOCALE_ARCHIVE=/nix/store/1hilqf0v1nm2w8xj87pwpm0rgq6lvhlv-glibc-locales-2.42-47/lib/locale/locale-archive"
# Environment="TZDIR=/nix/store/80izpiglrlqv2zb7rd7m5274k2dr142l-tzdata-2025c/share/zoneinfo"
Environment=WAYLAND_DISPLAY=wayland-1
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/vm-user/dbus.sock
Environment=PATH=/run/current-system/sw/bin
PassEnvironment=MESA_LOADER_DRIVER_OVERRIDE
PassEnvironment=MUVM_REMOTE_CONFIG
PassEnvironment=TERM
PassEnvironment=XDG_SESSION_TYPE
PassEnvironment=SDL_VIDEODRIVER
PassEnvironment=QT_QPA_PLATFORM
PassEnvironment=_JAVA_AWT_WM_NONREPARENTING
PassEnvironment=ELECTRON_OZONE_PLATFORM_HINT
PassEnvironment=GTK_USE_PORTAL
PassEnvironment=QT_QPA_PLATFORMTHEME
ExecStartPre=+/run/current-system/sw/bin/chown appvm:appvm /run/vm-user
ExecStart=/opt/bin/muvm-remote
ExecStopPost=+/nix/store/ygzfhw5nxrn7qqfqmz2s9p6cikcjqqkh-python3-3.13.11/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"
User=appvm
Group=appvm
StandardError=tty
StandardInput=tty
StandardOutput=tty
TTYPath=/dev/hvc0

View file

@ -0,0 +1,12 @@
[Unit]
Description=PipeWire VM bridge
Requires=pipewire-bridge.socket
[Service]
Type=exec
ExecStart=/opt/bin/muvm-pwbridge
# Environment=RUST_LOG=debug
# StandardError=tty
# StandardOutput=tty
# TTYPath=/dev/hvc0

View file

@ -0,0 +1,8 @@
[Unit]
Description=PipeWire VM bridge socket
PartOf=pipewire-bridge.service
[Socket]
SocketGroup=appvm
SocketUser=appvm
ListenStream=/run/vm-user/pipewire-0

View file

@ -0,0 +1,11 @@
[Unit]
After=session-bus.service
Description=D-Bus VM integration bridge
Requires=session-bus.socket session-bus.service
[Service]
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/vm-user/dbus.sock
ExecStartPre=+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128
ExecStart=/opt/bin/muvm-dbusbridge
Group=appvm
User=appvm

View file

@ -0,0 +1,13 @@
[Unit]
Description=Wayland VM bridge
Requires=wayland-bridge.socket
[Service]
ExecStartPre=+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128
ExecStart=/opt/bin/wl-cross-domain-proxy --listen-fd --filter-global wp_presentation
User=appvm
Group=appvm
StandardError=tty
StandardOutput=tty
TTYPath=/dev/hvc0

View file

@ -0,0 +1,9 @@
[Unit]
Description=Wayland VM bridge socket
PartOf=wayland-bridge.service
[Socket]
FileDescriptorName=wayland
SocketGroup=appvm
SocketUser=appvm
ListenStream=/run/vm-user/wayland-1

View file

@ -46,12 +46,12 @@
musicDirectory = "/etc/demo-music"; musicDirectory = "/etc/demo-music";
user = "appvm"; user = "appvm";
group = "appvm"; group = "appvm";
extraConfig = '' settings.audio_output = [
audio_output { {
type "pipewire" type = "pipewire";
name "Pipewire Output" name = "Pipewire Output";
} }
''; ];
}; };
environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl { environment.etc."demo-music/0101GhostsI.ogg".source = pkgs.fetchurl {
# just a CC-BY-SA licensed example # just a CC-BY-SA licensed example