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}