ashpd/flatpak/development.rs
1//! The Development interface lets any client, possibly in a sandbox if it has
2//! access to the session helper, spawn a process on the host, outside any
3//! sandbox.
4
5use std::{collections::HashMap, os::fd::AsFd, path::Path};
6
7use enumflags2::{BitFlags, bitflags};
8use futures_util::Stream;
9use serde_repr::{Deserialize_repr, Serialize_repr};
10use zbus::zvariant::{Fd, Type};
11
12use crate::{Error, FilePath, Pid, proxy::Proxy};
13
14#[bitflags]
15#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Copy, Clone, Debug, Type)]
16#[repr(u32)]
17/// Flags affecting the running of commands on the host
18pub enum HostCommandFlags {
19 #[doc(alias = "FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV")]
20 /// Clear the environment.
21 ClearEnv,
22 #[doc(alias = "FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS")]
23 /// Kill the sandbox when the caller disappears from the session bus.
24 WatchBus,
25}
26
27/// The Development interface lets any client, possibly in a sandbox if it has
28/// access to the session helper, spawn a process on the host, outside any
29/// sandbox.
30///
31/// Wrapper of the DBus interface: [`org.freedesktop.Flatpak.Development`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-org.freedesktop.Flatpak.Development)
32#[derive(Debug)]
33#[doc(alias = "org.freedesktop.Flatpak.Development")]
34pub struct Development(Proxy<'static>);
35
36impl Development {
37 /// Create a new instance of [`Development`]
38 pub async fn new() -> Result<Self, Error> {
39 let proxy = Proxy::new_flatpak_development("org.freedesktop.Flatpak.Development").await?;
40 Ok(Self(proxy))
41 }
42
43 /// Create a new instance of [`Development`]
44 pub async fn with_connection(connection: zbus::Connection) -> Result<Self, Error> {
45 let proxy = Proxy::new_flatpak_development_with_connection(
46 connection,
47 "org.freedesktop.Flatpak.Development",
48 )
49 .await?;
50 Ok(Self(proxy))
51 }
52
53 /// Emitted when a process started by
54 /// [`host_command()`][`Development::host_command`] exits.
55 ///
56 /// # Specifications
57 ///
58 /// See also [`HostCommandExited`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-signal-org-freedesktop-Flatpak-Development.HostCommandExited).
59 #[doc(alias = "HostCommandExited")]
60 pub async fn receive_spawn_exited(&self) -> Result<impl Stream<Item = (u32, u32)>, Error> {
61 self.0.signal("HostCommandExited").await
62 }
63
64 /// This method lets trusted applications (insider or outside a sandbox) run
65 /// arbitrary commands in the user's session, outside any sandbox.
66 ///
67 /// # Arguments
68 ///
69 /// * `cwd_path` - The working directory for the new process.
70 /// * `argv` - The argv for the new process, starting with the executable to
71 /// launch.
72 /// * `fds` - Array of file descriptors to pass to the new process.
73 /// * `envs` - Array of variable/value pairs for the environment of the new
74 /// process.
75 /// * `flags`
76 ///
77 /// # Returns
78 ///
79 /// The PID of the new process.
80 ///
81 /// # Specifications
82 ///
83 /// See also [`HostCommand`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-method-org-freedesktop-Flatpak-Development.HostCommand).
84 pub async fn host_command(
85 &self,
86 cwd_path: impl AsRef<Path>,
87 argv: &[impl AsRef<Path>],
88 fds: HashMap<u32, impl AsFd>,
89 envs: HashMap<&str, &str>,
90 flags: BitFlags<HostCommandFlags>,
91 ) -> Result<u32, Error> {
92 let cwd_path = FilePath::new(cwd_path)?;
93 let argv = argv
94 .iter()
95 .map(FilePath::new)
96 .collect::<Result<Vec<FilePath>, _>>()?;
97 let fds: HashMap<u32, Fd> = fds.iter().map(|(k, val)| (*k, Fd::from(val))).collect();
98 self.0
99 .call("HostCommand", &(cwd_path, argv, fds, envs, flags))
100 .await
101 }
102
103 /// This methods let you send a Unix signal to a process that was started
104 /// [`host_command()`][`Development::host_command`].
105 ///
106 /// # Arguments
107 ///
108 /// * `pid` - The PID of the process to send the signal to.
109 /// * `signal` - The signal to send.
110 /// * `to_process_group` - Whether to send the signal to the process group.
111 ///
112 /// # Specifications
113 ///
114 /// See also [`HostCommandSignal`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-method-org-freedesktop-Flatpak-Development.HostCommandSignal).
115 #[doc(alias = "SpawnSignal")]
116 #[doc(alias = "xdp_portal_spawn_signal")]
117 pub async fn host_command_signal(
118 &self,
119 pid: Pid,
120 signal: u32,
121 to_process_group: bool,
122 ) -> Result<(), Error> {
123 self.0
124 .call("HostCommandSignal", &(pid, signal, to_process_group))
125 .await
126 }
127}
128
129impl std::ops::Deref for Development {
130 type Target = zbus::Proxy<'static>;
131
132 fn deref(&self) -> &Self::Target {
133 &self.0
134 }
135}