From d6b1fbea4cf29bd6c826020d3f957054a57d65a8 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Thu, 9 Sep 2021 19:29:10 +0200 Subject: [PATCH] cmd/run: Unbreak 'enter' if the shell had exited with 127 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, 'toolbox enter' can get into a loop if the user tried to run something inside the shell that didn't exist, and quit immediately afterwards: $ toolbox enter ⬢$ foo bash: foo: command not found ⬢$ logout Error: command /bin/bash not found in container fedora-toolbox-34 Using /bin/bash instead. ⬢$ This is because: * The shell forwards the exit code of the last command that was invoked as its own exit code. If the last command that was attempted was absent then this exit code is 127. * 'podman exec' uses 127 as the exit code when it can't invoke the command. If it's able to successfully invoke the command, it forwards the exit code of the command itself. Therefore, in the above example 'podman exec' itself returns with an exit code of 127 even though both the working directory and the command that were passed to it were present. Hence, it's necessary to explicitly check if the requested command was really absent before attempting the fallbacks. Fallout from 4536e2c8c28f6c4fed5e0346ea1094156e449f59 https://github.com/containers/toolbox/pull/872 --- src/cmd/run.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cmd/run.go b/src/cmd/run.go index 6b6b0fda8..470a787bd 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -343,7 +343,7 @@ func runCommandWithFallbacks(container string, command []string, emitEscapeSeque } else { return fmt.Errorf("directory %s not found in container %s", workDir, container) } - } else { + } else if _, err := isCommandPresent(container, command[0]); err != nil { if fallbackToBash && runFallbackCommandsIndex < len(runFallbackCommands) { fmt.Fprintf(os.Stderr, "Error: command %s not found in container %s\n", @@ -357,6 +357,8 @@ func runCommandWithFallbacks(container string, command []string, emitEscapeSeque } else { return fmt.Errorf("command %s not found in container %s", command[0], container) } + } else { + return nil } default: return nil @@ -489,6 +491,25 @@ func getEntryPointAndPID(container string) (string, int, error) { return entryPoint, entryPointPIDInt, nil } +func isCommandPresent(container, command string) (bool, error) { + logrus.Debugf("Looking for command %s in container %s", command, container) + + logLevelString := podman.LogLevel.String() + args := []string{ + "--log-level", logLevelString, + "exec", + "--user", currentUser.Username, + container, + "sh", "-c", "command -v \"$1\"", "sh", command, + } + + if err := shell.Run("podman", nil, nil, nil, args...); err != nil { + return false, err + } + + return true, nil +} + func isPathPresent(container, path string) (bool, error) { logrus.Debugf("Looking for path %s in container %s", path, container)