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::{proxy::Proxy, Error, FilePath, Pid};
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<'a>(Proxy<'a>);
35
36impl<'a> Development<'a> {
37 /// Create a new instance of [`Development`]
38 pub async fn new() -> Result<Development<'a>, Error> {
39 let proxy = Proxy::new_flatpak_development("org.freedesktop.Flatpak.Development").await?;
40 Ok(Self(proxy))
41 }
42
43 /// Emitted when a process started by
44 /// [`host_command()`][`Development::host_command`] exits.
45 ///
46 /// # Specifications
47 ///
48 /// See also [`HostCommandExited`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-signal-org-freedesktop-Flatpak-Development.HostCommandExited).
49 #[doc(alias = "HostCommandExited")]
50 pub async fn receive_spawn_exited(&self) -> Result<impl Stream<Item = (u32, u32)>, Error> {
51 self.0.signal("HostCommandExited").await
52 }
53
54 /// This method lets trusted applications (insider or outside a sandbox) run
55 /// arbitrary commands in the user's session, outside any sandbox.
56 ///
57 /// # Arguments
58 ///
59 /// * `cwd_path` - The working directory for the new process.
60 /// * `argv` - The argv for the new process, starting with the executable to
61 /// launch.
62 /// * `fds` - Array of file descriptors to pass to the new process.
63 /// * `envs` - Array of variable/value pairs for the environment of the new
64 /// process.
65 /// * `flags`
66 ///
67 /// # Returns
68 ///
69 /// The PID of the new process.
70 ///
71 /// # Specifications
72 ///
73 /// See also [`HostCommand`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-method-org-freedesktop-Flatpak-Development.HostCommand).
74 pub async fn host_command(
75 &self,
76 cwd_path: impl AsRef<Path>,
77 argv: &[impl AsRef<Path>],
78 fds: HashMap<u32, impl AsFd>,
79 envs: HashMap<&str, &str>,
80 flags: BitFlags<HostCommandFlags>,
81 ) -> Result<u32, Error> {
82 let cwd_path = FilePath::new(cwd_path)?;
83 let argv = argv
84 .iter()
85 .map(FilePath::new)
86 .collect::<Result<Vec<FilePath>, _>>()?;
87 let fds: HashMap<u32, Fd> = fds.iter().map(|(k, val)| (*k, Fd::from(val))).collect();
88 self.0
89 .call("HostCommand", &(cwd_path, argv, fds, envs, flags))
90 .await
91 }
92
93 /// This methods let you send a Unix signal to a process that was started
94 /// [`host_command()`][`Development::host_command`].
95 ///
96 /// # Arguments
97 ///
98 /// * `pid` - The PID of the process to send the signal to.
99 /// * `signal` - The signal to send.
100 /// * `to_process_group` - Whether to send the signal to the process group.
101 ///
102 /// # Specifications
103 ///
104 /// See also [`HostCommandSignal`](https://docs.flatpak.org/en/latest/libflatpak-api-reference.html#gdbus-method-org-freedesktop-Flatpak-Development.HostCommandSignal).
105 #[doc(alias = "SpawnSignal")]
106 #[doc(alias = "xdp_portal_spawn_signal")]
107 pub async fn host_command_signal(
108 &self,
109 pid: Pid,
110 signal: u32,
111 to_process_group: bool,
112 ) -> Result<(), Error> {
113 self.0
114 .call("HostCommandSignal", &(pid, signal, to_process_group))
115 .await
116 }
117}
118
119impl<'a> std::ops::Deref for Development<'a> {
120 type Target = zbus::Proxy<'a>;
121
122 fn deref(&self) -> &Self::Target {
123 &self.0
124 }
125}