Skip to content
2 changes: 2 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,8 @@ user [?string](#?string)
workdir [?string](#?string)

env [?[]string](#?[]string)

detachKeys [?string](#?string)
### <a name="Image"></a>type Image


Expand Down
7 changes: 0 additions & 7 deletions cmd/podman/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -70,11 +69,5 @@ func execCmd(c *cliconfig.ExecValues) error {
defer runtime.DeferredShutdown(false)

exitCode, err = runtime.ExecContainer(getContext(), c)
if errors.Cause(err) == define.ErrOCIRuntimePermissionDenied {
exitCode = 126
}
if errors.Cause(err) == define.ErrOCIRuntimeNotFound {
exitCode = 127
}
return err
}
4 changes: 3 additions & 1 deletion cmd/podman/varlink/io.podman.varlink
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,9 @@ type ExecOpts(
# workdir to run command in container
workdir: ?string,
# slice of keyword=value environment variables
env: ?[]string
env: ?[]string,
# string of detach keys
detachKeys: ?string
)

# GetVersion returns version and build information of the podman service
Expand Down
15 changes: 5 additions & 10 deletions libpod/container_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ import (
"k8s.io/client-go/tools/remotecommand"
)

const (
defaultExecExitCode = 125
defaultExecExitCodeCannotInvoke = 126
)

// Init creates a container in the OCI runtime
func (c *Container) Init(ctx context.Context) (err error) {
span, _ := opentracing.StartSpanFromContext(ctx, "containerInit")
Expand Down Expand Up @@ -234,15 +229,15 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
defer c.lock.Unlock()

if err := c.syncContainer(); err != nil {
return defaultExecExitCodeCannotInvoke, err
return define.ExecErrorCodeCannotInvoke, err
}
}

conState := c.state.State

// TODO can probably relax this once we track exec sessions
if conState != define.ContainerStateRunning {
return defaultExecExitCodeCannotInvoke, errors.Wrapf(define.ErrCtrStateInvalid, "cannot exec into container that is not running")
return define.ExecErrorCodeCannotInvoke, errors.Wrapf(define.ErrCtrStateInvalid, "cannot exec into container that is not running")
}

if privileged || c.config.Privileged {
Expand All @@ -269,7 +264,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir

logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
if err := c.createExecBundle(sessionID); err != nil {
return defaultExecExitCodeCannotInvoke, err
return define.ExecErrorCodeCannotInvoke, err
}

defer func() {
Expand All @@ -281,7 +276,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir

pid, attachChan, err := c.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, user, sessionID, streams, preserveFDs, resize, detachKeys)
if err != nil {
ec := defaultExecExitCode
ec := define.ExecErrorCodeGeneric
// Conmon will pass a non-zero exit code from the runtime as a pid here.
// we differentiate a pid with an exit code by sending it as negative, so reverse
// that change and return the exit code the runtime failed with.
Expand All @@ -303,7 +298,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
if err := c.save(); err != nil {
// Now we have a PID but we can't save it in the DB
// TODO handle this better
return defaultExecExitCode, errors.Wrapf(err, "error saving exec sessions %s for container %s", sessionID, c.ID())
return define.ExecErrorCodeGeneric, errors.Wrapf(err, "error saving exec sessions %s for container %s", sessionID, c.ID())
}
c.newContainerEvent(events.Exec)
logrus.Debugf("Successfully started exec session %s in container %s", sessionID, c.ID())
Expand Down
30 changes: 30 additions & 0 deletions libpod/define/exec_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package define

import (
"github.com/pkg/errors"
)

const (
// ExecErrorCodeGeneric is the default error code to return from an exec session if libpod failed
// prior to calling the runtime
ExecErrorCodeGeneric = 125
// ExecErrorCodeCannotInvoke is the error code to return when the runtime fails to invoke a command
// an example of this can be found by trying to execute a directory:
// `podman exec -l /etc`
ExecErrorCodeCannotInvoke = 126
// ExecErrorCodeNotFound is the error code to return when a command cannot be found
ExecErrorCodeNotFound = 127
)

// TranslateExecErrorToExitCode takes an error and checks whether it
// has a predefined exit code associated. If so, it returns that, otherwise it returns
// the exit code originally stated in libpod.Exec()
func TranslateExecErrorToExitCode(originalEC int, err error) int {
if errors.Cause(err) == ErrOCIRuntimePermissionDenied {
return ExecErrorCodeCannotInvoke
}
if errors.Cause(err) == ErrOCIRuntimeNotFound {
return ExecErrorCodeNotFound
}
return originalEC
}
3 changes: 2 additions & 1 deletion pkg/adapter/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,8 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal
streams.AttachOutput = true
streams.AttachError = true

return ExecAttachCtr(ctx, ctr.Container, cli.Tty, cli.Privileged, envs, cmd, cli.User, cli.Workdir, streams, cli.PreserveFDs, cli.DetachKeys)
ec, err = ExecAttachCtr(ctx, ctr.Container, cli.Tty, cli.Privileged, envs, cmd, cli.User, cli.Workdir, streams, cli.PreserveFDs, cli.DetachKeys)
return define.TranslateExecErrorToExitCode(ec, err), err
}

// Prune removes stopped containers
Expand Down
Loading