diff --git a/Cargo.lock b/Cargo.lock
index 3d963c1..5260a56 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -142,8 +142,8 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "busd"
-version = "0.5.0"
-source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#7084025107e02600043856c56fd178730526daad"
+version = "0.4.0"
+source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#25736c855284b13371f0be2ef38f16af8f73bda1"
dependencies = [
"anyhow",
"clap",
@@ -151,8 +151,8 @@ dependencies = [
"event-listener",
"fastrand",
"futures-util",
+ "nix 0.30.1",
"quick-xml",
- "rustix",
"serde",
"tokio",
"tracing",
@@ -635,15 +635,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.178"
+version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "linux-raw-sys"
-version = "0.11.0"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "listenfd"
@@ -726,6 +726,19 @@ dependencies = [
"memoffset",
]
+[[package]]
+name = "nix"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+ "memoffset",
+]
+
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -858,9 +871,9 @@ dependencies = [
[[package]]
name = "quick-xml"
-version = "0.39.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1"
+checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b"
dependencies = [
"memchr",
"serde",
@@ -927,15 +940,15 @@ checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustix"
-version = "1.1.3"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1013,7 +1026,6 @@ dependencies = [
"clap",
"eyre",
"futures",
- "libc",
"rand",
"rustix",
"sidebus-common",
@@ -1309,9 +1321,7 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
- "getrandom",
"js-sys",
- "serde",
"wasm-bindgen",
]
@@ -1328,7 +1338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e8b4d00e672f147fc86a09738fadb1445bd1c0a40542378dfb82909deeee688"
dependencies = [
"libc",
- "nix",
+ "nix 0.29.0",
]
[[package]]
@@ -1426,12 +1436,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-[[package]]
-name = "windows-link"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
-
[[package]]
name = "windows-sys"
version = "0.52.0"
@@ -1459,15 +1463,6 @@ dependencies = [
"windows-targets 0.53.2",
]
-[[package]]
-name = "windows-sys"
-version = "0.61.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
-dependencies = [
- "windows-link",
-]
-
[[package]]
name = "windows-targets"
version = "0.52.6"
@@ -1656,9 +1651,8 @@ dependencies = [
[[package]]
name = "zbus"
-version = "5.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc"
+version = "5.9.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"async-broadcast",
"async-recursion",
@@ -1668,17 +1662,16 @@ dependencies = [
"futures-core",
"futures-lite",
"hex",
- "libc",
+ "nix 0.30.1",
"ordered-stream",
- "rustix",
+ "rand",
"serde",
"serde_repr",
"tokio",
"tokio-vsock",
"tracing",
"uds_windows",
- "uuid",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
"winnow",
"zbus_macros",
"zbus_names",
@@ -1687,9 +1680,8 @@ dependencies = [
[[package]]
name = "zbus_macros"
-version = "5.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222"
+version = "5.9.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1702,9 +1694,8 @@ dependencies = [
[[package]]
name = "zbus_names"
-version = "4.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f"
+version = "4.2.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"serde",
"winnow",
@@ -1787,9 +1778,8 @@ dependencies = [
[[package]]
name = "zvariant"
-version = "5.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b"
+version = "5.6.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"endi",
"enumflags2",
@@ -1801,9 +1791,8 @@ dependencies = [
[[package]]
name = "zvariant_derive"
-version = "5.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c"
+version = "5.6.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1814,9 +1803,8 @@ dependencies = [
[[package]]
name = "zvariant_utils"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9"
+version = "3.2.0"
+source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 0f66a83..3d815b6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,4 +9,6 @@ members = [
[workspace.dependencies]
sidebus-common = { path = "sidebus-common" }
busd = { git = "https://github.com/valpackett/busd", branch = "val/msksqvsqqrxm", default-features = false }
-zbus = { version = "5.0", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] }
+zbus = { git = "https://github.com/dbus2/zbus", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] }
+# zbus git to match busd git
+
diff --git a/README.md b/README.md
index c8ebf21..df3aac1 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,6 @@
(it.. runs as a "sidecar" to a VM.. but manages D-*Bus*.. get it?)
-
-
A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portals] work across virtual machines.
[XDG Desktop Portals]: https://flatpak.github.io/xdg-desktop-portal/docs/index.html
@@ -14,8 +10,9 @@ A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portal
- `sidebus-broker` host process:
- to be launched alongside the VMM
- - hosts a "private" bus for VM-instance-specific daemons such as permission-store and document-portal
- - listens on vsock (or on a unix socket that muvm would proxy as vsock) and connects to the VM bus as a client when the agent connects
+ - hosts D-Bus servers in-process, based on [busd](https://github.com/dbus2/busd):
+ - a "private" bus for VM-instance-specific daemons such as permission-store and document-portal
+ - a "VM" bus, the one actually exposed to the guest over vsock
- orchestrates the lifecycle of the aforementioned daemons + virtiofsd
- (we are sharing the directory *provided by* the document-portal FUSE filesystem!)
- provides portal front-end interfaces like `org.freedesktop.portal.FileChooser` on the VM bus
@@ -23,10 +20,11 @@ A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portal
- (not talking directly to impls: don't want to reimplement per-DE portal selection; also 1:1 mapping is nicer to code)
- but with extra hooks like exposing files to the guest using our private (per-VM) document-portal!
- `sidebus-agent` guest process:
- - connects to the broker over vsock and splices the connection into the VM (session) bus
- - can be spawned spawned on-demand by D-Bus
+ - listens on a guest unix socket, proxies D-Bus messages to a vsock
+ - spawned on-demand by systemd via socket activation
- uses systemd credentials for config args like vsock port
- (very convenient to pass via the VMM, e.g. qemu: `-smbios type=11,value=io.systemd.credential:sidebus.port=1337`)
+ - guest NixOS configuration exposed via the flake
## Development Notes
diff --git a/flake.lock b/flake.lock
index 8445fa1..e8bb457 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,32 +1,30 @@
{
"nodes": {
- "flake-parts": {
+ "flake-utils": {
"inputs": {
- "nixpkgs-lib": [
- "nixpkgs"
- ]
+ "systems": "systems"
},
"locked": {
- "lastModified": 1768135262,
- "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
- "owner": "hercules-ci",
- "repo": "flake-parts",
- "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
- "owner": "hercules-ci",
- "repo": "flake-parts",
+ "owner": "numtide",
+ "repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
- "lastModified": 1762977756,
- "narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=",
+ "lastModified": 1751271578,
+ "narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55",
+ "rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df",
"type": "github"
},
"original": {
@@ -38,8 +36,44 @@
},
"root": {
"inputs": {
- "flake-parts": "flake-parts",
- "nixpkgs": "nixpkgs"
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1751510438,
+ "narHash": "sha256-m8PjOoyyCR4nhqtHEBP1tB/jF+gJYYguSZmUmVTEAQE=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "7f415261f298656f8164bd636c0dc05af4e95b6b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
}
}
},
diff --git a/flake.nix b/flake.nix
index c2050d0..1aeb30c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,60 +1,80 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- flake-parts.url = "github:hercules-ci/flake-parts";
- flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
+ flake-utils.url = "github:numtide/flake-utils";
+ rust-overlay = {
+ url = "github:oxalica/rust-overlay";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
- outputs =
- inputs@{ flake-parts, ... }:
- flake-parts.lib.mkFlake { inherit inputs; } {
- systems = [
- "x86_64-linux"
- "aarch64-linux"
- ];
-
- perSystem =
- { pkgs, ... }:
- let
- buildEnvVars = {
- BIN_XDG_PERMISSION_STORE = "${pkgs.xdg-desktop-portal}/libexec/xdg-permission-store";
- BIN_XDG_DOCUMENT_PORTAL = "${pkgs.xdg-desktop-portal}/libexec/xdg-document-portal";
- BIN_VIRTIOFSD = "${pkgs.virtiofsd}/bin/virtiofsd";
- };
-
- rustPackage =
- crate:
- let
- cargoToml = builtins.fromTOML (builtins.readFile ./${crate}/Cargo.toml);
- in
- pkgs.rustPlatform.buildRustPackage {
- inherit (cargoToml.package) name version;
- src = ./.;
- cargoLock.lockFile = ./Cargo.lock;
- cargoLock.outputHashes = {
- "busd-0.5.0" = "sha256-IZZ2MeEmUbzRrH6SUz0pnecMH4f8Mh54WdhI4q44YfI=";
- };
- buildAndTestSubdir = crate;
- env = buildEnvVars;
- };
- in
- {
- devShells.default = pkgs.mkShell {
- buildInputs = with pkgs; [
- cargo
- rustc
- rust-analyzer
- clippy
- ];
- env = buildEnvVars;
- };
-
- packages.sidebus-agent = rustPackage "sidebus-agent";
- packages.sidebus-broker = rustPackage "sidebus-broker";
+ outputs = {self, nixpkgs, flake-utils, rust-overlay}:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ overlays = [ (import rust-overlay) ];
+ pkgs = import nixpkgs {
+ inherit system overlays;
};
- flake = {
- nixosModules.sidebus-vm = ./nixosModules/sidebus-vm.nix;
- };
- };
+ buildEnvVars = {
+ BIN_XDG_PERMISSION_STORE = "${pkgs.xdg-desktop-portal}/libexec/xdg-permission-store";
+ BIN_XDG_DOCUMENT_PORTAL = "${pkgs.xdg-desktop-portal}/libexec/xdg-document-portal";
+ BIN_VIRTIOFSD = "${pkgs.virtiofsd}/bin/virtiofsd";
+ };
+
+ rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
+ rustPlatform = pkgs.makeRustPlatform {
+ cargo = rustToolchain;
+ rustc = rustToolchain;
+ };
+ rustPackage = crate:
+ let cargoToml = builtins.fromTOML (builtins.readFile ./${crate}/Cargo.toml);
+ in rustPlatform.buildRustPackage {
+ inherit (cargoToml.package) name version;
+ src = ./.;
+ cargoLock.lockFile = ./Cargo.lock;
+ cargoLock.outputHashes = {
+ "zbus-5.9.0" = "sha256-3xaKbf+JmO5yVwPbvA3z9dHvqICh7yCeKk1SIX8zhJA=";
+ "busd-0.4.0" = "sha256-UzTclEJ8lRMmiuLJJi+gsm7vkx+MLfnDdi5s9OVT1HE=";
+ };
+ buildAndTestSubdir = crate;
+ env = buildEnvVars;
+ };
+ in
+ {
+ devShells.default = pkgs.mkShell {
+ buildInputs = [ rustToolchain ];
+ env = buildEnvVars;
+ };
+
+ packages.sidebus-agent = rustPackage "sidebus-agent";
+ packages.sidebus-broker = rustPackage "sidebus-broker";
+
+ nixosModules.sidebus-vm = { ... }: {
+ environment.sessionVariables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/sidebus.sock";
+ systemd.sockets.sidebus-agent = {
+ # SocketMode= is 0666 by default
+ listenStreams = [ "/run/sidebus.sock" ];
+ wantedBy = [ "sockets.target" ];
+ documentation = [ "https://git.clan.lol/valpackett/sidebus" ];
+ };
+ systemd.services.sidebus-agent = {
+ # TODO: confinement (can do a lot)
+ serviceConfig = {
+ ExecStart = "${rustPackage "sidebus-agent"}/bin/sidebus-agent";
+ ImportCredential = "sidebus.*";
+ };
+ documentation = [ "https://git.clan.lol/valpackett/sidebus" ];
+ };
+ systemd.mounts = [
+ {
+ type = "virtiofs";
+ what = "vm-doc-portal";
+ where = "/run/vm-doc-portal";
+ wantedBy = [ "multi-user.target" ];
+ }
+ ];
+ };
+ }
+ );
}
diff --git a/nixosModules/sidebus-vm.nix b/nixosModules/sidebus-vm.nix
deleted file mode 100644
index 215d2b1..0000000
--- a/nixosModules/sidebus-vm.nix
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- environment.sessionVariables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/sidebus.sock";
- systemd.sockets.sidebus-agent = {
- # SocketMode= is 0666 by default
- listenStreams = [ "/run/sidebus.sock" ];
- wantedBy = [ "sockets.target" ];
- documentation = [ "https://git.clan.lol/valpackett/sidebus" ];
- };
- systemd.services.sidebus-agent = {
- # TODO: confinement (can do a lot)
- serviceConfig = {
- ExecStart = throw "sidebus-vm module requires setting systemd.services.sidebus-agent.serviceConfig.ExecStart to a sidebus-agent package";
- ImportCredential = "sidebus.*";
- };
- documentation = [ "https://git.clan.lol/valpackett/sidebus" ];
- };
- systemd.mounts = [
- {
- type = "virtiofs";
- what = "vm-doc-portal";
- where = "/run/vm-doc-portal";
- wantedBy = [ "multi-user.target" ];
- }
- ];
-}
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000..a1de405
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,3 @@
+[toolchain]
+channel = "1.88.0"
+components = ["rust-analyzer", "rust-src", "clippy"]
diff --git a/sidebus-agent/src/main.rs b/sidebus-agent/src/main.rs
index 650cde3..984a59f 100644
--- a/sidebus-agent/src/main.rs
+++ b/sidebus-agent/src/main.rs
@@ -1,3 +1,5 @@
+use eyre::OptionExt;
+use tokio::net::UnixListener;
use tracing::info;
#[tokio::main]
@@ -8,23 +10,38 @@ async fn main() -> eyre::Result<()> {
let vsock_port = std::fs::read_to_string(creds_dir.join("sidebus.port"))?
.trim()
.parse::()?;
- let vsock_addr = zbus::Address::from(zbus::address::Transport::Vsock(
- zbus::address::transport::Vsock::new(2, vsock_port),
- ));
- info!("connecting to session bus");
- let session_conn = zbus::connection::Builder::session()?.p2p().build().await?;
-
- let vsock_conn = zbus::connection::Builder::address(vsock_addr)?
- .server(session_conn.server_guid())
- .unwrap()
- .p2p()
- .auth_mechanism(zbus::AuthMechanism::Anonymous)
- .build()
- .await
- .unwrap();
- info!(guid = %vsock_conn.server_guid(), "connected to vsock bus");
- sidebus_common::raw::splice_conns(vsock_conn, session_conn).await;
+ let unix_listener = UnixListener::from_std(
+ listenfd::ListenFd::from_env()
+ .take_unix_listener(0)?
+ .ok_or_eyre("no unix listener provided")?,
+ )?;
+ info!("listening for unix clients");
+ while let Ok((unix_client, client_addr)) = unix_listener.accept().await {
+ info!(?client_addr, "new unix client");
+ tokio::spawn(async move {
+ let vsock_addr = zbus::Address::from(zbus::address::Transport::Vsock(
+ zbus::address::transport::Vsock::new(2, vsock_port),
+ ));
+ let vsock_conn = zbus::connection::Builder::address(vsock_addr)
+ .unwrap()
+ .p2p()
+ .auth_mechanism(zbus::AuthMechanism::Anonymous)
+ .build()
+ .await
+ .unwrap();
+ info!(guid = %vsock_conn.server_guid(), "connected to vsock bus");
+ let client_conn = zbus::connection::Builder::unix_stream(unix_client)
+ .server(vsock_conn.server_guid())
+ .unwrap()
+ .p2p()
+ .auth_mechanism(zbus::AuthMechanism::External)
+ .build()
+ .await
+ .unwrap();
+ sidebus_common::raw::splice_conns(client_conn, vsock_conn).await;
+ });
+ }
Ok(())
}
diff --git a/sidebus-broker/Cargo.toml b/sidebus-broker/Cargo.toml
index 1cbde4d..3be80d9 100644
--- a/sidebus-broker/Cargo.toml
+++ b/sidebus-broker/Cargo.toml
@@ -18,4 +18,3 @@ rustix = { version = "1.0.8", features = ["fs"] }
url = "2.5.4"
rand = "0.9.2"
futures = "0.3.31"
-libc = "0.2.178"
diff --git a/sidebus-broker/src/bus.rs b/sidebus-broker/src/bus.rs
index b2fd94f..4607379 100644
--- a/sidebus-broker/src/bus.rs
+++ b/sidebus-broker/src/bus.rs
@@ -1,6 +1,6 @@
-use std::{hash::DefaultHasher, sync::Arc};
+use std::sync::Arc;
use tokio_stream::StreamExt as _;
-use tracing::{debug, error, trace};
+use tracing::{debug, trace};
pub struct HostedBus {
peers: Arc,
@@ -57,14 +57,10 @@ impl HostedBus {
.map_err(|err| eyre::eyre!(Box::new(err))) // https://github.com/eyre-rs/eyre/issues/31 XXX: busd should not use anyhow!
}
- pub async fn connect_unix(
- &mut self,
- socket: tokio::net::UnixStream,
- auth: zbus::AuthMechanism,
- ) -> eyre::Result<()> {
+ pub async fn connect_unix(&mut self, socket: tokio::net::UnixStream) -> eyre::Result<()> {
let id = self.next_id();
self.peers
- .add(&self.guid, id, socket.into(), auth)
+ .add(&self.guid, id, socket.into(), zbus::AuthMechanism::External)
.await
.map_err(|err| eyre::eyre!(Box::new(err)))
}
@@ -81,7 +77,7 @@ impl HostedBus {
}
pub trait SharedHostedBus {
- async fn run_unix_listener(self, listener: tokio::net::UnixListener, auth: zbus::AuthMechanism);
+ async fn run_unix_listener(self, listener: tokio::net::UnixListener);
async fn spawn_external_client(
self,
command: &mut tokio::process::Command,
@@ -89,15 +85,9 @@ pub trait SharedHostedBus {
}
impl SharedHostedBus for Arc> {
- async fn run_unix_listener(
- self,
- listener: tokio::net::UnixListener,
- auth: zbus::AuthMechanism,
- ) {
+ async fn run_unix_listener(self, listener: tokio::net::UnixListener) {
while let Ok((socket, _remote_addr)) = listener.accept().await {
- if let Err(e) = self.lock().await.connect_unix(socket, auth).await {
- error!("unix connection: {:?}", e);
- }
+ self.lock().await.connect_unix(socket).await.unwrap()
}
}
@@ -110,7 +100,7 @@ impl SharedHostedBus for Arc> {
let abstract_path = format!("/run/sidebus-broker/{}", zbus::Guid::generate());
let listener = tokio::net::UnixListener::bind(format!("\0{abstract_path}"))?;
debug!(%abstract_path, "opened listener for external client");
- tokio::spawn(self.run_unix_listener(listener, zbus::AuthMechanism::External));
+ tokio::spawn(self.run_unix_listener(listener));
Ok(command
.env(
"DBUS_SESSION_BUS_ADDRESS",
diff --git a/sidebus-broker/src/main.rs b/sidebus-broker/src/main.rs
index aad976b..7a2247d 100644
--- a/sidebus-broker/src/main.rs
+++ b/sidebus-broker/src/main.rs
@@ -4,12 +4,9 @@ mod vsock;
use bus::SharedHostedBus;
use clap::Parser;
-use eyre::OptionExt;
-use futures::{TryFutureExt, stream::FuturesUnordered};
-use std::{path::PathBuf, sync::Arc, time::Duration};
+use std::{path::PathBuf, sync::Arc};
use tokio::{net::UnixListener, process::Command, sync::Mutex};
-use tokio_stream::StreamExt as _;
-use tracing::{Instrument, debug, error, info_span};
+use tracing::error;
use zbus::names::WellKnownName;
// https://github.com/rust-lang/rfcs/issues/2407#issuecomment-385291238
@@ -25,7 +22,7 @@ macro_rules! enclose {
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct BrokerCli {
- /// Create unix socket listeners for internal busses in the provided directory
+ /// Create unix socket listeners for all internal busses in the provided directory
#[clap(long)]
debug_access: Option,
@@ -37,29 +34,9 @@ struct BrokerCli {
#[clap(long, default_value = "/run/vm-doc-portal")]
guest_mountpoint: PathBuf,
- /// Mappings from guest paths to host paths for passthrough file systems (for file transfer), in guest=host format
+ /// Vsock port number to listen on
#[clap(long)]
- path_mapping: Vec,
-
- /// Vsock port number to listen on for the VM bus
- #[clap(long)]
- vsock_port: Option,
-
- /// Unix socket path to listen on for the VM bus
- #[clap(long)]
- unix_path: Option,
-
- /// Use ANONYMOUS auth to connect to the guest bus instead of EXTERNAL with the provided --guest-uid
- #[clap(long)]
- guest_bus_anonymous_auth: bool,
-
- /// The user ID for the appvm user inside of the guest
- #[clap(long, default_value = "1337")]
- guest_uid: u32,
-
- /// The group ID for the appvm group inside of the guest
- #[clap(long, default_value = "1337")]
- guest_gid: u32,
+ vsock_port: u32,
}
async fn new_hosted_bus() -> eyre::Result<(
@@ -74,272 +51,110 @@ async fn new_hosted_bus() -> eyre::Result<(
Ok((Arc::new(Mutex::new(bus)), guid, owner_stream))
}
-fn parse_path_mapping(s: &str) -> eyre::Result<(PathBuf, PathBuf)> {
- let mut split = s.split('=');
- let guest_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?);
- let host_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?);
- Ok((guest_path, host_path))
-}
-
#[tokio::main]
async fn main() -> eyre::Result<()> {
tracing_subscriber::fmt::init();
let cli = BrokerCli::parse();
- let mut path_prefix_to_host: Vec<(PathBuf, PathBuf)> = cli
- .path_mapping
- .iter()
- .flat_map(|arg| match parse_path_mapping(arg) {
- Ok(mapping) => Some(mapping),
- Err(err) => {
- error!(?err, %arg, "could not parse path mapping");
- None
- }
- })
- .collect();
- path_prefix_to_host.sort_unstable_by_key(|(prefix, _)| -(prefix.as_os_str().len() as isize));
- debug!(?path_prefix_to_host, "parsed path mappings");
+ let (vm_bus, vm_bus_guid, _) = new_hosted_bus().await?;
let (priv_bus, _, mut priv_lst) = new_hosted_bus().await?;
- let mut server_tasks = tokio::task::JoinSet::new();
- let mut child_procs = Vec::new();
-
if let Some(dir_path) = cli.debug_access {
if !dir_path.is_dir() {
error!(path = %dir_path.display(), "--debug-access path is not an existing directory");
std::process::exit(1);
}
+ let vm_dbg_listener = UnixListener::bind(dir_path.join("vm.sock"))?;
+ let _vm_dbg_task = tokio::spawn(vm_bus.clone().run_unix_listener(vm_dbg_listener));
let priv_dbg_listener = UnixListener::bind(dir_path.join("priv.sock"))?;
- server_tasks.spawn(
- priv_bus
- .clone()
- .run_unix_listener(priv_dbg_listener, zbus::AuthMechanism::External),
- );
+ let _priv_dbg_task = tokio::spawn(priv_bus.clone().run_unix_listener(priv_dbg_listener));
// TODO: unlink sockets on exit
}
std::fs::create_dir_all(&cli.runtime_dir)?;
- child_procs.push(
- priv_bus
- .clone()
- .spawn_external_client(
- Command::new(env!("BIN_XDG_PERMISSION_STORE"))
- .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
- .kill_on_drop(true),
- )
- .await?,
- );
+ let _xps = priv_bus
+ .clone()
+ .spawn_external_client(
+ Command::new(env!("BIN_XDG_PERMISSION_STORE"))
+ .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
+ .kill_on_drop(true),
+ )
+ .await?;
let impl_permission_store =
WellKnownName::from_static_str("org.freedesktop.impl.portal.PermissionStore")?.into();
priv_lst.wait_for_acquisition(impl_permission_store).await?;
- child_procs.push(
- priv_bus
- .clone()
- .spawn_external_client(
- Command::new(env!("BIN_XDG_DOCUMENT_PORTAL"))
- .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
- .kill_on_drop(true),
- )
- .await?,
- );
+ let _xdp = priv_bus
+ .clone()
+ .spawn_external_client(
+ Command::new(env!("BIN_XDG_DOCUMENT_PORTAL"))
+ .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
+ .kill_on_drop(true),
+ )
+ .await?;
let portal_documents =
WellKnownName::from_static_str("org.freedesktop.portal.Documents")?.into();
priv_lst.wait_for_acquisition(portal_documents).await?;
- child_procs.push(
- Command::new(env!("BIN_VIRTIOFSD"))
- .args(&[
- "--shared-dir",
- cli.runtime_dir.join("doc").to_str().unwrap(),
- "--socket-path",
- cli.runtime_dir.join("fs.sock").to_str().unwrap(),
- "--uid-map",
- &format!(":{}:{}:1:", cli.guest_uid, unsafe { libc::getuid() }),
- "--gid-map",
- &format!(":{}:{}:1:", cli.guest_gid, unsafe { libc::getgid() }),
- "--log-level",
- "debug",
- ])
- .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
- .kill_on_drop(true)
- .spawn()?,
- );
+ let _vfs = Command::new(env!("BIN_VIRTIOFSD"))
+ .args(&[
+ "--shared-dir",
+ cli.runtime_dir.join("doc").to_str().unwrap(),
+ "--socket-path",
+ cli.runtime_dir.join("fs.sock").to_str().unwrap(),
+ "--uid-map",
+ ":1000:1001:1:",
+ "--gid-map",
+ ":100:100:1:",
+ "--log-level",
+ "debug",
+ ])
+ .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str())
+ .kill_on_drop(true)
+ .spawn();
+ // TODO: die when it exits
+ let vm_bus_conn = vm_bus.lock().await.connect_channel(false).await?;
let priv_bus_conn = priv_bus.lock().await.connect_channel(false).await?;
let host_session_conn = zbus::connection::Builder::session()?.build().await?;
let file_chooser_imp = portal::file_chooser::FileChooser::new(
- &host_session_conn,
- &priv_bus_conn,
- cli.guest_mountpoint.clone(),
- )
- .await?;
- let file_transfer_imp = portal::file_transfer::FileTransfer::new(
&host_session_conn,
&priv_bus_conn,
cli.guest_mountpoint,
- path_prefix_to_host,
)
.await?;
- let notification_imp = portal::notification::Notification::new(&host_session_conn).await?;
- let print_imp = portal::print::Print::new(&host_session_conn).await?;
- let settings_imp = portal::settings::Settings::new(&host_session_conn).await?;
-
- async fn on_vm_bus_connected(
- vm_bus_conn: zbus::Connection,
- file_chooser: portal::file_chooser::FileChooser,
- file_transfer: portal::file_transfer::FileTransfer,
- notification: portal::notification::Notification,
- print: portal::print::Print,
- settings: portal::settings::Settings,
- ) -> Result<(), eyre::Report> {
- if !vm_bus_conn
- .object_server()
- .at("/org/freedesktop/portal/desktop", file_chooser)
- .await?
- {
- error!("org.freedesktop.portal.FileChooser already provided");
- };
-
- if !vm_bus_conn
- .object_server()
- .at("/org/freedesktop/portal/documents", file_transfer)
- .await?
- {
- error!("org.freedesktop.portal.FileTransfer already provided");
- };
- let file_transfer_ref = vm_bus_conn
- .object_server()
- .interface::<_, portal::file_transfer::FileTransfer>(
- "/org/freedesktop/portal/documents",
- )
- .await?;
- tokio::spawn(async move {
- let file_transfer = file_transfer_ref.get().await;
- let emitter = file_transfer_ref.signal_emitter();
- if let Err(err) = file_transfer.forward_transfer_closed(emitter.clone()).await {
- error!(%err, "forwarding forward_transfer_closed changes ended");
- }
- });
-
- if !vm_bus_conn
- .object_server()
- .at("/org/freedesktop/portal/desktop", notification)
- .await?
- {
- error!("org.freedesktop.portal.Notification already provided");
- };
- let notification_ref = vm_bus_conn
- .object_server()
- .interface::<_, portal::notification::Notification>("/org/freedesktop/portal/desktop")
- .await?;
- tokio::spawn(async move {
- let notification = notification_ref.get().await;
- let emitter = notification_ref.signal_emitter();
- if let Err(err) = notification.forward_actions(emitter.clone()).await {
- error!(%err, "forwarding notification changes ended");
- }
- });
-
- if !vm_bus_conn
- .object_server()
- .at("/org/freedesktop/portal/desktop", print)
- .await?
- {
- error!("org.freedesktop.portal.Print already provided");
- };
-
- if !vm_bus_conn
- .object_server()
- .at("/org/freedesktop/portal/desktop", settings)
- .await?
- {
- error!("org.freedesktop.portal.Settings already provided");
- };
- let settings_ref = vm_bus_conn
- .object_server()
- .interface::<_, portal::settings::Settings>("/org/freedesktop/portal/desktop")
- .await?;
- tokio::spawn(async move {
- let settings = settings_ref.get().await;
- let emitter = settings_ref.signal_emitter();
- if let Err(err) = settings.forward_changes(emitter).await {
- error!(%err, "forwarding settings changes ended");
- }
- });
-
- // XXX: no method for "wait until the conn dies"?
- Ok(std::future::pending::<()>().await)
- }
-
- if let Some(path) = cli.unix_path {
- let vm_unix_listener = UnixListener::bind(path)?;
- server_tasks.spawn(enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
- while let Ok((socket, remote_addr)) = vm_unix_listener.accept().await {
- let f = enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
- let client_conn = if cli.guest_bus_anonymous_auth {
- zbus::connection::Builder::unix_stream(socket).auth_mechanism(zbus::AuthMechanism::Anonymous)
- } else {
- zbus::connection::Builder::unix_stream(socket).user_id(cli.guest_uid)
- }
- .name("org.freedesktop.portal.Desktop")?
- .name("org.freedesktop.portal.Documents")?
- .build()
- .await?;
- on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await
- });
- tokio::spawn(
- async {
- match f.await {
- Ok(()) => debug!("done with server"),
- Err(err) => error!(%err, "error dealing with server"),
- }
- }
- .instrument(info_span!("serve", ?remote_addr)),
- );
- }
- }));
- }
-
- if let Some(port) = cli.vsock_port {
- // TODO: modprobe vhost_vsock first!
- server_tasks.spawn(
- vsock::ListenerBuilder::new(vsock::VsockAddr::new(vsock::VMADDR_CID_HOST, port))
- .with_label("VM Bus")
- .listen(move |client| {
- enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move {
- // TODO: Not necessary to go through the channel, add vsock support to the Peer too?
- let client_conn = client.build().await?;
- on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await
- })
- })
- .map_ok_or_else(
- |e| {
- error!("vsock listener: {:?}", e);
- },
- |()| (),
- ),
- );
- }
-
- let mut waiter = child_procs
- .iter_mut()
- .map(|child| child.wait())
- .collect::>();
- tokio::select! {
- _ = server_tasks.join_all() => debug!("server tasks ended"),
- res = waiter.next() => debug!(?res, "child process terminated"),
- _ = tokio::signal::ctrl_c() => debug!("interrupt signal"),
+ vm_bus_conn
+ .request_name("org.freedesktop.portal.Desktop")
+ .await?;
+ let true = vm_bus_conn
+ .object_server()
+ .at("/org/freedesktop/portal/desktop", file_chooser_imp)
+ .await?
+ else {
+ unreachable!("our own fresh bus can't have interfaces already provided");
};
- drop(waiter);
- for mut child in child_procs {
- if let Err(e) = child.kill().await {
- error!(?e, "could not kill process");
- }
- }
+
+ // TODO: modprobe vhost_vsock first!
+ // NOTE: Every individual D-Bus client inside of the VM is a new client here!
+ vsock::ListenerBuilder::new(vsock::VsockAddr::new(
+ vsock::VMADDR_CID_HOST,
+ cli.vsock_port,
+ ))
+ .with_label("VM Bus")
+ .listen(move |client| {
+ enclose! { (vm_bus, vm_bus_guid) async move {
+ // TODO: Not necessary to go through the channel, add vsock support to the Peer too
+ let client_conn = client.build((&vm_bus_guid).into()).await?;
+ let vmbus_conn = vm_bus.lock().await.connect_channel(true).await?;
+ sidebus_common::raw::splice_conns(client_conn, vmbus_conn).await;
+ Ok(())
+ } }
+ })
+ .await?;
+
Ok(())
}
diff --git a/sidebus-broker/src/portal/file_chooser.rs b/sidebus-broker/src/portal/file_chooser.rs
index 6121da8..b3a0ff9 100644
--- a/sidebus-broker/src/portal/file_chooser.rs
+++ b/sidebus-broker/src/portal/file_chooser.rs
@@ -8,7 +8,6 @@ use zbus::{Connection, ObjectServer, fdo::Result, zvariant};
use super::documents::DocumentsProxy;
use super::request::{RESPONSE_SUCCESS, ReqHandler, ResultTransformer};
-#[derive(Clone)]
pub struct FileChooser {
host: FileChooserProxy<'static>,
docs: DocumentsProxy<'static>,
@@ -53,7 +52,6 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: false,
- persistent: true,
directory: options.get_as("directory")?.unwrap_or(false),
})
.perform(async || self.host.open_file(parent_window, title, options).await)
@@ -74,7 +72,6 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: true,
- persistent: true,
directory: false,
})
.perform(async || self.host.save_file(parent_window, title, options).await)
@@ -95,7 +92,6 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: true,
- persistent: true,
directory: false,
})
.perform(async || self.host.save_files(parent_window, title, options).await)
@@ -109,13 +105,11 @@ impl FileChooser {
}
}
-#[derive(Clone)]
-pub struct FileTransformer {
- pub docs: DocumentsProxy<'static>,
- pub guest_root: PathBuf,
- pub for_save: bool,
- pub persistent: bool,
- pub directory: bool,
+struct FileTransformer {
+ docs: DocumentsProxy<'static>,
+ guest_root: PathBuf,
+ for_save: bool,
+ directory: bool,
}
// ref: send_response_in_thread_func
@@ -139,14 +133,6 @@ impl ResultTransformer for FileTransformer {
.async_map(|u| self.add_path_as_doc(u))
.await
.flatten()
- .map(|path| match url::Url::from_file_path(&path) {
- Ok(url) => Some(url.to_string()),
- Err(err) => {
- warn!(?err, ?path, "could not make url from returned path");
- None
- }
- })
- .flatten()
.collect::>();
results.insert("uris", guest_uris.into());
@@ -163,7 +149,7 @@ const DIRECTORY: u32 = 1 << 3;
// https://github.com/flatpak/xdg-desktop-portal/blob/10e712e06aa8eb9cd0e59c73c5be62ba53e981a4/src/xdp-documents.c#L71
impl FileTransformer {
- pub async fn add_path_as_doc(&self, path: PathBuf) -> Option {
+ async fn add_path_as_doc(&self, path: PathBuf) -> Option {
use rustix::fs::{Mode, OFlags};
let o_path_fd = match rustix::fs::open(
@@ -179,8 +165,8 @@ impl FileTransformer {
};
let flags = REUSE_EXISTING
+ | PERSISTENT
| AS_NEEDED_BY_APP
- | if self.persistent { PERSISTENT } else { 0 }
| if self.directory { DIRECTORY } else { 0 };
// XXX: portal impl can return writable=false but host frontend does not pass that back..
@@ -225,7 +211,14 @@ impl FileTransformer {
return None;
}
};
- Some(self.guest_root.join(doc_id).join(filename))
+ let path = self.guest_root.join(doc_id).join(filename);
+ match url::Url::from_file_path(&path) {
+ Ok(url) => Some(url.to_string()),
+ Err(err) => {
+ warn!(?err, ?path, "could not make url from returned path");
+ None
+ }
+ }
}
}
diff --git a/sidebus-broker/src/portal/file_transfer.rs b/sidebus-broker/src/portal/file_transfer.rs
deleted file mode 100644
index 8c175f6..0000000
--- a/sidebus-broker/src/portal/file_transfer.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-use std::{
- collections::HashMap,
- os::fd::{AsFd, AsRawFd},
- os::unix::ffi::OsStrExt,
- path::PathBuf,
-};
-
-use tokio::sync::broadcast;
-use tokio_stream::StreamExt;
-use tracing::{debug, error};
-use zbus::{
- Connection, fdo::Result, names::OwnedUniqueName, object_server::SignalEmitter, zvariant,
-};
-
-use super::{documents::DocumentsProxy, file_chooser::FileTransformer};
-
-#[derive(Clone)]
-pub struct FileTransfer {
- host: FileTransferProxy<'static>,
- file_transformer: FileTransformer,
- tx: broadcast::Sender,
- path_prefix_to_host: Vec<(PathBuf, PathBuf)>,
-}
-
-#[derive(Clone, Debug)]
-enum ForwarderCommand {
- Add(String, OwnedUniqueName),
- // Remove(String),
-}
-
-#[zbus::interface(
- name = "org.freedesktop.portal.FileTransfer",
- proxy(
- default_service = "org.freedesktop.portal.Documents",
- default_path = "/org/freedesktop/portal/documents"
- )
-)]
-impl FileTransfer {
- async fn add_files(
- &self,
- key: &str,
- fds: Vec>,
- options: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result<()> {
- let mut host_paths = Vec::with_capacity(fds.len());
- for fd in fds.iter() {
- let link = rustix::fs::readlink(
- format!("/proc/self/fd/{}", fd.as_fd().as_raw_fd()),
- Vec::new(),
- )
- .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
- let guest_path = std::path::PathBuf::from(std::ffi::OsStr::from_bytes(
- &link.to_string_lossy().as_bytes(),
- ));
- let (prefix, host_prefix) = self
- .path_prefix_to_host
- .iter()
- .find(|(prefix, _)| guest_path.starts_with(prefix))
- .ok_or_else(|| {
- zbus::fdo::Error::Failed("Could not find host mapping for path".to_owned())
- })?;
- let guest_suffix = guest_path
- .strip_prefix(prefix)
- .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
- let host_path = if guest_suffix.as_os_str().is_empty() {
- // Edge case: a bind-mounted file exposed at the same path would get an extra '/' after its path
- host_prefix.to_path_buf()
- } else {
- host_prefix.join(guest_suffix)
- };
- debug!(
- ?guest_path,
- ?prefix,
- ?guest_suffix,
- ?host_prefix,
- ?host_path,
- "mapped path"
- );
- let path_fd = rustix::fs::open(
- host_path,
- rustix::fs::OFlags::PATH,
- rustix::fs::Mode::empty(),
- )
- .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?;
- host_paths.push(path_fd.into()); // OwnedFd variant of zbus's Fd enum, so still owned by the Vec
- }
- self.host.add_files(key, host_paths, options).await
- }
-
- async fn retrieve_files(
- &self,
- key: &str,
- options: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result> {
- let host_paths = self.host.retrieve_files(key, options).await?;
- let mut result = Vec::with_capacity(host_paths.len());
- for host_path in host_paths {
- if let Some(guest_path) = self
- .file_transformer
- .add_path_as_doc(PathBuf::from(&host_path))
- .await
- {
- result.push(guest_path.to_string_lossy().into_owned());
- } else {
- debug!(%host_path, "could not add path as doc to retrieve file");
- }
- }
- Ok(result)
- }
-
- async fn start_transfer(
- &self,
- #[zbus(header)] hdr: zbus::message::Header<'_>,
- options: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result {
- let sender = hdr
- .sender()
- .ok_or_else(|| zbus::Error::MissingField)?
- .to_owned();
- let key = self.host.start_transfer(options).await?;
- debug!(%key, %sender, "started transfer");
- if let Err(err) = self
- .tx
- .send(ForwarderCommand::Add(key.clone(), sender.into()))
- {
- error!(?err, "file_transfer internal channel error");
- return Err(zbus::fdo::Error::IOError("channel error".to_owned()));
- }
- Ok(key)
- }
-
- async fn stop_transfer(&self, key: &str) -> Result<()> {
- debug!(%key, "stopping transfer");
- self.host.stop_transfer(key).await
- }
-
- #[zbus(signal)]
- async fn transfer_closed(signal_emitter: &SignalEmitter<'_>, key: &str) -> zbus::Result<()>;
-
- #[zbus(property, name = "version")]
- fn version(&self) -> Result {
- Ok(1)
- }
-}
-
-impl FileTransfer {
- pub async fn new(
- host_session_conn: &Connection,
- priv_conn: &Connection,
- guest_root: PathBuf,
- path_prefix_to_host: Vec<(PathBuf, PathBuf)>,
- ) -> Result {
- let host = FileTransferProxy::builder(host_session_conn)
- .build()
- .await?;
- let docs = DocumentsProxy::builder(priv_conn).build().await?;
- let file_transformer = FileTransformer {
- docs,
- guest_root,
- for_save: false,
- persistent: false,
- directory: false,
- };
- let (tx, _) = broadcast::channel(8);
- Ok(FileTransfer {
- host,
- file_transformer,
- tx,
- path_prefix_to_host,
- })
- }
-
- pub async fn forward_transfer_closed(
- &self,
- mut signal_emitter: SignalEmitter<'static>,
- ) -> Result<()> {
- let mut stream = self.host.receive_transfer_closed().await?;
- let mut cmds = self.tx.subscribe();
- let mut receivers = HashMap::new();
-
- loop {
- tokio::select! {
- Ok(cmd) = cmds.recv() => match cmd {
- ForwarderCommand::Add(key, receiver) => { receivers.insert(key, receiver); },
- // ForwarderCommand::Remove(key) => { receivers.remove(&key); },
- },
- Some(signal) = stream.next() => {
- debug!(?signal, "transfer closed");
- if let Ok((key,)) = signal.0.deserialize::<(&str,)>() {
- if let Some(bus_name) = receivers.remove(key) {
- signal_emitter = signal_emitter.set_destination(zbus::names::BusName::Unique(bus_name.clone().into()));
- if let Err(err) = FileTransfer::transfer_closed(&signal_emitter, key).await {
- error!(?err, %key, "could not forward signal");
- }
- } else {
- error!(%key, "got a signal for unknown key");
- }
- } else {
- error!("could not deserialize transfer closed signal");
- };
- }
- }
- }
- }
-}
diff --git a/sidebus-broker/src/portal/mod.rs b/sidebus-broker/src/portal/mod.rs
index d43de89..69aa6be 100644
--- a/sidebus-broker/src/portal/mod.rs
+++ b/sidebus-broker/src/portal/mod.rs
@@ -1,7 +1,3 @@
pub mod documents;
pub mod file_chooser;
-pub mod file_transfer;
-pub mod notification;
-pub mod print;
pub mod request;
-pub mod settings;
diff --git a/sidebus-broker/src/portal/notification.rs b/sidebus-broker/src/portal/notification.rs
deleted file mode 100644
index 0d41850..0000000
--- a/sidebus-broker/src/portal/notification.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use std::collections::HashMap;
-
-use tokio_stream::StreamExt;
-use tracing::warn;
-use zbus::{Connection, fdo::Result, names::UniqueName, object_server::SignalEmitter, zvariant};
-
-#[derive(Clone)]
-pub struct Notification {
- host: NotificationProxy<'static>,
-}
-
-#[zbus::interface(
- name = "org.freedesktop.portal.Notification",
- proxy(
- default_service = "org.freedesktop.portal.Desktop",
- default_path = "/org/freedesktop/portal/desktop"
- )
-)]
-impl Notification {
- async fn add_notification(
- &self,
- #[zbus(header)] hdr: zbus::message::Header<'_>,
- id: &str,
- notification: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result<()> {
- let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?;
- self.host
- .add_notification(
- &format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}"),
- notification,
- )
- .await
- }
-
- async fn remove_notification(
- &self,
- #[zbus(header)] hdr: zbus::message::Header<'_>,
- id: &str,
- ) -> Result<()> {
- let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?;
- self.host
- .remove_notification(&format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}"))
- .await
- }
-
- #[zbus(signal)]
- async fn action_invoked(
- signal_emitter: &SignalEmitter<'_>,
- id: &str,
- action: &str,
- parameter: Vec>,
- ) -> zbus::Result<()>;
-
- #[zbus(property)]
- async fn supported_options(&self) -> Result> {
- self.host
- .supported_options()
- .await
- .map_err(|err| err.into())
- }
-
- #[zbus(property, name = "version")]
- fn version(&self) -> Result {
- Ok(2)
- }
-}
-
-impl Notification {
- pub async fn new(host_session_conn: &Connection) -> Result {
- let host = NotificationProxy::builder(host_session_conn)
- .build()
- .await?;
- Ok(Self { host })
- }
-
- pub async fn forward_actions(&self, mut signal_emitter: SignalEmitter<'static>) -> Result<()> {
- let mut stream = self.host.receive_action_invoked().await?;
- while let Some(x) = stream.next().await {
- let args = x.args()?;
- let mut split = args.id.split("\x0C\x0CSIDEBUS\x0C\x0C");
- let sender = split
- .next()
- .and_then(|x| UniqueName::try_from(x).ok().map(|x| x.to_owned()))
- .ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?;
- let id = split
- .next()
- .ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?;
- signal_emitter = signal_emitter.set_destination(sender.into());
- Notification::action_invoked(&signal_emitter, id, args.action, args.parameter).await?;
- ()
- }
- warn!("actions stream end");
- Ok(())
- }
-}
diff --git a/sidebus-broker/src/portal/print.rs b/sidebus-broker/src/portal/print.rs
deleted file mode 100644
index 7c77881..0000000
--- a/sidebus-broker/src/portal/print.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use std::collections::HashMap;
-
-use zbus::{Connection, ObjectServer, fdo::Result, zvariant};
-
-use super::request::ReqHandler;
-
-#[derive(Clone)]
-pub struct Print {
- host: PrintProxy<'static>,
-}
-
-#[zbus::interface(
- name = "org.freedesktop.portal.Print",
- proxy(
- default_service = "org.freedesktop.portal.Desktop",
- default_path = "/org/freedesktop/portal/desktop"
- )
-)]
-impl Print {
- async fn prepare_print(
- &self,
- #[zbus(header)] hdr: zbus::message::Header<'_>,
- #[zbus(object_server)] server: &ObjectServer,
- #[zbus(connection)] conn: &Connection,
- parent_window: &str,
- title: &str,
- settings: HashMap<&str, zvariant::Value<'_>>,
- page_setup: HashMap<&str, zvariant::Value<'_>>,
- options: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result {
- ReqHandler::prepare(&self.host, hdr, server, conn, &options)
- .perform(async || {
- self.host
- .prepare_print(parent_window, title, settings, page_setup, options)
- .await
- })
- .await
- }
-
- async fn print(
- &self,
- #[zbus(header)] hdr: zbus::message::Header<'_>,
- #[zbus(object_server)] server: &ObjectServer,
- #[zbus(connection)] conn: &Connection,
- parent_window: &str,
- title: &str,
- fd: zvariant::Fd<'_>,
- options: HashMap<&str, zvariant::Value<'_>>,
- ) -> Result {
- ReqHandler::prepare(&self.host, hdr, server, conn, &options)
- .perform(async || self.host.print(parent_window, title, fd, options).await)
- .await
- }
-
- #[zbus(property, name = "version")]
- fn version(&self) -> Result {
- Ok(3)
- }
-}
-
-impl Print {
- pub async fn new(host_session_conn: &Connection) -> Result {
- let host = PrintProxy::builder(host_session_conn).build().await?;
- Ok(Self { host })
- }
-}
diff --git a/sidebus-broker/src/portal/settings.rs b/sidebus-broker/src/portal/settings.rs
deleted file mode 100644
index de03b8b..0000000
--- a/sidebus-broker/src/portal/settings.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use std::collections::HashMap;
-
-use tokio_stream::StreamExt;
-use tracing::warn;
-use zbus::{Connection, fdo::Result, object_server::SignalEmitter, zvariant};
-
-#[derive(Clone)]
-pub struct Settings {
- host: SettingsProxy<'static>,
-}
-
-#[zbus::interface(
- name = "org.freedesktop.portal.Settings",
- proxy(
- default_service = "org.freedesktop.portal.Desktop",
- default_path = "/org/freedesktop/portal/desktop"
- )
-)]
-impl Settings {
- async fn read(&self, namespace: &str, key: &str) -> Result {
- self.host.read(namespace, key).await
- }
-
- async fn read_all(
- &self,
- namespaces: Vec<&str>,
- ) -> Result>> {
- self.host.read_all(namespaces).await
- }
-
- async fn read_one(&self, namespace: &str, key: &str) -> Result {
- self.host.read_one(namespace, key).await
- }
-
- /// SettingChanged signal
- #[zbus(signal)]
- async fn setting_changed(
- signal_emitter: &SignalEmitter<'_>,
- namespace: &str,
- key: &str,
- value: zvariant::Value<'_>,
- ) -> zbus::Result<()>;
-
- #[zbus(property, name = "version")]
- async fn version(&self) -> Result {
- Ok(2)
- }
-}
-
-impl Settings {
- pub(crate) async fn new(host_session_conn: &Connection) -> Result {
- let host = SettingsProxy::builder(host_session_conn).build().await?;
- Ok(Self { host })
- }
-
- pub async fn forward_changes(&self, signal_emitter: &SignalEmitter<'static>) -> Result<()> {
- let mut stream = self.host.receive_setting_changed().await?;
- while let Some(x) = stream.next().await {
- let args = x.args()?;
- Settings::setting_changed(signal_emitter, args.namespace, args.key, args.value).await?;
- ()
- }
- warn!("settings change stream end");
- Ok(())
- }
-}
diff --git a/sidebus-broker/src/vsock.rs b/sidebus-broker/src/vsock.rs
index 23d6c54..f3524a0 100644
--- a/sidebus-broker/src/vsock.rs
+++ b/sidebus-broker/src/vsock.rs
@@ -13,11 +13,12 @@ impl ConnectionBuilder {
&self.remote_addr
}
- pub async fn build<'a>(self) -> eyre::Result {
+ pub async fn build<'a>(self, guid: zbus::Guid<'a>) -> eyre::Result {
zbus::connection::Builder::vsock_stream(self.socket)
+ .server(guid)
+ .unwrap()
+ .p2p()
.auth_mechanism(zbus::AuthMechanism::Anonymous)
- .name("org.freedesktop.portal.Desktop")?
- .name("org.freedesktop.portal.Documents")?
.build()
.await
.map_err(|e| e.into())