From ae48ecf5c0e6150e45f58e3a9e4df741aeed6e1f Mon Sep 17 00:00:00 2001 From: casjay Date: Mon, 27 Jul 2026 23:29:28 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20entrypoint=20hang=20and=20?= =?UTF-8?q?lost-interpreter=20bugs=20=F0=9F=90=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rootfs/usr/local/bin/entrypoint.sh: 1. The "start all services" gate (`if [ "$START_SERVICES" = "yes" ] || [ -z "$1" ]`) always evaluated true on a first-run container regardless of $1, because START_SERVICES is force-set to "yes" whenever no PID file exists yet. Any command passed to `docker run` — `exec ...`, `sh -c ...`, `shell`, or an arbitrary program — was swallowed into the service-start+monitor branch before reaching the `case "$1"` statement that already handles those subcommands, hanging the container as a daemon instead of running the given command. Changed the condition to `if [ -z "$1" ]` so the daemon branch only fires when no command was given at all. 2. The `*/bin/sh | */bin/bash | bash | sh | shell)` case branch unconditionally shifted $1 before `__exec_command "$@"` (a bare `exec "$@"`). For `docker run image sh -c 'cmd'` this turned the exec into `exec -c cmd` (command not found, exit 127) instead of `exec sh -c 'cmd'`. Split the branch: real interpreter names (*/bin/sh, */bin/bash, bash, sh) now pass through unshifted; the "shell" keyword (not a real interpreter) gets its own branch that shifts and prepends "sh" to any remaining args, or falls back to a bare `__exec_command` (exec bash -l) when none remain. Verified `bash -n` passes. Found and fixed upstream in dockersrc/go, confirmed identical in this repo's generated entrypoint.sh, and mechanically applied here with the same patch. --- rootfs/usr/local/bin/entrypoint.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/rootfs/usr/local/bin/entrypoint.sh b/rootfs/usr/local/bin/entrypoint.sh index ca25136..148bed8 100755 --- a/rootfs/usr/local/bin/entrypoint.sh +++ b/rootfs/usr/local/bin/entrypoint.sh @@ -476,7 +476,11 @@ SKIP_SERVICE_START="no" [ "$2" = "init" ] && SKIP_SERVICE_START="yes" && CONTAINER_INIT="yes" # - - - - - - - - - - - - - - - - - - - - - - - - - # Start all services if no pidfile and not skipping -if [ "$START_SERVICES" = "yes" ] || [ -z "$1" ]; then +# Start all services only when no command was given at all — an explicit +# command (exec, shell, tail, or an arbitrary program) must reach the case +# statement below instead of being swallowed into daemon/monitor mode, even +# on a first run where START_SERVICES is force-set to "yes" +if [ -z "$1" ]; then if [ "$SKIP_SERVICE_START" = "no" ]; then [ "$1" = "start" ] && shift 1 [ "$1" = "all" ] && shift 1 @@ -625,11 +629,25 @@ ssl) ;; # manage ssl certificate # Launch shell -*/bin/sh | */bin/bash | bash | sh | shell) - shift 1 +# Launch shell — do not shift here: "sh -c 'cmd'" / "bash -c 'cmd'" needs the +# interpreter name kept as argv[0] for __exec_command's `exec "$@"` to work; +# shifting it away turned "sh -c 'cmd'" into `exec -c cmd` (command not found) +*/bin/sh | */bin/bash | bash | sh) __exec_command "${@:-/bin/bash -l}" exit $? ;; +# "shell" is a keyword, not a real interpreter — it must be shifted away, and +# any remaining args need "sh" prepended so __exec_command's `exec "$@"` gets +# a real interpreter instead of trying to exec "-c" as a program +shell) + shift 1 + if [ $# -eq 0 ]; then + __exec_command + else + __exec_command sh "$@" + fi + exit $? + ;; # execute commands exec) shift 1