diff --git a/exec.go b/exec.go index 891fabbd8de..f8baff3d152 100644 --- a/exec.go +++ b/exec.go @@ -101,7 +101,8 @@ following will output a list of processes running in the container: if err == nil { os.Exit(status) } - return fmt.Errorf("exec failed: %w", err) + fatalWithCode(fmt.Errorf("exec failed: %w", err), 255) + return nil // to satisfy the linter }, SkipArgReorder: true, } diff --git a/man/runc-exec.8.md b/man/runc-exec.8.md index dafd03dcb8c..49f9cab53c5 100644 --- a/man/runc-exec.8.md +++ b/man/runc-exec.8.md @@ -59,6 +59,11 @@ multiple times. : Pass _N_ additional file descriptors to the container (**stdio** + **$LISTEN_FDS** + _N_ in total). Default is **0**. +# EXIT STATUS + +Exits with a status of _command_ (unless **-d** is used), or **255** if +an error occurred. + # EXAMPLES If the container can run **ps**(1) command, the following will output a list of processes running in the container: diff --git a/tests/integration/exec.bats b/tests/integration/exec.bats index 039041cc65a..a49112fa035 100644 --- a/tests/integration/exec.bats +++ b/tests/integration/exec.bats @@ -21,6 +21,26 @@ function teardown() { [[ "${output}" == *"Hello from exec"* ]] } +@test "runc exec [exit codes]" { + runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox + [ "$status" -eq 0 ] + + runc exec test_busybox false + [ "$status" -eq 1 ] + + runc exec test_busybox sh -c "exit 42" + [ "$status" -eq 42 ] + + runc exec --pid-file /non-existent/directory test_busybox true + [ "$status" -eq 255 ] + + runc exec test_busybox no-such-binary + [ "$status" -eq 255 ] + + runc exec no_such_container true + [ "$status" -eq 255 ] +} + @test "runc exec --pid-file" { # run busybox detached runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox diff --git a/utils.go b/utils.go index 2809c3df8ab..32ab33e5506 100644 --- a/utils.go +++ b/utils.go @@ -53,13 +53,17 @@ func logrusToStderr() bool { // fatal prints the error's details if it is a libcontainer specific error type // then exits the program with an exit status of 1. func fatal(err error) { - // make sure the error is written to the logger + fatalWithCode(err, 1) +} + +func fatalWithCode(err error, ret int) { + // Make sure the error is written to the logger. logrus.Error(err) if !logrusToStderr() { fmt.Fprintln(os.Stderr, err) } - os.Exit(1) + os.Exit(ret) } // setupSpec performs initial setup based on the cli.Context for the container