#!/usr/bin/env bash if [ "$(id -u)" = "0" ]; then echo "Switching to dedicated user 'mysql'" exec gosu mysql "$BASH_SOURCE" "$@" fi # usage: file_env VAR [DEFAULT] # ie: file_env 'XYZ_DB_PASSWORD' 'example' # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) file_env() { local var="$1" local fileVar="${var}_FILE" local def="${2:-}" if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then mysql_error "Both $var and $fileVar are set (but are exclusive)" fi local val="$def" if [ "${!var:-}" ]; then val="${!var}" elif [ "${!fileVar:-}" ]; then val="$(< "${!fileVar}")" fi export "$var"="$val" unset "$fileVar" } # set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset # and make them the same value (so user scripts can use either) _mariadb_file_env() { local var="$1"; shift local maria="MARIADB_${var#MYSQL_}" file_env "$var" "$@" file_env "$maria" "${!var}" if [ "${!maria:-}" ]; then export "$var"="${!maria}" fi } # SQL escape the string $1 to be placed in a string literal. # escape, \ followed by ' docker_sql_escape_string_literal() { local newline=$'\n' local escaped=${1//\\/\\\\} escaped="${escaped//$newline/\\n}" echo "${escaped//\'/\\\'}" } mysql_get_config() { local conf="$1"; shift mysqld --verbose --help 2>/dev/null \ | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' } # Build env vars DATADIR="$(mysql_get_config 'datadir')" SOCKET="$(mysql_get_config 'socket')" _mariadb_file_env 'MYSQL_ROOT_HOST' '%' _mariadb_file_env 'MYSQL_ROOT_PASSWORD' : "${MARIADB_ALLOW_EMPTY_ROOT_PASSWORD:=${MYSQL_ALLOW_EMPTY_PASSWORD:-}}" export MYSQL_ALLOW_EMPTY_PASSWORD="$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" MARIADB_ALLOW_EMPTY_ROOT_PASSWORD : "${MARIADB_RANDOM_ROOT_PASSWORD:=${MYSQL_RANDOM_ROOT_PASSWORD:-}}" export MYSQL_RANDOM_ROOT_PASSWORD="$MARIADB_RANDOM_ROOT_PASSWORD" MARIADB_RANDOM_ROOT_PASSWORD : "${MARIADB_INITDB_SKIP_TZINFO:=${MYSQL_INITDB_SKIP_TZINFO:-}}" export MYSQL_INITDB_SKIP_TZINFO="$MARIADB_INITDB_SKIP_TZINFO" MARIADB_INITDB_SKIP_TZINFO if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' fi # Spin up temp server echo "Starting temporary MariaDB server..." mysqld --skip-networking --skip-grant-tables --socket="${SOCKET}" & echo "Waiting for server startup" for i in {30..0}; do if mysql --protocol=socket -hlocalhost -uroot --socket="${SOCKET}" --database=mysql <<<'SELECT 1'; then break fi sleep 1 done if [ "$i" = 0 ]; then echo "Unable to start temporary server." exit 1 fi # Try password reset echo "Resetting root password..." if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD echo "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" fi # Sets root password and creates root users for non-localhost hosts rootCreate= rootPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}" ) # default root to listen for connections from anywhere if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then # no, we don't care if read finds a terminating character in this heredoc # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 read -r -d '' rootCreate <<-EOSQL || true ALTER USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; EOSQL fi # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" --database=mysql --binary-mode <<-EOSQL FLUSH PRIVILEGES ; ALTER USER 'root'@'localhost' IDENTIFIED BY '${rootPasswordEscaped}' ; GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ; ${rootCreate} EOSQL echo "Password reset complete."