rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.9k stars 12.67k forks source link

`std::process::Command` Terminal execution command never returns? #114460

Closed dierbei closed 1 year ago

dierbei commented 1 year ago

Creating an OCI Bundle

# create the top most bundle directory
mkdir /mycontainer
cd /mycontainer

# create the rootfs directory
mkdir rootfs

# export busybox via Docker into the rootfs directory
docker export $(docker create busybox) | tar -C rootfs -xvf -

I tried this code:

let mut binding = Command::new("runc");
let child = binding
    .arg("--log-format")
    .arg("json")
    .arg("create")
    .arg("-b")
    .arg("/mycontainer")
    .arg("example")
    .stdout(Stdio::piped())
    .stderr(Stdio::piped())
    .spawn()
    .unwrap();
let result = child.wait_with_output().expect("");

I expected to see this happen: explanation

image

The hope is to perform some operations after creating. It seems that no results have been returned.

Meta

rustc --version --verbose:

rustc 1.73.0-nightly (474709a9a 2023-08-03)
binary: rustc
commit-hash: 474709a9a2a74a8bcf0055fadb335d0ca0d2d939
commit-date: 2023-08-03
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly
LLVM version: 16.0.5
Backtrace

``` ```

SpBills commented 1 year ago

The call to wait_with_output is causing your program to "stall" (or rather, wait for the child process to finish) indefinitely.

Simultaneously waits for the child to exit and collect all remaining output on the stdout/stderr handles, returning an Output instance.

Can you confirm that you can run this command from the CLI and it return?

I am guessing your desired behavior is to

  1. Spawn the child without waiting for it to die,
  2. Do a health check on the container to confirm it is running.
dierbei commented 1 year ago

@SpBills Yes, my purpose is to collect the stdout and stderr of the child process.

In fact, the more confusing part is that it can be created by executing commands directly on the shell terminal.

But the Rust program is blocking, which confuses me a lot.

For example, after I execute the following command on the command line, it will not block.

root@ecsHyNL:~/golang/test-rnc# runc --log-format json create -b /mycontainer example
root@ecsHyNL:~/golang/test-rnc#
SpBills commented 1 year ago

@SpBills Yes, my purpose is to collect the stdout and stderr of the child process.

In fact, the more confusing part is that it can be created by executing commands directly on the shell terminal.

But the Rust program is blocking, which confuses me a lot.

For example, after I execute the following command on the command line, it will not block.

root@ecsHyNL:~/golang/test-rnc# runc --log-format json create -b /mycontainer example
root@ecsHyNL:~/golang/test-rnc#

Huh, that's weird. I am going to give you the benefit of the doubt that you are running the command in the same environment that you are running the Rust program too.

I do get a feeling it has something to do with env variables though, as programmatic container problems often are.

After doing some testing, it looks like Command::new automatically inherits the parent environment. However, due to setuid, it probably has some permissions issues. Can you try chmod u+s <file_path> on your file executable?

dierbei commented 1 year ago

@SpBills Thanks for the suggestion, I also think it's a problem with the container.

I tried the following steps to run the rust program, still the same problem.

image

I haven't thought of a solution so far.