summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/system/unshare.go21
-rw-r--r--docs/source/markdown/podman-unshare.1.md29
-rw-r--r--test/e2e/unshare_test.go35
3 files changed, 82 insertions, 3 deletions
diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go
index f930d8b62..50230609e 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -2,6 +2,7 @@ package system
import (
"os"
+ "os/exec"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
@@ -50,5 +51,23 @@ func unshare(cmd *cobra.Command, args []string) error {
args = []string{shell}
}
- return registry.ContainerEngine().Unshare(registry.Context(), args, unshareOptions)
+ err := registry.ContainerEngine().Unshare(registry.Context(), args, unshareOptions)
+ if err != nil {
+ if exitError, ok := err.(*exec.ExitError); ok {
+ // the user command inside the unshare env has failed
+ // we set the exit code, do not return the error to the user
+ // otherwise "exit status X" will be printed
+ registry.SetExitCode(exitError.ExitCode())
+ return nil
+ }
+ // cmd.Run() can return fs.ErrNotExist, fs.ErrPermission or exec.ErrNotFound
+ // follow podman run/exec standard with the exit codes
+ if errors.Is(err, os.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
+ registry.SetExitCode(127)
+ } else if errors.Is(err, os.ErrPermission) {
+ registry.SetExitCode(126)
+ }
+ return err
+ }
+ return nil
}
diff --git a/docs/source/markdown/podman-unshare.1.md b/docs/source/markdown/podman-unshare.1.md
index 2e7adfd34..72821b6e5 100644
--- a/docs/source/markdown/podman-unshare.1.md
+++ b/docs/source/markdown/podman-unshare.1.md
@@ -37,6 +37,35 @@ connect to a rootless container via IP address (CNI networking). This is otherwi
not possible from the host network namespace.
_Note: Using this option with more than one unshare session can have unexpected results._
+## Exit Codes
+
+The exit code from `podman unshare` gives information about why the container
+failed to run or why it exited. When `podman unshare` commands exit with a non-zero code,
+the exit codes follow the `chroot` standard, see below:
+
+ **125** The error is with podman **_itself_**
+
+ $ podman unshare --foo; echo $?
+ Error: unknown flag: --foo
+ 125
+
+ **126** Executing a _contained command_ and the _command_ cannot be invoked
+
+ $ podman unshare /etc; echo $?
+ Error: fork/exec /etc: permission denied
+ 126
+
+ **127** Executing a _contained command_ and the _command_ cannot be found
+
+ $ podman run busybox foo; echo $?
+ Error: fork/exec /usr/bin/bogus: no such file or directory
+ 127
+
+ **Exit code** _contained command_ exit code
+
+ $ podman run busybox /bin/sh -c 'exit 3'; echo $?
+ 3
+
## EXAMPLE
```
diff --git a/test/e2e/unshare_test.go b/test/e2e/unshare_test.go
index eacdda68a..79ce68e89 100644
--- a/test/e2e/unshare_test.go
+++ b/test/e2e/unshare_test.go
@@ -47,8 +47,7 @@ var _ = Describe("Podman unshare", func() {
session := podmanTest.Podman([]string{"unshare", "readlink", "/proc/self/ns/user"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- ok, _ := session.GrepString(userNS)
- Expect(ok).To(BeFalse())
+ Expect(session.OutputToString()).ToNot(ContainSubstring(userNS))
})
It("podman unshare --rootles-cni", func() {
@@ -57,4 +56,36 @@ var _ = Describe("Podman unshare", func() {
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("tap0"))
})
+
+ It("podman unshare exit codes", func() {
+ session := podmanTest.Podman([]string{"unshare", "false"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(1))
+ Expect(session.OutputToString()).Should(Equal(""))
+ Expect(session.ErrorToString()).Should(Equal(""))
+
+ session = podmanTest.Podman([]string{"unshare", "/usr/bin/bogus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(127))
+ Expect(session.OutputToString()).Should(Equal(""))
+ Expect(session.ErrorToString()).Should(ContainSubstring("no such file or directory"))
+
+ session = podmanTest.Podman([]string{"unshare", "bogus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(127))
+ Expect(session.OutputToString()).Should(Equal(""))
+ Expect(session.ErrorToString()).Should(ContainSubstring("executable file not found in $PATH"))
+
+ session = podmanTest.Podman([]string{"unshare", "/usr"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(126))
+ Expect(session.OutputToString()).Should(Equal(""))
+ Expect(session.ErrorToString()).Should(ContainSubstring("permission denied"))
+
+ session = podmanTest.Podman([]string{"unshare", "--bogus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(125))
+ Expect(session.OutputToString()).Should(Equal(""))
+ Expect(session.ErrorToString()).Should(ContainSubstring("unknown flag: --bogus"))
+ })
})