diff --git a/crates/libcontainer/src/container/builder.rs b/crates/libcontainer/src/container/builder.rs index 5aa1d39c5..c3d3b2be6 100644 --- a/crates/libcontainer/src/container/builder.rs +++ b/crates/libcontainer/src/container/builder.rs @@ -1,3 +1,4 @@ +use std::os::fd::RawFd; use std::path::PathBuf; use super::init_builder::InitContainerBuilder; @@ -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, + // RawFd set to stdin of the container init process. + pub stdin: Option, + // RawFd set to stdout of the container init process. + pub stdout: Option, + // RawFd set to stderr of the container init process. + pub stderr: Option, } /// Builder that can be used to configure the common properties of @@ -70,6 +77,9 @@ impl ContainerBuilder { console_socket: None, preserve_fds: 0, executor: workload::default::get_executor(), + stdin: None, + stdout: None, + stderr: None, } } @@ -257,6 +267,90 @@ 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 currrent process. + /// # Example + /// + /// ```no_run + /// # use libcontainer::container::builder::ContainerBuilder; + /// # use libcontainer::syscall::syscall::SyscallType; + /// # use libcontainer::workload::default::DefaultExecutor; + /// # use libc; + /// # use std::os::fd::IntoRawFd; + /// + /// let f = OpenOptions::new() + /// .read(true) + /// .custom_flags(libc::O_NONBLOCK) + /// .open("/path/to/stdin_pipe")?; + /// + /// ContainerBuilder::new( + /// "74f1a4cb3801".to_owned(), + /// SyscallType::default(), + /// ) + /// .with_stdin(f.into_raw_fd()); + /// ``` + pub fn with_stdin(mut self, stdin: RawFd) -> 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 currrent process. + /// # Example + /// + /// ```no_run + /// # use libcontainer::container::builder::ContainerBuilder; + /// # use libcontainer::syscall::syscall::SyscallType; + /// # use libcontainer::workload::default::DefaultExecutor; + /// # use libc; + /// # use std::os::fd::IntoRawFd; + /// + /// let f = OpenOptions::new() + /// .read(true) + /// .custom_flags(libc::O_NONBLOCK) + /// .open("/path/to/stdout_pipe")?; + /// + /// ContainerBuilder::new( + /// "74f1a4cb3801".to_owned(), + /// SyscallType::default(), + /// ) + /// .with_stdout(f.into_raw_fd()); + /// ``` + pub fn with_stdout(mut self, stdout: RawFd) -> 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 currrent process. + /// # Example + /// + /// ```no_run + /// # use libcontainer::container::builder::ContainerBuilder; + /// # use libcontainer::syscall::syscall::SyscallType; + /// # use libcontainer::workload::default::DefaultExecutor; + /// # use libc; + /// # use std::os::fd::IntoRawFd; + /// + /// let f = OpenOptions::new() + /// .read(true) + /// .custom_flags(libc::O_NONBLOCK) + /// .open("/path/to/stderr_pipe")?; + /// + /// ContainerBuilder::new( + /// "74f1a4cb3801".to_owned(), + /// SyscallType::default(), + /// ) + /// .with_stderr(f.into_raw_fd()); + /// ``` + pub fn with_stderr(mut self, stderr: RawFd) -> Self { + self.stderr = Some(stderr); + self + } } #[cfg(test)] diff --git a/crates/libcontainer/src/container/builder_impl.rs b/crates/libcontainer/src/container/builder_impl.rs index ed2cd07dd..6019e5f2c 100644 --- a/crates/libcontainer/src/container/builder_impl.rs +++ b/crates/libcontainer/src/container/builder_impl.rs @@ -49,6 +49,12 @@ pub(super) struct ContainerBuilderImpl { pub detached: bool, /// Default executes the specified execution of a generic command pub executor: Box, + // RawFd set to stdin of the container init process. + pub stdin: Option, + // RawFd set to stdout of the container init process. + pub stdout: Option, + // RawFd set to stderr of the container init process. + pub stderr: Option, } impl ContainerBuilderImpl { @@ -154,6 +160,9 @@ impl ContainerBuilderImpl { cgroup_config, detached: self.detached, executor: self.executor.clone(), + stdin: self.stdin, + stdout: self.stdout, + stderr: self.stderr, }; let (init_pid, need_to_clean_up_intel_rdt_dir) = diff --git a/crates/libcontainer/src/container/init_builder.rs b/crates/libcontainer/src/container/init_builder.rs index 2230acc60..368d588f1 100644 --- a/crates/libcontainer/src/container/init_builder.rs +++ b/crates/libcontainer/src/container/init_builder.rs @@ -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()?; diff --git a/crates/libcontainer/src/container/tenant_builder.rs b/crates/libcontainer/src/container/tenant_builder.rs index 1ebddd76b..f74f999d0 100644 --- a/crates/libcontainer/src/container/tenant_builder.rs +++ b/crates/libcontainer/src/container/tenant_builder.rs @@ -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()?; diff --git a/crates/libcontainer/src/process/args.rs b/crates/libcontainer/src/process/args.rs index a4451dd85..98954c408 100644 --- a/crates/libcontainer/src/process/args.rs +++ b/crates/libcontainer/src/process/args.rs @@ -42,4 +42,10 @@ pub struct ContainerArgs { pub detached: bool, /// Manage the functions that actually run on the container pub executor: Box, + // RawFd set to stdin of the container init process. + pub stdin: Option, + // RawFd set to stdout of the container init process. + pub stdout: Option, + // RawFd set to stderr of the container init process. + pub stderr: Option, } diff --git a/crates/libcontainer/src/process/container_init_process.rs b/crates/libcontainer/src/process/container_init_process.rs index 64182c1c7..5c997b173 100644 --- a/crates/libcontainer/src/process/container_init_process.rs +++ b/crates/libcontainer/src/process/container_init_process.rs @@ -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, dup2, setsid, Gid, Uid}; use oci_spec::runtime::{ IOPriorityClass, LinuxIOPriority, LinuxNamespaceType, LinuxSchedulerFlag, LinuxSchedulerPolicy, Scheduler, Spec, User, @@ -304,6 +304,16 @@ 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)?; + } + if let Some(stdout) = args.stdout { + dup2(stdout, 1).map_err(InitProcessError::NixOther)?; + } + if let Some(stderr) = args.stderr { + dup2(stderr, 2).map_err(InitProcessError::NixOther)?; + } } apply_rest_namespaces(&namespaces, spec, syscall.as_ref())?;