firecracker_rs_sdk/instance/
mod.rs

1#[cfg(any(feature = "_rt-std", feature = "_rt-async"))]
2use std::{path::Path, process::Child};
3use std::{path::PathBuf, process::Command};
4
5use crate::jailer::ChrootStrategy;
6#[cfg(any(feature = "_rt-std", feature = "_rt-async"))]
7use crate::{agent::SocketAgent, fstack::FStack, Error, Result};
8
9#[cfg(feature = "_rt-async")]
10mod rt_async;
11#[cfg(feature = "_rt-std")]
12mod rt_std;
13
14#[cfg(not(any(feature = "_rt-std", feature = "_rt-async")))]
15pub struct Instance {}
16
17#[cfg(not(any(feature = "_rt-std", feature = "_rt-async")))]
18impl Instance {
19    pub(crate) fn new(
20        _socket_on_host: PathBuf,
21        _jailer_workspace_dir: Option<PathBuf>,
22        _chroot_strategy: Option<ChrootStrategy>,
23        _remove_jailer_workspace_dir: Option<bool>,
24        _command: Command,
25        _exec_file_name: PathBuf,
26    ) -> Self {
27        crate::missing_rt_panic!()
28    }
29}
30
31#[cfg(any(feature = "_rt-std", feature = "_rt-async"))]
32pub struct Instance {
33    socket_on_host: PathBuf,
34
35    jailer_workspace_dir: Option<PathBuf>,
36
37    chroot_strategy: Option<ChrootStrategy>,
38
39    remove_jailer_workspace_dir: Option<bool>,
40
41    command: Command,
42
43    child: Option<Child>,
44
45    agent: Option<SocketAgent>,
46
47    fstack: FStack,
48
49    exec_file_name: PathBuf,
50
51    jailer_pid: Option<u32>,
52
53    firecracker_pid: Option<u32>,
54}
55
56#[cfg(any(feature = "_rt-std", feature = "_rt-async"))]
57impl Instance {
58    pub(crate) fn new(
59        socket_on_host: PathBuf,
60        jailer_workspace_dir: Option<PathBuf>,
61        chroot_strategy: Option<ChrootStrategy>,
62        remove_jailer_workspace_dir: Option<bool>,
63        command: Command,
64        exec_file_name: PathBuf,
65    ) -> Self {
66        Self {
67            socket_on_host,
68            jailer_workspace_dir,
69            chroot_strategy,
70            remove_jailer_workspace_dir,
71            command,
72            child: None,
73            agent: None,
74            fstack: FStack::new(),
75            exec_file_name,
76            jailer_pid: None,
77            firecracker_pid: None,
78        }
79    }
80
81    /// Returns jailer workspace directory (i.e. <chroot_base>/exec_file_name/<id>/root/).
82    ///
83    /// Always returns [`None`] if the instance is not spawned with `jailer` (bare `firecracker`).
84    pub fn jailer_workspace_dir(&self) -> Option<PathBuf> {
85        self.jailer_workspace_dir.clone()
86    }
87
88    /// Check whether this instance would remove jailer workspace directory
89    /// (i.e. <chroot_base>/exec_file_name/<id>/root/) when it's dropped.
90    ///
91    /// Always returns [`None`] if the instance is not spawned with `jailer` (bare `firecracker`).
92    pub fn remove_jailer_workspace_dir(&self) -> Option<bool> {
93        self.remove_jailer_workspace_dir
94    }
95
96    /// Returns `firecracker` PID of this instance.
97    pub fn firecracker_pid(&self) -> Option<u32> {
98        self.firecracker_pid
99    }
100
101    /// Returns `jailer` PID of this instance.
102    /// Note that since `jailer` would exit as soon as it completes its job, the PID returned
103    /// is usually without a corresponding running process.
104    pub fn jailer_pid(&self) -> Option<u32> {
105        self.jailer_pid
106    }
107
108    /// Returns the hard link inside the jailer corresponding to `path`.
109    /// # Example
110    /// ```rust,ignore,no_run
111    /// // This is the file that would be seen by other processes
112    /// let host_file = "/demo/foo/bar.txt";
113    /// // Let's assume that the jailer workspace directory is
114    /// let jailer_workspace_dir = "/srv/jailer/firecracker/test-instance/root";
115    ///
116    /// // Spawned with [`ChrootStrategy::NaiveLinkStrategy`]
117    /// let instance_1: Instance;
118    /// let jailed_link_1 = instance_1.jailed_link(host_file)?;
119    ///
120    /// // `host_file` and `jailed_link_1` are hard links pointing to the same INode.
121    /// assert_eq!(
122    ///     jailed_link_1,
123    ///     "/srv/jailer/firecracker/test-instance/root/bar.txt".into();
124    /// );
125    ///
126    /// // Spawned with [`ChrootStrategy::FullLinkStrategy`]
127    /// let instance_2: Instance;
128    /// let jailed_link_2 = instance_2.jailed_link(host_file)?;
129    /// // `host_file` and `jailed_link_2` are hard links pointing to the same INode.
130    /// assert_eq!(
131    ///     jailed_link_2,
132    ///     "/srv/jailer/firecracker/test-instance/root/demo/foo/bar.txt".into();
133    /// );
134    /// ```
135    pub fn jailed_link<P: AsRef<Path>>(&self, path: P) -> Result<PathBuf> {
136        match (&self.chroot_strategy, &self.jailer_workspace_dir) {
137            (Some(chroot_strategy), Some(jailer_workspace_dir)) => {
138                chroot_strategy.chroot_path(jailer_workspace_dir, path)
139            }
140            _ => Err(Error::Instance("Not using jailer".into())),
141        }
142    }
143}
144
145#[macro_export]
146macro_rules! check_agent_exists {
147    ($self:ident) => {{
148        if $self.agent.is_none() {
149            return Err(Error::Instance("No agent spawned".into()));
150        }
151        $self.agent.as_mut().unwrap()
152    }};
153}