mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
daemon/exec: don't overwrite exit code if set
If we fail to start an exec, the deferred error-handling block in [L181-L193](c7e42d855e/daemon/exec.go (L181-L193)) would set the exit code to `126` (`EACCES`). However, if we get far enough along attempting to start the exec, we set the exit code according to the error returned from starting the task [L288-L291](c7e42d855e/daemon/exec.go (L288-L291)). For some situations (such as `docker exec [some-container] missing-binary`), the 2nd block returns the correct exit code (`127`) but that then gets overwritten by the 1st block. This commit changes that logic to only set the default exit code `126` if the exit code has not been set yet. Signed-off-by: Laura Brehm <laurabrehm@hey.com>
This commit is contained in:
@@ -183,8 +183,12 @@ func (daemon *Daemon) ContainerExecStart(ctx context.Context, name string, optio
|
||||
ec.Lock()
|
||||
ec.Container.ExecCommands.Delete(ec.ID)
|
||||
ec.Running = false
|
||||
exitCode := 126
|
||||
ec.ExitCode = &exitCode
|
||||
if ec.ExitCode == nil {
|
||||
// default to `126` (`EACCES`) if we fail to start
|
||||
// the exec without setting an exit code.
|
||||
exitCode := exitEaccess
|
||||
ec.ExitCode = &exitCode
|
||||
}
|
||||
if err := ec.CloseStreams(); err != nil {
|
||||
log.G(ctx).Errorf("failed to cleanup exec %s streams: %s", ec.Container.ID, err)
|
||||
}
|
||||
|
||||
@@ -30,3 +30,36 @@ func TestExecConsoleSize(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(result.Stdout()), "57 123")
|
||||
}
|
||||
|
||||
func TestFailedExecExitCode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
doc string
|
||||
command []string
|
||||
expectedExitCode int
|
||||
}{
|
||||
{
|
||||
doc: "executable not found",
|
||||
command: []string{"nonexistent"},
|
||||
expectedExitCode: 127,
|
||||
},
|
||||
{
|
||||
doc: "executable cannot be invoked",
|
||||
command: []string{"/etc"},
|
||||
expectedExitCode: 126,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
ctx := setupTest(t)
|
||||
apiClient := testEnv.APIClient()
|
||||
|
||||
cID := container.Run(ctx, t, apiClient)
|
||||
|
||||
result, err := container.Exec(ctx, apiClient, cID, tc.command)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, result.ExitCode, tc.expectedExitCode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user