Skip to main content

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}