linuxbashdocker

Start up script fails with error "-e: invalid option", what is missing?


The following script is the ENTRYPOINT of my Dockerfile:

/config/bootstrap.sh

#!/bin/bash

set -e
set -u

# Supervisord default params
SUPERVISOR_PARAMS='-c /etc/supervisord.conf'

mkdir -p /data/conf /data/run /data/logs
chmod 711 /data/conf /data/run /data/logs

if [ "$(ls /config/init/)" ]; then
  for init in /config/init/*.sh; do
    . $init
  done
fi

# We have TTY, so probably an interactive container...
if test -t 0; then
  # Run supervisord detached...
  supervisord $SUPERVISOR_PARAMS

  # Some command(s) has been passed to container? Execute them and exit.
  # No commands provided? Run bash.
  if [[ $@ ]]; then
    eval $@
  else
    export PS1='[\u@\h : \w]\$ '
    /bin/bash
  fi    
else
  # If some extra params were passed, execute them before.
  if [[ $@ ]]; then
    eval $@
  fi
  supervisord -n $SUPERVISOR_PARAMS
fi

As you can see I am picking up all the scripts from /config/init and run them, right? One of those script is this one:

#!/bin/sh

set -e

DATA_DIR="/data/www"
WEB_DIR="$DATA_DIR/web"
VAR_DIR="$DATA_DIR/var"

usermod -u 1000 apache && groupmod -g 1000 apache && \
chown -R apache:root $DATA_DIR

if  [ "$(ls -la $WEB_DIR)" ]; then
    find "$WEB_DIR" -type d -print0 -exec chmod 777 {} \;
fi

if  [ "$(ls -la $VAR_DIR)" ]; then
    find "$VAR_DIR" -type d -print0 -exec chmod 777 {} \;
fi

if [ "$(ls -a $DATA_DIR)" ]; then
    touch "$DATA_DIR"/index.php
    echo "<?php phpinfo(); ?>" > "$DATA_DIR"/index.php
fi

exec "$@"

Each time I try to run the container upon success build I get the following error:

$ docker run -it reynierpm/php-fpm -e INSTALL_COMPOSER=true
ls: cannot access /data/www/web: No such file or directory
ls: cannot access /data/www/var: No such file or directory
/config/init/20-permissions.sh: line 26: exec: -e: invalid option
exec: usage: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]

UPDATE

The script above has been updated to the following:

#!/bin/bash

set -e

data_dir="/data/www"
web_dir="$data_dir/web"
var_cache_dir="$data_dir/var/cache"
var_logs_dir="$data_dir/var/logs"

# This script will be placed in /config/init/ and run when container starts.
usermod -u 1000 apache && groupmod -g 1000 apache && \
chown -R apache:root "$data_dir"

# Setup web directory permissions and ownership
if  [ -d "$web_dir" ]; then
    chgrp -R apache "$web_dir"
    chmod -R g+w "$web_dir"
    find "$web_dir" -type d -exec chmod 2775 {} +
    find "$web_dir" -type f -exec chmod ug+rw {} +
fi

# Setup cache directory permissions and ownership
if  [ -d "$var_cache_dir" ]; then
    chgrp -R apache "$var_cache_dir"
    chmod -R g+w "$var_cache_dir"
    find "$var_cache_dir" -type d -exec chmod 2775 {} +
    find "$var_cache_dir" -type f -exec chmod ug+rw {} +
fi

# Setup cache directory permissions and ownership
if  [ -d "$var_logs_dir" ]; then
    chgrp -R apache "$var_logs_dir"
    chmod -R g+w "$var_logs_dir"
    find "$var_logs_dir" -type d -exec chmod 2775 {} +
    find "$var_logs_dir" -type f -exec chmod ug+rw {} +
fi

# Create index.php file if $data_dir is empty
if files=("$data_dir"/*); [[ -e "${files[0]}" ]]; then
    echo '<?php phpinfo(); ?>' > "$data_dir/index.php";
fi

exec "$@"

But still not working ....

$ docker run -it reynierpm/php-fpm -e INSTALL_COMPOSER="true"
/config/init/21-permissions.sh: line 43: exec: -e: invalid option
exec: usage: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]

What I am missing here? What's wrong?


Solution

  • In your secondary script, you have this line at the end :

    exec "$@"
    

    It is very likely (well, mostly certain) that positional parameters contain -e as an argument. Where could that come from, you may ask?

    Your secondary script is sourced by this line in the primary script :

    . $init
    

    Sourced scripts execute in the context of the parent, so positional parameters are not replaced (unless you specify arguments after the name of the file you are sourcing). If $1 in your parent script contains -e, your sourced script will see that. It is possible your main script is receiving an argument, or one of your secondary scripts changes arguments. It is a bit of a problem executing all these scripts in the same context, there can be variables and positional parameters leaking.

    There is another issue I am seeing : your secondary script ends with an exec command, which replaces the current process with the command provided in argument (except in the specific cases where exec is used to manipulate file descriptors). Therefore, I would expect this secondary script to never return to the main script, and because of the secondary script being sourced, your primary script actually never finishing.