1use crate::{
4 config::{Config, LogLevel},
5 conmon_capnp::conmon::CgroupManager,
6 container_io::ContainerIO,
7};
8use anyhow::{Result, bail};
9use std::{fmt, path::Path};
10use tracing::debug;
11
12pub(crate) fn check_id(id: &str) -> Result<()> {
18 if id.is_empty() || id.starts_with('-') || id.chars().any(char::is_control) {
19 bail!("invalid container ID {id:?}")
20 }
21 Ok(())
22}
23
24#[derive(Clone, Copy)]
26pub(crate) struct GenerateRuntimeArgs<'a> {
27 pub(crate) config: &'a Config,
28 pub(crate) id: &'a str,
29 pub(crate) container_io: &'a ContainerIO,
30 pub(crate) pidfile: &'a Path,
31 pub(crate) cgroup_manager: CgroupManager,
32}
33
34impl GenerateRuntimeArgs<'_> {
35 const SYSTEMD_CGROUP_ARG: &'static str = "--systemd-cgroup";
36 const LOG_LEVEL_FLAG_CRUN: &'static str = "--log-level";
37
38 pub(crate) fn create_args(
47 &self,
48 bundle_path: &Path,
49 restore_path: Option<&Path>,
50 command_args: impl IntoIterator<Item = impl AsRef<str>>,
51 ) -> Result<Vec<String>> {
52 let mut args = Vec::with_capacity(16);
53 args.extend(self.default_args());
54
55 args.push(if restore_path.is_some() {
56 "restore".into()
57 } else {
58 "create".into()
59 });
60 args.push("--bundle".into());
61 args.push(bundle_path.display().to_string());
62 args.push("--pid-file".into());
63 args.push(self.pidfile.display().to_string());
64
65 if let Some(restore_path) = restore_path {
66 args.push("--detach".into());
67 args.push("--image-path".into());
68 args.push(restore_path.display().to_string());
69 args.push("--work-path".into());
70 args.push(bundle_path.display().to_string());
71 }
72
73 args.extend(command_args.into_iter().map(|arg| arg.as_ref().into()));
74
75 if let Some(terminal) = self.container_io.terminal() {
76 args.push(format!("--console-socket={}", terminal.path().display()));
77 }
78
79 args.push(self.checked_id()?.into());
80
81 debug!("Runtime args {args:?}");
82 Ok(args)
83 }
84
85 pub(crate) fn exec_args(
89 &self,
90 command: impl IntoIterator<Item = impl AsRef<str>>,
91 ) -> Result<ExecArgs> {
92 let mut args = Vec::with_capacity(12);
93 args.extend(self.default_args());
94
95 args.push("exec".into());
96 args.push("-d".into());
97
98 if let Some(terminal) = self.container_io.terminal() {
99 args.push(format!("--console-socket={}", terminal.path().display()));
100 args.push("--tty".into());
101 }
102
103 args.push(format!("--pid-file={}", self.pidfile.display()));
104 args.push("--".into());
108 args.push(self.checked_id()?.into());
109 let command_start = args.len();
110 args.extend(command.into_iter().map(|arg| arg.as_ref().into()));
111
112 Ok(ExecArgs {
113 args,
114 command_start,
115 })
116 }
117
118 fn checked_id(&self) -> Result<&str> {
121 check_id(self.id)?;
122 Ok(self.id)
123 }
124
125 fn default_args(&self) -> Vec<String> {
127 let mut args = vec![];
128
129 if self.config.runtime_is_crun() {
130 args.push(format!("--log=journald:{}", self.id));
131
132 let level = match self.config.log_level() {
135 LogLevel::Trace | LogLevel::Debug => Some("debug"),
136 LogLevel::Warn => Some("warning"),
137 LogLevel::Error => Some("error"),
138 LogLevel::Info | LogLevel::Off => None,
139 };
140 if let Some(level) = level {
141 args.push(format!("{}={level}", Self::LOG_LEVEL_FLAG_CRUN));
142 }
143 }
144
145 if let Some(rr) = self.config.runtime_root() {
146 args.push(format!("--root={}", rr.display()));
147 }
148
149 if self.cgroup_manager == CgroupManager::Systemd {
150 args.push(Self::SYSTEMD_CGROUP_ARG.into());
151 }
152
153 args
154 }
155}
156
157pub(crate) struct ExecArgs {
159 pub(crate) args: Vec<String>,
160
161 pub(crate) command_start: usize,
163}
164
165pub(crate) struct LoggedArgs<'a> {
169 pub(crate) args: &'a [String],
170
171 pub(crate) command_start: Option<usize>,
173}
174
175impl fmt::Debug for LoggedArgs<'_> {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 match self.command_start {
178 Some(start) => {
179 let (args, command) = self.args.split_at(start.min(self.args.len()));
180 write!(f, "{args:?} with {} command args", command.len())
181 }
182 None => write!(f, "{:?}", self.args),
183 }
184 }
185}
186
187#[cfg(test)]
188mod tests;