pub struct Container { /* private fields */ }Expand description
A Container is a configuration of how a process shall be spawned. It can,
but doesn’t have to, include Linux namespace configuration.
NOTE: Configuring resource limits via cgroups is not yet supported.
Implementations§
Source§impl Container
impl Container
Sourcepub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
Inserts or updates an environment variable mapping.
Note that environment variable names are case-insensitive (but case-preserving) on Windows, and case-sensitive on all other platforms.
§Examples
Basic usage:
use reverie_process::Container;
let container = Container::new().env("PATH", "/bin");Sourcepub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
Adds or updates multiple environment variable mappings.
§Examples
Basic usage:
use std::collections::HashMap;
use std::env;
use reverie_process::Container;
use reverie_process::Stdio;
let filtered_env: HashMap<String, String> = env::vars()
.filter(|&(ref k, _)| k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH")
.collect();
let container = Container::new()
.stdin(Stdio::null())
.stdout(Stdio::inherit())
.env_clear()
.envs(&filtered_env);Sourcepub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Self
pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Self
Removes an environment variable mapping.
§Examples
Basic usage:
use reverie_process::Container;
let container = Container::new().env_remove("PATH");Sourcepub fn env_clear(&mut self) -> &mut Self
pub fn env_clear(&mut self) -> &mut Self
Clears the entire environment map for the child process.
§Examples
Basic usage:
use reverie_process::Container;
let container = Container::new().env_clear();Sourcepub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self
Sets the working directory for the child process.
§Interaction with chroot
The working directory is set after the chroot is performed (if a chroot directory is specified). Thus, the path given is relative to the chroot directory. Otherwise, if no chroot directory is specified, the working directory is relative to the current working directory of the parent process at the time the child process is spawned.
§Platform-specific behavior
If the program path is relative (e.g., "./script.sh"), it’s ambiguous
whether it should be interpreted relative to the parent’s working
directory or relative to current_dir. The behavior in this case is
platform specific and unstable, and it’s recommended to use
canonicalize to get an absolute program path instead.
§Examples
Basic usage:
use reverie_process::Container;
let container = Container::new().current_dir("/bin");Sourcepub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
Sets configuration for the child process’s standard input (stdin) handle.
Defaults to Stdio::inherit when used with spawn or status, and
defaults to Stdio::piped when used with output.
§Examples
Basic usage:
use reverie_process::Container;
use reverie_process::Stdio;
let container = Container::new().stdin(Stdio::null());Sourcepub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
Sets configuration for the child process’s standard output (stdout) handle.
Defaults to Stdio::inherit when used with spawn or status, and
defaults to Stdio::piped when used with output.
§Examples
Basic usage:
use reverie_process::Container;
use reverie_process::Stdio;
let container = Container::new().stdout(Stdio::null());Sourcepub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self
Sets configuration for the child process’s standard error (stderr) handle.
Defaults to Stdio::inherit when used with spawn or status, and
defaults to Stdio::piped when used with output.
§Examples
Basic usage:
use reverie_process::Container;
use reverie_process::Stdio;
let container = Container::new().stderr(Stdio::null());Sourcepub fn chroot<P: AsRef<Path>>(&mut self, chroot: P) -> &mut Self
pub fn chroot<P: AsRef<Path>>(&mut self, chroot: P) -> &mut Self
Changes the root directory of the calling process to the specified path. This directory will be inherited by all child processes of the calling process.
Note that changing the root directory may cause the program to not be found. As such, the program path should be relative to this directory.
Unshares parts of the process execution context that are normally shared with the parent process. This is useful for executing the child process in a new namespace.
Sourcepub fn get_current_dir(&self) -> Option<&Path>
pub fn get_current_dir(&self) -> Option<&Path>
Returns the working directory for the child process.
This returns None if the working directory will not be changed.
Sourcepub fn get_envs(&self) -> impl Iterator<Item = (&OsStr, Option<&OsStr>)>
pub fn get_envs(&self) -> impl Iterator<Item = (&OsStr, Option<&OsStr>)>
Returns an iterator of the environment variables that will be set when the process is spawned. Note that this does not include any environment variables inherited from the parent process.
Sourcepub fn get_captured_envs(&self) -> BTreeMap<OsString, OsString>
pub fn get_captured_envs(&self) -> BTreeMap<OsString, OsString>
Returns a mapping of all environment variables that the new child process will inherit.
Sourcepub fn get_env<K: AsRef<OsStr>>(&self, env: K) -> Option<Cow<'_, OsStr>>
pub fn get_env<K: AsRef<OsStr>>(&self, env: K) -> Option<Cow<'_, OsStr>>
Gets an environment variable. If the child process is to inherit this environment variable from the current process, then this returns the current process’s environment variable unless it is to be overridden.
Sourcepub fn map_uid(&mut self, inside_uid: uid_t, outside_uid: uid_t) -> &mut Self
pub fn map_uid(&mut self, inside_uid: uid_t, outside_uid: uid_t) -> &mut Self
Maps one user ID to another.
Implies Namespace::USER.
§Example
This is can be used to gain CAP_SYS_ADMIN privileges in the user
namespace by mapping the root user inside the container to the current
user outside of the container.
use reverie_process::Container;
let container = Container::new().map_uid(1, unsafe { libc::getuid() });§Implementation
This modifies /proc/{pid}/uid_map where {pid} is the PID of the child
process. See user_namespaces(7) for more details.
Sourcepub fn map_uid_range(
&mut self,
starting_inside_uid: uid_t,
starting_outside_uid: uid_t,
count: u32,
) -> &mut Self
pub fn map_uid_range( &mut self, starting_inside_uid: uid_t, starting_outside_uid: uid_t, count: u32, ) -> &mut Self
Maps potentially many user IDs inside the new user namespace to user IDs outside of the user namespace.
Implies Namespace::USER.
§Implementation
This modifies /proc/{pid}/uid_map where {pid} is the PID of the child
process. See user_namespaces(7) for more details.
Sourcepub fn map_root(&mut self) -> &mut Self
pub fn map_root(&mut self) -> &mut Self
Convience function for mapping root (inside the container) to the current user ID (outside the container). This is useful for gaining new capabilities inside the container, such as being able to mount file systems.
Implies Namespace::USER.
This is the same as:
use reverie_process::Container;
let container = Container::new()
.map_uid(0, unsafe { libc::geteuid() })
.map_gid(0, unsafe { libc::getegid() });Sourcepub fn map_gid(&mut self, inside_gid: gid_t, outside_gid: gid_t) -> &mut Self
pub fn map_gid(&mut self, inside_gid: gid_t, outside_gid: gid_t) -> &mut Self
Maps one group ID to another.
Implies Namespace::USER.
§Implementation
This modifies /proc/{pid}/gid_map where {pid} is the PID of the child
process. See user_namespaces(7) for more details.
Sourcepub fn map_gid_range(
&mut self,
starting_inside_gid: gid_t,
starting_outside_gid: gid_t,
count: u32,
) -> &mut Self
pub fn map_gid_range( &mut self, starting_inside_gid: gid_t, starting_outside_gid: gid_t, count: u32, ) -> &mut Self
Maps potentially many group IDs inside the new user namespace to group IDs outside of the user namespace.
Implies Namespace::USER.
§Implementation
This modifies /proc/{pid}/gid_map where {pid} is the PID of the child
process. See user_namespaces(7) for more details.
Sourcepub fn hostname<S: Into<OsString>>(&mut self, hostname: S) -> &mut Self
pub fn hostname<S: Into<OsString>>(&mut self, hostname: S) -> &mut Self
Sets the hostname of the container.
Implies Namespace::UTS, which requires CAP_SYS_ADMIN.
use reverie_process::Container;
let container = Container::new().map_root().hostname("foobar.local");Sourcepub fn domainname<S: Into<OsString>>(&mut self, domainname: S) -> &mut Self
pub fn domainname<S: Into<OsString>>(&mut self, domainname: S) -> &mut Self
Sets the domain name of the container.
Implies Namespace::UTS, which requires CAP_SYS_ADMIN.
§Example
use reverie_process::Container;
let container = Container::new().map_root().domainname("foobar");Sourcepub fn get_hostname(&self) -> Option<&OsStr>
pub fn get_hostname(&self) -> Option<&OsStr>
Gets the hostname of the container.
Sourcepub fn get_domainname(&self) -> Option<&OsStr>
pub fn get_domainname(&self) -> Option<&OsStr>
Gets the domainname of the container.
Sourcepub fn mount(&mut self, mount: Mount) -> &mut Self
pub fn mount(&mut self, mount: Mount) -> &mut Self
Adds a file system to be mounted. Note that these are mounted in the same order as given.
Implies Namespace::MOUNT. Note that Namespace::USER should also have
been set and map_uid should have been called in order to gain the
privileges required to mount.
Sourcepub fn mounts<I>(&mut self, mounts: I) -> &mut Selfwhere
I: IntoIterator<Item = Mount>,
pub fn mounts<I>(&mut self, mounts: I) -> &mut Selfwhere
I: IntoIterator<Item = Mount>,
Adds multiple mounts.
Sourcepub fn local_networking_only(&mut self) -> &mut Self
pub fn local_networking_only(&mut self) -> &mut Self
Sets up the container to have local networking only. This will prevent any network communication to the outside world.
Implies Namespace::NETWORK and Namespace::MOUNT.
This also causes a fresh /sys to be mounted to avoid seeing the host
network interfaces in /sys/class/net.
Sourcepub fn seccomp(&mut self, filter: Filter) -> &mut Self
pub fn seccomp(&mut self, filter: Filter) -> &mut Self
Sets the seccomp filter. The filter is loaded immediately before execve
and after all pre_exec callbacks have been executed. Thus, you will
still be able to call filtered syscalls from pre_exec callbacks.
Sourcepub fn seccomp_notify(&mut self) -> &mut Self
pub fn seccomp_notify(&mut self) -> &mut Self
Indicates that we want to listen for seccomp events using seccomp_unotify(2).
If this is set, the seccomp listener file descriptor will be accessible
via the Child.
Sourcepub fn pty(&mut self, child: PtyChild) -> &mut Self
pub fn pty(&mut self, child: PtyChild) -> &mut Self
Sets the controlling pseudoterminal for the child process).
In the child process, this has the effect of:
- Creating a new session (with
setsid()). - Using an
ioctlto set the controlling terminal. - Setting this file descriptor as the stdio streams.
NOTE: Since this modifies the stdio streams, calling this will reset
Self::stdin, Self::stdout, and Self::stderr back to
Stdio::inherit().
Sourcepub fn affinity(&mut self, affinity: usize) -> &mut Self
pub fn affinity(&mut self, affinity: usize) -> &mut Self
Sets the CPU to which the child threads/processes will be pinned.
Sourcepub fn run<F, T>(&mut self, f: F) -> Result<T, RunError>
pub fn run<F, T>(&mut self, f: F) -> Result<T, RunError>
Runs a function in a new process with the specified namespaces unshared. This blocks until the function itself returns and the process has exited.
§Safety
-
This should be called early on in the life of a process, before any other threads are created. This reduces the chance that any global resources (like the Tokio runtime) have been created yet.
-
Memory allocated in the parent must not be freed in the child, especially if using jemalloc where a separate thread does deallocations.
Sourcepub fn run_with_startup<P, C, F, O, S, T, D>(
&mut self,
timeout: Duration,
parent_start: P,
child_start: C,
run: F,
) -> Result<(O, DeferredContainerRun<T>), StartupRunError>where
P: FnOnce(ParentStartContext<'_>) -> Result<O, StartupError>,
C: FnMut(&mut ChildStartContext) -> Result<S, StartupError>,
F: FnMut(S) -> (T, D),
T: Serialize + DeserializeOwned,
pub fn run_with_startup<P, C, F, O, S, T, D>(
&mut self,
timeout: Duration,
parent_start: P,
child_start: C,
run: F,
) -> Result<(O, DeferredContainerRun<T>), StartupRunError>where
P: FnOnce(ParentStartContext<'_>) -> Result<O, StartupError>,
C: FnMut(&mut ChildStartContext) -> Result<S, StartupError>,
F: FnMut(S) -> (T, D),
T: Serialize + DeserializeOwned,
Runs child setup and a parent readiness callback before installing the unchanged seccomp filter and entering the child workload.
child_start runs after namespace/filesystem setup, without creating a
helper task. It returns child-local state and may transfer up to
MAX_STARTUP_FDS owned descriptors through its context. parent_start
runs in the original process, with the actual owned child and received
descriptors, and must return only when its external resources are ready.
Its returned owner stays in the parent. Only then may run consume the
child state. Startup endpoint aliases close before seccomp is installed.
The positive, representable timeout gives the entire protocol one
monotonic I/O deadline, including time spent in callbacks. It does not
preempt arbitrary callback code or destructors. Failure cancels and
reaps the owned child; actual cleanup errors remain errors. Kernel waits
for an uninterruptible child still require outer process supervision.
Like Self::run, call this before starting other threads. No signal
handler or other thread may reap this child; SIGCHLD auto-reaping is
rejected before clone. Callbacks must obey the existing fork-safety
rules, close unrelated inherited descriptors, and not fork workers in
the child. This API does not prove capture completion or guest teardown.
Results are drained before wait, including large values. run returns
a deferred cleanup value just as Self::run_with_deferred_drop does;
the returned handle’s DeferredContainerRun::finalize_with_status
checks the real terminal status before yielding the value.
Sourcepub fn run_with_startup_owned<P, C, F, S, T, U>(
&mut self,
timeout: Duration,
parent_start: &mut P,
child_start: &mut C,
run: &mut F,
) -> Result<OwnedDeferredContainerRun<T>, StartupOwnedFailure<T>>where
P: FnMut(ParentStartContext<'_>) -> Result<(), StartupError>,
C: FnMut(&mut ChildStartContext) -> Result<S, StartupError>,
F: FnMut(S) -> (T, U),
T: Serialize,
pub fn run_with_startup_owned<P, C, F, S, T, U>(
&mut self,
timeout: Duration,
parent_start: &mut P,
child_start: &mut C,
run: &mut F,
) -> Result<OwnedDeferredContainerRun<T>, StartupOwnedFailure<T>>where
P: FnMut(ParentStartContext<'_>) -> Result<(), StartupError>,
C: FnMut(&mut ChildStartContext) -> Result<S, StartupError>,
F: FnMut(S) -> (T, U),
T: Serialize,
Runs the existing startup protocol with retained child/result ownership.
Call before starting threads; no handler or other thread may reap this
child. The callbacks are borrowed. Parent setup returns unit: retain
initialized parent resources outside this call and pair them with every
returned owner, including errors. This API cannot clean external state.
Child callbacks obey the same fork-safety and no-child-worker contract
as Self::run_with_startup. Namespace/filter/signal policy is unchanged.
Linux pidfd support is required and probed before clone. Startup uses one finite timeout, without preempting callbacks. Result acquisition then blocks draining the pipe before wait, with no workload deadline or value size cap. On read failure the same FD and partial bytes remain owned. Generic deserialization happens only after actual successful child wait. Explicit cleanup observation is bounded; implicit Drop can block and requires outer process supervision for uninterruptible/unknown cleanup.
Sourcepub fn run_with_deferred_drop_owned<F, T, D>(
&mut self,
run: &mut F,
) -> Result<OwnedDeferredContainerRun<T>, StartupOwnedFailure<T>>
pub fn run_with_deferred_drop_owned<F, T, D>( &mut self, run: &mut F, ) -> Result<OwnedDeferredContainerRun<T>, StartupOwnedFailure<T>>
Runs a deferred workload while retaining the original child/result owner.
This has the fork-safety requirements of Self::run: call before
starting threads, with no handler or other thread reaping this child.
The workload may create its own workers; it is not subject to the
startup callbacks’ no-child-worker contract. The borrowed factory and
any external parent resources must remain alive through every returned
owner, including errors. Ownership here covers the direct child, not
arbitrary descendants.
A normal raw-clone callback return exits only its calling thread. Join
worker threads before returning, or arrange an explicit group exit
(for example _exit in D) if those workers must end with the callback.
The child publishes and closes its encoded result before dropping D.
Linux pidfd support is required and probed before clone. After clone,
failures retain the original wait, reader and exact partial bytes, with
no implicit cleanup attempt. The workload may already have started
before such a failure is detected. Call the retained owner’s explicit
cancellation/observation methods with an absolute deadline; failed
results stay failed even when the child later exits successfully.
Atomic pidfd availability is validated after the initial drain: a real
read failure is reported first; otherwise missing identity is a protocol
refusal with complete encoded bytes and EOF retained.
Initial result acquisition blocks draining the pipe before wait, without a workload deadline or size cap. Explicit finalization bounds do not bound that acquisition or child serialization. Implicit owner Drop can block; callers requiring a hard bound need outer process supervision. Generic result decoding is available only after an actual successful child wait, including for an encoded container-setup refusal.
Sourcepub fn run_with_deferred_drop<F, T, D>(
&mut self,
f: F,
) -> Result<DeferredContainerRun<T>, RunError>
pub fn run_with_deferred_drop<F, T, D>( &mut self, f: F, ) -> Result<DeferredContainerRun<T>, RunError>
Runs a function in a new process, publishes its result, and only then drops a child-owned cleanup value.
The returned handle owns the mandatory wait for the child. Callers may
inspect the provisional value while doing independent work, but can
only take ownership of it through
DeferredContainerRun::finalize, which rejects an unsuccessful child
exit. Dropping the handle still reaps the child, but yields no value.
A caller therefore cannot accidentally destructure the value away from the mandatory cleanup check:
use reverie_process::Container;
let (value, cleanup) = Container::new()
.run_with_deferred_drop(|| (42, ()))
.unwrap();This has the same fork-safety requirements as Container::run.