Skip to content

Commit

Permalink
Merge pull request #2961 from abel-von/support-set-stdio
Browse files Browse the repository at this point in the history
libcontainer: support set stdios for container
  • Loading branch information
YJDoc2 authored Nov 23, 2024
2 parents fad458f + cca8a6a commit 4478b32
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 1 deletion.
112 changes: 112 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,13 +267,84 @@ impl ContainerBuilder {
self.executor = Box::new(executor);
self
}

/// Sets the stdin of the container, for those who use libcontainer as a library,
/// the container stdin may 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: impl Into<OwnedFd>) -> Self {
self.stdin = Some(stdin.into());
self
}

/// Sets the stdout of the container, for those who use libcontainer as a library,
/// the container stdout may 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: impl Into<OwnedFd>) -> Self {
self.stdout = Some(stdout.into());
self
}

/// Sets the stderr of the container, for those who use libcontainer as a library,
/// the container stderr may 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: impl Into<OwnedFd>) -> Self {
self.stderr = Some(stderr.into());
self
}
}

#[cfg(test)]
mod tests {
use std::os::fd::AsRawFd;
use std::path::PathBuf;

use anyhow::{Context, Result};
use nix::unistd::pipe;

use crate::container::builder::ContainerBuilder;
use crate::syscall::syscall::SyscallType;
Expand Down Expand Up @@ -334,4 +415,35 @@ mod tests {
assert!(result.is_ok());
Ok(())
}

#[test]
fn test_stdios() -> Result<()> {
let (r, _w) = pipe()?;
let stdin_raw = r.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stdin(r);
assert_eq!(
builder.stdin.as_ref().map(|o| o.as_raw_fd()),
Some(stdin_raw)
);

let (_r, w) = pipe()?;
let stdout_raw = w.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stdout(w);
assert_eq!(
builder.stdout.as_ref().map(|o| o.as_raw_fd()),
Some(stdout_raw)
);

let (_r, w) = pipe()?;
let stderr_raw = w.as_raw_fd();
let builder =
ContainerBuilder::new("74f1a4cb3801".to_owned(), SyscallType::default()).with_stderr(w);
assert_eq!(
builder.stderr.as_ref().map(|o| o.as_raw_fd()),
Some(stderr_raw)
);
Ok(())
}
}
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 @@ -51,6 +52,12 @@ pub(super) struct ContainerBuilderImpl {
pub executor: Box<dyn Executor>,
/// If do not use pivot root to jail process inside rootfs
pub no_pivot: bool,
// 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 @@ -157,6 +164,9 @@ impl ContainerBuilderImpl {
detached: self.detached,
executor: self.executor.clone(),
no_pivot: self.no_pivot,
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 @@ -103,6 +103,9 @@ impl InitContainerBuilder {
detached: self.detached,
executor: self.base.executor,
no_pivot: self.no_pivot,
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 @@ -143,6 +143,9 @@ impl TenantContainerBuilder {
detached: self.detached,
executor: self.base.executor,
no_pivot: false,
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 @@ -44,4 +44,10 @@ pub struct ContainerArgs {
pub executor: Box<dyn Executor>,
/// If do not use pivot root to jail process inside rootfs
pub no_pivot: bool,
// 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::{MntFlags, 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 @@ -374,6 +374,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 4478b32

Please sign in to comment.