start_command/docker_init_option.rs
1//! Parse and validate the opt-in init process for docker isolation
2//! (issue #244):
3//!
4//! ```text
5//! --init run `docker run --init`, so Docker's bundled tini is PID 1
6//! and reaps orphaned processes
7//! --no-init keep the command as PID 1, overriding the environment default
8//! ```
9//!
10//! Without either flag, `START_COMMAND_DOCKER_INIT=1` turns it on for every
11//! docker launch on the host. The default stays off: a command that is its
12//! own supervisor keeps today's behaviour, and recovery works the same for
13//! containers started with or without it.
14
15use crate::args_parser::WrapperOptions;
16
17/// Environment variable holding the host-wide default.
18pub const DOCKER_INIT_ENV: &str = "START_COMMAND_DOCKER_INIT";
19
20/// Whether an environment value asks for an init process (1, true, yes, on).
21pub fn docker_init_from_env_value(value: Option<&str>) -> bool {
22 let value = value.unwrap_or("").trim().to_lowercase();
23 matches!(value.as_str(), "1" | "true" | "yes" | "on")
24}
25
26/// Parse `--init` / `--no-init`. Returns the number of arguments consumed.
27pub fn parse(args: &[String], index: usize, options: &mut WrapperOptions) -> usize {
28 match args[index].as_str() {
29 "--init" => {
30 options.init = Some(true);
31 1
32 }
33 "--no-init" => {
34 options.init = Some(false);
35 1
36 }
37 _ => 0,
38 }
39}
40
41/// Resolve `options.init` from the environment. See [`validate_with_env`].
42pub fn validate(options: &mut WrapperOptions) -> Result<(), String> {
43 validate_with_env(options, &|name| std::env::var(name).ok())
44}
45
46/// Resolve `options.init` to `Some(bool)`: the flag if one was given (`None`
47/// means none), otherwise the environment default for docker launches.
48/// Idempotent, because validation may run again on options it already
49/// resolved: `--no-init` (or a resolved `false`) without docker is the default
50/// anyway and is accepted.
51pub fn validate_with_env(
52 options: &mut WrapperOptions,
53 env: &dyn Fn(&str) -> Option<String>,
54) -> Result<(), String> {
55 let is_docker = options.isolated.as_deref() == Some("docker");
56 if options.init == Some(true) && !is_docker {
57 return Err("--init option is only valid with --isolated docker".to_string());
58 }
59 if options.init.is_none() {
60 options.init =
61 Some(is_docker && docker_init_from_env_value(env(DOCKER_INIT_ENV).as_deref()));
62 }
63 Ok(())
64}