From 9d9ec543a40912b332397a238144daf646673a57 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:16:10 +0200 Subject: [PATCH] Improve logic s6 --- .templates/ha_entrypoint.sh | 124 +++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/.templates/ha_entrypoint.sh b/.templates/ha_entrypoint.sh index 57581f68c..afd7285a0 100755 --- a/.templates/ha_entrypoint.sh +++ b/.templates/ha_entrypoint.sh @@ -1,6 +1,8 @@ #!/command/with-contenv bashio # shellcheck shell=bash +set -e # Exit immediately if a command exits with a non-zero status + echo "Starting..." # Detect if this is PID1 (main container process) — do this once at the start @@ -9,100 +11,116 @@ if [ "$$" -eq 1 ]; then PID1=true fi +###################### +# Select the shebang # +###################### + +# List of candidate shebangs, prioritize with-contenv if PID1 +candidate_shebangs=() +if $PID1; then + candidate_shebangs+=("/command/with-contenv bashio" "/usr/bin/with-contenv bashio") +fi +candidate_shebangs+=( + "/usr/bin/env bashio" + "/usr/bin/bashio" + "/usr/bin/bash" + "/usr/bin/sh" + "/bin/bash" + "/bin/sh" +) + +# Find the first valid shebang interpreter in candidate list +shebang="" +for candidate in "${candidate_shebangs[@]}"; do + command_path="${candidate%% *}" + # Test if command exists and can actually execute a shell command (for shells) + if [ -x "$command_path" ]; then + # Try as both 'sh -c' and 'bashio echo' style + if "$command_path" -c 'echo yes' >/dev/null 2>&1 || "$command_path" echo "yes" >/dev/null 2>&1; then + shebang="$candidate" + break + fi + fi +done +if [ -z "$shebang" ]; then + echo "ERROR: No valid shebang found!" + exit 1 +fi + #################### # Starting scripts # #################### -# Loop through /etc/cont-init.d/* +# Loop through /etc/cont-init.d/* scripts and execute them for SCRIPTS in /etc/cont-init.d/*; do [ -e "$SCRIPTS" ] || continue echo "$SCRIPTS: executing" - # Check if run as root + # Check if run as root (UID 0) if [ "$(id -u)" -eq 0 ]; then + # Fix permissions for root user chown "$(id -u)":"$(id -g)" "$SCRIPTS" chmod a+x "$SCRIPTS" else echo -e "\e[38;5;214m$(date) WARNING: Script executed with user $(id -u):$(id -g), things can break and chown won't work\e[0m" - # Disable chown and chmod in scripts - sed -i "s/^chown /true # chown /g" "$SCRIPTS" - sed -i "s/ chown / true # chown /g" "$SCRIPTS" - sed -i "s/^chmod /true # chmod /g" "$SCRIPTS" - sed -i "s/ chmod / true # chmod /g" "$SCRIPTS" + # Disable chown and chmod commands inside the script for non-root users + sed -i "s/^\s*chown /true # chown /g" "$SCRIPTS" + sed -i "s/^\s*chmod /true # chmod /g" "$SCRIPTS" fi - # Get current shebang, if not available use another - currentshebang="$(sed -n '1{s/^#![[:blank:]]*//p;q}' "$SCRIPTS")" - if [ ! -f "${currentshebang%% *}" ]; then - for shebang in "/command/with-contenv bashio" "/usr/bin/with-contenv bashio" "/usr/bin/env bashio" "/usr/bin/bashio" "/usr/bin/bash" "/usr/bin/sh" "/bin/bash" "/bin/sh"; do - command_path="${shebang%% *}" - if [ -x "$command_path" ] && "$command_path" echo "yes" >/dev/null 2>&1; then - echo "Valid shebang: $shebang" - break - fi - done - sed -i "s|$currentshebang|$shebang|g" "$SCRIPTS" - fi + # Replace the shebang in the script with the valid one + sed -i "1s|^.*|#!$shebang|" "$SCRIPTS" - # Use source to share env variables when requested - if [ "${ha_entry_source:-null}" = true ] && command -v "source" &>/dev/null; then - sed -i "s/(.*\s|^)exit \([0-9]\+\)/ \1 return \2 || exit \2/g" "$SCRIPTS" - sed -i "s/bashio::exit.nok/return 1/g" "$SCRIPTS" - sed -i "s/bashio::exit.ok/return 0/g" "$SCRIPTS" + # Optionally use 'source' to share env variables, when requested + if [ "${ha_entry_source:-null}" = true ]; then + # Replace exit with return, so sourced scripts can return errors + sed -i -E 's/^\s*exit ([0-9]+)/return \1 \|\| exit \1/g' "$SCRIPTS" + sed -i 's/bashio::exit\.nok/return 1/g' "$SCRIPTS" + sed -i 's/bashio::exit\.ok/return 0/g' "$SCRIPTS" # shellcheck disable=SC1090 source "$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?" else "$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?" fi - # Cleanup + # Cleanup after execution rm "$SCRIPTS" done -# Start services.d +# Start run scripts in services.d and s6-overlay/s6-rc.d if PID1 if $PID1; then - if [ "$(ls -A /etc/services.d/*/run)" ]; then - for runfile in /etc/services.d/*/run; do - if [[ -f "$runfile" ]]; then - echo "Starting: $runfile" - # Replace s6-setuidgid with su-based equivalent - sed -i -E 's|^s6-setuidgid[[:space:]]+([a-zA-Z0-9._-]+)[[:space:]]+(.*)$|su -s /bin/bash \1 -c "\2"|g' "$runfile" - chmod +x "$runfile" - ( exec "$runfile" ) & true - fi - done - fi - if [ "$(ls -A /etc/s6-overlay/s6-rc.d/*/run)" ]; then - for runfile in /etc/s6-overlay/s6-rc.d/*/run; do - if [[ -f "$runfile" ]]; then - echo "Starting: $runfile" - # Replace s6-setuidgid with su-based equivalent - sed -i -E 's|^s6-setuidgid[[:space:]]+([a-zA-Z0-9._-]+)[[:space:]]+(.*)$|su -s /bin/bash \1 -c "\2"|g' "$runfile" - chmod +x "$runfile" - ( exec "$runfile" ) & true - fi - done - fi + shopt -s nullglob # Don't expand unmatched globs to themselves + for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do + [ -f "$runfile" ] || continue + echo "Starting: $runfile" + # Replace the shebang line in each runfile + sed -i "1s|^.*|#!$shebang|" "$runfile" + # Replace s6-setuidgid calls with 'su' (bash-based) equivalents + sed -i -E 's|^s6-setuidgid[[:space:]]+([a-zA-Z0-9._-]+)[[:space:]]+(.*)$|su -s /bin/bash \1 -c "\2"|g' "$runfile" + chmod +x "$runfile" + ( exec "$runfile" ) & true + done + shopt -u nullglob fi ###################### # Starting container # ###################### -# If PID 1, keep alive and manage sigterm +# If this is PID 1, keep alive and manage sigterm for clean shutdown if $PID1; then echo " " echo -e "\033[0;32mEverything started!\033[0m" terminate() { echo "Termination signal received, forwarding to subprocesses..." - # Terminate all subprocesses + # Terminate all direct child processes if command -v pgrep &>/dev/null; then for pid in $(pgrep -P $$); do echo "Terminating child PID $pid" kill -TERM "$pid" 2>/dev/null || echo "Failed to terminate PID $pid" done else - # Fallback to iterating through /proc if pgrep is not available + # Fallback: Scan /proc for children for pid in /proc/[0-9]*/; do pid=${pid#/proc/} pid=${pid%/} @@ -112,12 +130,12 @@ if $PID1; then fi done fi - wait echo "All subprocesses terminated. Exiting." exit 0 } trap terminate SIGTERM SIGINT + # Main keep-alive loop while :; do sleep infinity & wait $! @@ -126,6 +144,6 @@ else echo " " echo -e "\033[0;32mStarting the upstream container\033[0m" echo " " - # Launch lsio mods + # Launch optional mods script if present if [ -f /docker-mods ]; then exec /docker-mods; fi fi