#!/bin/bash die() { echo "$1" exit 1 } # Read options from config file read_config() { # Initial settings MYSQLVER="$(echo @MYSQLVER@ | sed 's|\.[0-9]\+$||')" mysql_daemon_user=mysql mysql_daemon_group=mysql # status information directory (e.g. info about a necessity of upgrade, current version etc) mariadb_status_dir="/var/lib/misc" if [[ -z "$INSTANCE" ]]; then datadir=/var/lib/mysql socket="/run/mysql/mysql.sock" else datadir="/var/lib/mysql-$INSTANCE" socket="/run/mysql/mysql.${INSTANCE}.sock" fi # Read options - important for multi setup if [[ -n "$INSTANCE" ]]; then opts="$(/usr/bin/my_print_defaults --defaults-extra-file=/etc/my${INSTANCE}.cnf mysqld mysqld_multi "$INSTANCE")" tmp_opts="$opts" config="/etc/my${INSTANCE}.cnf" else opts="$(/usr/bin/my_print_defaults mysqld)" tmp_opts="$opts" config="/etc/my.cnf" fi # Update local variables according to the settings from config for arg in $tmp_opts; do case "$arg" in --basedir=*) basedir="$(echo "$arg" | sed -e 's/^[^=]*=//')" ;; --socket=*) socket="$(echo "$arg" | sed -e 's/^[^=]*=//')" ;; --datadir=*) datadir="$(echo "$arg" | sed -e 's/^[^=]*=//')" ;; --user=*) mysql_daemon_user="$(echo "$arg" | sed -e 's/^[^=]*=//')" ;; --group=*) mysql_daemon_group="$(echo "$arg" | sed -e 's/^[^=]*=//')" ;; esac done # work-around for lost+found directory in $datadir (bug #986251) if [ -d "$datadir/lost+found" ] then ignore_db_dir="--ignore-db-dir=lost+found" else ignore_db_dir="" fi } # Create new empty database if needed mysql_install() { if [[ ! -d "$datadir/mysql" ]]; then echo "Creating MySQL privilege database... " mysql_install_db --rpm --user="$mysql_daemon_user" --datadir="$datadir" || \ die "Creation of MySQL database in $datadir failed" echo -n "$MYSQLVER" > "$mariadb_status_dir"/mariadb_upgrade_info fi } # Upgrade database if needed mysql_upgrade() { # Run mysql_upgrade on every package install/upgrade. Not always # necessary, but doesn't do any harm. if [[ -f "$mariadb_status_dir/.mariadb_run_upgrade" ]]; then echo "Checking MySQL configuration for obsolete options..." sed -i -e 's|^\([[:blank:]]*\)skip-locking|\1skip-external-locking|' \ -e 's|^\([[:blank:]]*skip-federated\)|#\1|' /etc/my.cnf # instead of running mysqld --bootstrap, which wouldn't allow # us to run mysql_upgrade, we start a full-featured server with # --skip-grant-tables and restict access to it by unix # permissions of the named socket echo "Trying to run upgrade of MySQL databases..." # Check whether upgrade process is not already running protected="$(cat "/run/mysql/protecteddir.$INSTANCE" 2> /dev/null)" if [[ -n "$protected" && -d "$protected" ]]; then pid="$(cat "$protected/mysqld.pid" 2> /dev/null)" if [[ "$pid" && -d "/proc/$pid" ]] && [[ $(readlink "/proc/$pid/exe" | grep -q "mysql") ]]; then die "Another upgrade in already in progress!" else echo "Stale files from previous upgrade detected, cleaned them up" rm -rf "$protected" rm -f "/run/mysql/protecteddir.$INSTANCE" fi fi protected="$(mktemp -d -p /var/tmp mysql-protected.XXXXXX | tee "/run/mysql/protecteddir.$INSTANCE")" [ -n "$protected" ] || die "Can't create a tmp dir '$protected'" # Create a secure tmp dir chown --no-dereference "$mysql_daemon_user:$mysql_daemon_group" "$protected" || die "Failed to set group/user to '$protected'" chmod 0700 "$protected" || die "Failed to set permissions to '$protected'" # Run protected MySQL accessible only though socket in our directory echo "Running protected MySQL... " /usr/sbin/mysqld \ --defaults-file="$config" \ --user="$mysql_daemon_user" \ --skip-networking \ --skip-grant-tables \ $ignore_db_dir \ --log-error="$protected/log_upgrade_run" \ --socket="$protected/mysql.sock" \ --pid-file="$protected/mysqld.pid" & mysql_wait "$protected/mysql.sock" || die "MySQL didn't start, can't continue" # Run upgrade itself echo "Running upgrade itself..." echo "It will do some chek first and report all errors and tries to correct them" echo if /usr/bin/mysql_upgrade --no-defaults --force --socket="$protected/mysql.sock"; then echo "Everything upgraded successfully" up_ok="" rm -f "$mariadb_status_dir/.mariadb_run_upgrade" [[ $(grep -q "^$MYSQLVER" "$mariadb_status_dir/mariadb_upgrade_info" 2> /dev/null) ]] || \ echo -n "$MYSQLVER" > "$mariadb_status_dir/mariadb_upgrade_info" else echo "Upgrade failed" up_ok="false" fi # Shut down MySQL echo "Shutting down protected MySQL" protected_pid=$(cat "$protected/mysqld.pid") kill $protected_pid for i in {1..30}; do /usr/bin/mysqladmin --socket="$protected/mysql.sock" ping > /dev/null 2>&1 # Check both ping response and the pid in a process list as it can take some time till the process is terminated. # Otherwise it can lead to "found left-over process" situation when regular mariadb is started. if [[ $? -eq 1 ]] && ! ps -p $protected_pid > /dev/null 2>&1; then break fi sleep 1 done /usr/bin/mysqladmin --socket="$protected/mysql.sock" ping > /dev/null 2>&1 && kill -9 $protected_pid # Cleanup echo "Final cleanup" if [[ -z "$up_ok" ]]; then rm -rf "$protected" "/run/mysql/protecteddir.$INSTANCE" else die "Something failed during upgrade, please check logs" fi fi } mysql_wait() { [[ -z "$1" ]] || socket="$1" echo "Waiting for MySQL to start" for i in {1..60}; do /usr/bin/mysqladmin --socket="$socket" ping > /dev/null 2>&1 && break sleep 1 done if /usr/bin/mysqladmin --socket="$socket" ping > /dev/null 2>&1; then echo "MySQL is alive" return 0 else echo "MySQL is still dead" return 1 fi } mysql_start() { exec /usr/sbin/mysqld \ --defaults-file="$config" \ $ignore_db_dir \ --user="$mysql_daemon_user" \ --socket="$socket" } # We rely on output in english at some points LC_ALL=C INSTANCE="$2" read_config # Make sure that /run/mysql is created and has correct permissions (bsc#1038740) systemd-tmpfiles --create /usr/lib/tmpfiles.d/mariadb.conf case "$1" in install) mysql_install ;; upgrade) mysql_upgrade ;; start) mysql_start ;; wait) mysql_wait ;; *) echo "Supported commands are:" echo " install - creates empty database if needed" echo " upgrade - tries to migrate data to newer version if needed" echo " start - tries to start instance" echo " wait - waits till instance is pingable" echo "All commands can take extra argument which is group from 'mysqld_multi' you want to work with" ;; esac