Skip to content

Commit

Permalink
libcontainer: support set stdio for container
Browse files Browse the repository at this point in the history
currently the container can only inherit stdios from it's parent
process, the one who create container with libcontainer can not set
stdios to a different file.

Signed-off-by: Abel Feng <fshb1988@gmail.com>
  • Loading branch information
abel-von committed Oct 28, 2024
1 parent eaaca64 commit f710590
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 1 deletion.
79 changes: 79 additions & 0 deletions crates/libcontainer/src/container/builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::os::fd::OwnedFd;
use std::path::PathBuf;

use super::init_builder::InitContainerBuilder;
Expand All @@ -24,6 +25,12 @@ pub struct ContainerBuilder {
/// The function that actually runs on the container init process. Default
/// is to execute the specified command in the oci spec.
pub(super) executor: Box<dyn Executor>,
// RawFd set to stdin of the container init process.
pub stdin: Option<OwnedFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<OwnedFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<OwnedFd>,
}

/// Builder that can be used to configure the common properties of
Expand Down Expand Up @@ -70,6 +77,9 @@ impl ContainerBuilder {
console_socket: None,
preserve_fds: 0,
executor: workload::default::get_executor(),
stdin: None,
stdout: None,
stderr: None,
}
}

Expand Down Expand Up @@ -257,6 +267,75 @@ impl ContainerBuilder {
self.executor = Box::new(executor);
self
}

/// Sets the stdin of the container, for those who use libcontainer as an library,
/// the container stdin may not have to be set to an opened file descriptor
/// rather than the stdin of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (r, _w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stdin(r);
/// ```
pub fn with_stdin(mut self, stdin: OwnedFd) -> Self {
self.stdin = Some(stdin);
self
}

/// Sets the stdout of the container, for those who use libcontainer as an library,
/// the container stdout may not have to be set to an opened file descriptor
/// rather than the stdout of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (_r, w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stdout(w);
/// ```
pub fn with_stdout(mut self, stdout: OwnedFd) -> Self {
self.stdout = Some(stdout);
self
}

/// Sets the stderr of the container, for those who use libcontainer as an library,
/// the container stderr may not have to be set to an opened file descriptor
/// rather than the stderr of the current process.
/// # Example
///
/// ```no_run
/// # use libcontainer::container::builder::ContainerBuilder;
/// # use libcontainer::syscall::syscall::SyscallType;
/// # use libcontainer::workload::default::DefaultExecutor;
/// # use nix::unistd::pipe;
///
/// let (_r, w) = pipe().unwrap();
/// ContainerBuilder::new(
/// "74f1a4cb3801".to_owned(),
/// SyscallType::default(),
/// )
/// .with_stderr(w);
/// ```
pub fn with_stderr(mut self, stderr: OwnedFd) -> Self {
self.stderr = Some(stderr);
self
}
}

#[cfg(test)]
Expand Down
10 changes: 10 additions & 0 deletions crates/libcontainer/src/container/builder_impl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs;
use std::io::Write;
use std::os::fd::{AsRawFd, OwnedFd};
use std::os::unix::prelude::RawFd;
use std::path::PathBuf;
use std::rc::Rc;
Expand Down Expand Up @@ -49,6 +50,12 @@ pub(super) struct ContainerBuilderImpl {
pub detached: bool,
/// Default executes the specified execution of a generic command
pub executor: Box<dyn Executor>,
// RawFd set to stdin of the container init process.
pub stdin: Option<OwnedFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<OwnedFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<OwnedFd>,
}

impl ContainerBuilderImpl {
Expand Down Expand Up @@ -154,6 +161,9 @@ impl ContainerBuilderImpl {
cgroup_config,

Check warning on line 161 in crates/libcontainer/src/container/builder_impl.rs

View workflow job for this annotation

GitHub Actions / check (aarch64, gnu)

Diff in /home/runner/work/youki/youki/crates/libcontainer/src/container/builder_impl.rs
detached: self.detached,
executor: self.executor.clone(),
stdin: self.stdin.as_ref().map(|x|x.as_raw_fd()),
stdout: self.stdout.as_ref().map(|x|x.as_raw_fd()),
stderr: self.stderr.as_ref().map(|x|x.as_raw_fd()),
};

let (init_pid, need_to_clean_up_intel_rdt_dir) =
Expand Down
3 changes: 3 additions & 0 deletions crates/libcontainer/src/container/init_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ impl InitContainerBuilder {
preserve_fds: self.base.preserve_fds,
detached: self.detached,
executor: self.base.executor,
stdin: self.base.stdin,
stdout: self.base.stdout,
stderr: self.base.stderr,
};

builder_impl.create()?;
Expand Down
3 changes: 3 additions & 0 deletions crates/libcontainer/src/container/tenant_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ impl TenantContainerBuilder {
preserve_fds: self.base.preserve_fds,
detached: self.detached,
executor: self.base.executor,
stdin: self.base.stdin,
stdout: self.base.stdout,
stderr: self.base.stderr,
};

let pid = builder_impl.create()?;
Expand Down
6 changes: 6 additions & 0 deletions crates/libcontainer/src/process/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ pub struct ContainerArgs {
pub detached: bool,
/// Manage the functions that actually run on the container
pub executor: Box<dyn Executor>,
// RawFd set to stdin of the container init process.
pub stdin: Option<RawFd>,
// RawFd set to stdout of the container init process.
pub stdout: Option<RawFd>,
// RawFd set to stderr of the container init process.
pub stderr: Option<RawFd>,
}
15 changes: 14 additions & 1 deletion crates/libcontainer/src/process/container_init_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use nc;
use nix::mount::MsFlags;
use nix::sched::CloneFlags;
use nix::sys::stat::Mode;
use nix::unistd::{self, setsid, Gid, Uid};
use nix::unistd::{self, close, dup2, setsid, Gid, Uid};
use oci_spec::runtime::{
IOPriorityClass, LinuxIOPriority, LinuxNamespaceType, LinuxSchedulerFlag, LinuxSchedulerPolicy,
Scheduler, Spec, User,
Expand Down Expand Up @@ -304,6 +304,19 @@ pub fn container_init_process(
tracing::error!(?err, "failed to set up tty");
InitProcessError::Tty(err)
})?;
} else {
if let Some(stdin) = args.stdin {
dup2(stdin, 0).map_err(InitProcessError::NixOther)?;
close(stdin).map_err(InitProcessError::NixOther)?;
}
if let Some(stdout) = args.stdout {
dup2(stdout, 1).map_err(InitProcessError::NixOther)?;
close(stdout).map_err(InitProcessError::NixOther)?;
}
if let Some(stderr) = args.stderr {
dup2(stderr, 2).map_err(InitProcessError::NixOther)?;
close(stderr).map_err(InitProcessError::NixOther)?;
}
}

apply_rest_namespaces(&namespaces, spec, syscall.as_ref())?;
Expand Down

0 comments on commit f710590

Please sign in to comment.