1use crate::{
6 channel::Receiver,
7 child_reaper::{ChildReaper, RuntimeCall, StartedChild, WatchedExec},
8 config::Config,
9 conmon_capnp::conmon::CgroupManager,
10 container_io::{ContainerIO, Message},
11 container_log::ContainerLog,
12 fs_util::TempFile,
13 runtime_args::{ExecArgs, GenerateRuntimeArgs},
14 terminal::Terminal,
15};
16use anyhow::{Context, Result};
17use std::path::PathBuf;
18use tokio::time::Instant;
19
20pub(crate) struct ExecStart {
24 container_io: ContainerIO,
26
27 pidfile: TempFile,
31 args: ExecArgs,
32 runtime: PathBuf,
33}
34
35impl ExecStart {
36 pub(crate) fn new(
40 config: &Config,
41 id: &str,
42 tty: bool,
43 command: &[String],
44 cgroup_manager: CgroupManager,
45 pidfile_prefix: &str,
46 ) -> Result<Self> {
47 let container_io =
48 ContainerIO::new(tty, ContainerLog::new()).context("create container IO")?;
49 let pidfile = TempFile::new(Some(config.runtime_dir()), pidfile_prefix, ".pid");
50 let args = GenerateRuntimeArgs {
51 config,
52 id,
53 container_io: &container_io,
54 pidfile: pidfile.path(),
55 cgroup_manager,
56 }
57 .exec_args(command)
58 .context("generate exec args")?;
59 Ok(Self {
60 container_io,
61 pidfile,
62 args,
63 runtime: config.runtime().to_path_buf(),
64 })
65 }
66
67 pub(crate) fn collect_stdio(&self, stdout: bool, stderr: bool) -> Result<()> {
70 self.container_io.collect_stdio(stdout, stderr)
71 }
72
73 pub(crate) fn stdio(&self) -> Result<(Receiver<Message>, Receiver<Message>)> {
76 self.container_io.stdio()
77 }
78
79 pub(crate) fn terminal(&self) -> Option<&Terminal> {
82 self.container_io.terminal()
83 }
84
85 pub(crate) async fn run(
89 &mut self,
90 reaper: &ChildReaper,
91 stdin: bool,
92 deadline: Instant,
93 ) -> Result<StartedChild> {
94 let call = RuntimeCall {
95 command_start: Some(self.args.command_start),
96 stdin,
97 ..RuntimeCall::new(
98 &self.runtime,
99 &self.args.args,
100 self.pidfile.path(),
101 deadline,
102 )
103 };
104 reaper.create_child(call, &mut self.container_io).await
105 }
106
107 pub(crate) async fn runtime_error(&self, e: anyhow::Error) -> anyhow::Error {
110 self.container_io.runtime_error(e).await
111 }
112
113 pub(crate) fn watch(
117 self,
118 reaper: &ChildReaper,
119 id: Box<str>,
120 started: StartedChild,
121 timeout: Option<Instant>,
122 ) -> Result<WatchedExec> {
123 drop(self.pidfile);
125 reaper.watch_exec(id, started, timeout, self.container_io)
126 }
127}