MCPcopy Create free account
hub / github.com/bootc-dev/bootc / build_command

Method build_command

crates/utils/src/chroot.rs:72–165  ·  view source on GitHub ↗

Build the underlying [`Command`] with the mount-namespace setup and chroot installed as a `pre_exec` hook.

(self, args: impl IntoIterator<Item = S>)

Source from the content-addressed store, hash-verified

70 /// Build the underlying [`Command`] with the mount-namespace
71 /// setup and chroot installed as a `pre_exec` hook.
72 fn build_command<S: AsRef<OsStr>>(self, args: impl IntoIterator<Item = S>) -> Result<Command> {
73 let mut args_iter = args.into_iter();
74 let program = args_iter
75 .next()
76 .context("ChrootCmd requires the program as the first arg")?;
77
78 // mount() requires its target directories to exist.
79 let proc_target = self.chroot_path.join("proc");
80 let dev_target = self.chroot_path.join("dev");
81 let sys_target = self.chroot_path.join("sys");
82 let run_target = self.chroot_path.join("run");
83 for p in [&proc_target, &dev_target, &sys_target, &run_target] {
84 create_dir_all(p).with_context(|| format!("Creating {p}"))?;
85 }
86
87 // Convert paths to CStrings up front so the pre_exec closure
88 // below stays allocation-free.
89 let proc_target = CString::new(proc_target.as_str())?;
90 let dev_target = CString::new(dev_target.as_str())?;
91 let sys_target = CString::new(sys_target.as_str())?;
92 let run_target = CString::new(run_target.as_str())?;
93
94 let user_binds: Vec<(CString, CString)> = self
95 .bind_mounts
96 .iter()
97 .map(|(src, tgt)| -> Result<_> {
98 let tgt_in_chroot = self.chroot_path.join(tgt.trim_start_matches('/'));
99 create_dir_all(&tgt_in_chroot)
100 .with_context(|| format!("Creating bind target {tgt_in_chroot}"))?;
101 Ok((CString::new(*src)?, CString::new(tgt_in_chroot.as_str())?))
102 })
103 .collect::<Result<_>>()?;
104
105 let chroot_cstr = CString::new(self.chroot_path.as_str())?;
106
107 let mut cmd = Command::new(program);
108 cmd.args(args_iter);
109 cmd.env_clear().envs(self.env_vars.iter().copied());
110
111 // SAFETY: All operations below are safe to invoke between
112 // fork and exec — only rustix-wrapped syscalls and iteration
113 // over CStrings allocated above.
114 #[allow(unsafe_code)]
115 unsafe {
116 cmd.pre_exec(move || {
117 unshare_unsafe(UnshareFlags::NEWNS)?;
118
119 // Recursively mark every mount in our new namespace as
120 // PRIVATE. This both prevents the mounts we add below
121 // from leaking back to the host, and ensures that those
122 // mounts inherit PRIVATE propagation from their parent.
123 mount_change(
124 c"/",
125 MountPropagationFlags::PRIVATE | MountPropagationFlags::REC,
126 )?;
127
128 // Bind-mount the chroot target onto itself so that `/`
129 // appears as a real mount point after chroot. Without

Callers 5

runMethod · 0.80
run_get_stringMethod · 0.80

Calls 5

mountFunction · 0.85
argsMethod · 0.80
into_iterMethod · 0.45
nextMethod · 0.45
iterMethod · 0.45