#!/bin/bash
#
# mysqld	This shell script takes care of starting and stopping
#		the MySQL subsystem (mysqld).
#
# chkconfig: 345 78 12
# description:	MySQL database server.
# processname: mysqld
# config: /etc/my.cnf
# pidfile: /var/run/mysqld_app_init/mysqld.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Source subsystem configuration.
[ -f /etc/sysconfig/subsys/mysqld ] && . /etc/sysconfig/subsys/mysqld


#################### start of import from mysql.lib ###########################

MYSQL_ITER_MAGIC_NUMBER=40
MYSQL_WAIT_MAGIC_NUMBER=3
MYSQL_SKIP_VERIFY_RUNNING=""
MYSQL_SINGLE_DAEMON="1"
PID_FILE=/var/run/mysqld_app_init/mysqld.pid

if [ -e /usr/libexec/mysqld ]; then
    # mysql.org RPMs
    MYSQLD=/usr/libexec/mysqld
elif [ -e /usr/sbin/mysqld ]; then
    # Redhat/Fedora RPMs
    MYSQLD=/usr/sbin/mysqld
else
    # unknown
    MYSQLD=mysqld
fi

MY_TMP_FILE=/tmp/tmpmysql.$$
MY_CNF_FILE=/etc/my.cnf
TMPL_MY_CNF_FILE=/etc/virtualhosting/templates/mysql/etc/my.cnf
TMPL_MYSQL_SOCK_FILE=/home/virtual/FILESYSTEMTEMPLATE/.mysqlsock/mysql.sock
ADMIN_SOCK_FILE=`my_print_defaults -c /etc/my.cnf.admin_appl mysqld | egrep "^--socket=" | cut -d '=' -f2`


if [ x"$1" = x"admin" ]; then
    MY_PRINT_CNF_FILE="-c /etc/my.cnf.admin_appl"
else
    MY_PRINT_CNF_FILE="-c /etc/my.cnf"
fi

function commit_tmp_change() {
  mv -f $MY_TMP_FILE.new $MY_TMP_FILE
}

function remove_socket_entry() {
  cat $MY_TMP_FILE | egrep -v "^[\ \t]*socket[\ \t]*=.*" > $MY_TMP_FILE.new
  commit_tmp_change
}

function remove_host_entry() {
  cat $MY_TMP_FILE | egrep -v "^[\ \t]*host[\ \t]*=.*" > $MY_TMP_FILE.new
  commit_tmp_change
}

function update_ini_group() {
  HAS_INI_GROUP=`egrep "^[\ \t]*\[$1\]" $MY_TMP_FILE`
  if [ x"$HAS_INI_GROUP" = x"" ]; then
    echo "[$1]
socket=$2" >> $MY_TMP_FILE
  else
    sed '/[\ \t]*\['$1'\]/ a \
socket='$2 $MY_TMP_FILE > $MY_TMP_FILE.new
    commit_tmp_change
  fi
}

function update_my_cnf() {
  rm -f $MY_TMP_FILE
  cp -f $MY_CNF_FILE $MY_TMP_FILE
  remove_socket_entry
  update_ini_group mysqld $TMPL_MYSQL_SOCK_FILE
  update_ini_group client $TMPL_MYSQL_SOCK_FILE
  cp -f $MY_TMP_FILE $MY_CNF_FILE
  rm -f $MY_TMP_FILE
}

function remove_virt_hardlinks() {
    local SITES=`find /home/virtual  -type d -maxdepth 1 | egrep "/site[0-9]+"`
    local SITERETVAL=$?
    if [ $SITERETVAL -eq 0 ]; then
        for site_root in $SITES
        do
            IS_MYSQL_ENABLED=`egrep '^[[:space:]]*enabled[[:space:]]*=[[:space:]]*1$' $site_root/info/current/mysql`
            if [ x"$IS_MYSQL_ENABLED" = x"" ]; then
                :
            else
                rm -f $site_root/fst/var/lib/mysql/mysql.sock
            fi
        done
    else
        /sbin/initlog -f local1 -p info \
            -s "mysqld init failed to exec sitelookup"
    fi
}

function create_virt_hardlinks() {
    local SITES=`find /home/virtual  -type d -maxdepth 1 | egrep "/site[0-9]+"`
    local SITERETVAL=$?
    if [ $SITERETVAL -eq 0 ]; then
        for site_root in $SITES
        do
            IS_MYSQL_ENABLED=`egrep '^[[:space:]]*enabled[[:space:]]*=[[:space:]]*1$' $site_root/info/current/mysql`
            if [ x"$IS_MYSQL_ENABLED" = x"" ]; then
                :
            else
                rm -f $site_root/fst/var/lib/mysql/mysql.sock
                /sbin/initlog -f local1 -p info -c "ln $TMPL_MYSQL_SOCK_FILE $site_root/fst/var/lib/mysql/mysql.sock"
            fi
        done
    else
        /sbin/initlog -f local1 -p info \
            -s "mysqld init failed to exec sitelookup"
    fi
}

# Attempt telnet connection to check mysql status on port 3306
# RETURNS: 0 = up, 1 = down
function check_telnet
{
	local stat
        
        hostname=$(/bin/hostname -i)
	telnet 127.0.0.1 3306 > /tmp/mysqlstatus.$$ 2>&1 << "EOF"
a001 LOGOUT
EOF

	# Did we get connected string
	grep "Connected to" /tmp/mysqlstatus.$$ > /dev/null 2>&1
	stat=$?
	rm /tmp/mysqlstatus.$$
	return $stat
}

# Wait for MySQL to stop answering telnet connections.
function wait_telnet
{
	local stat=0
	local cnt=0
	local max=$MYSQL_ITER_MAGIC_NUMBER

	while [ $cnt -lt $max ]; do
		check_telnet
		if [ $? -ne 0 ]; then
			return 0
		fi
		let cnt=cnt+1
		sleep $MYSQL_WAIT_MAGIC_NUMBER
	done
        /sbin/initlog -n mysqld_app_init -s \
		"Stopping MySQL: Still answering telnet connections..."
	return 1
}

# Check for mysql.sock file
# RETURNS: 0 = up, 1 = down
function check_sock
{
        local sock_path
        sock_path=`my_print_defaults $MY_PRINT_CNF_FILE mysqld | egrep "^--socket=" | cut -d '=' -f2`
	if [ -S $sock_path ]; then
		return 0
	fi
	return 1
}

# Wait for sock file to appear.
function wear_sock
{
	local stat=0
	local cnt=0
	local max=$MYSQL_ITER_MAGIC_NUMBER

	while [ $cnt -lt $max ]; do
		check_sock
		if [ $? -eq 0 ]; then
			return 0
		fi
		let cnt=cnt+1
		sleep $MYSQL_WAIT_MAGIC_NUMBER
	done
        /sbin/initlog -n mysqld_app_init -s \
		"Stopping MySQL: Socket file still hasn't appeared..."
	return 1
}

# Wait for sock file to disappear.
function wait_sock
{
	local stat=0
	local cnt=0
	local max=$MYSQL_ITER_MAGIC_NUMBER

	while [ $cnt -lt $max ]; do
		check_sock
		if [ $? -ne 0 ]; then
			return 0
		fi
		let cnt=cnt+1
		sleep $MYSQL_WAIT_MAGIC_NUMBER
	done
        /sbin/initlog -n mysqld_app_init -s \
		"Stopping MySQL: Socket file is still around..."
	return 1
}

# Check if there are any MySQL processes running
# RETURNS: 0 = up, 1 = down
function check_procs
{
	# See if mysql is running based on the output of ps.
	mysqlproc=`ps ax -o cmd | grep ^$MYSQLD`
        if [ -n "$mysqlproc" ]; then
		return 0
        else
                return 1
        fi
}

# Wait for the MySQL processes to disappear
function wait_procs
{
	local stat=0
	local cnt=0
	local max=$MYSQL_ITER_MAGIC_NUMBER

	while [ $cnt -lt $max ]; do
		check_procs
		if [ $? -ne 0 ]; then
			return 0
		fi
		let cnt=cnt+1
		sleep $MYSQL_WAIT_MAGIC_NUMBER
	done
        /sbin/initlog -n mysqld_app_init -s \
		"Stopping MySQL: Some processes are still around..."
	return 1
}

# Verify MySQL is up
function verify_running
{
	if [ "$MYSQL_SKIP_VERIFY_RUNNING" ]; then
		return 0
	fi

	local stat1
	local stat2

	check_telnet
	stat1=$?
	check_sock
	stat2=$?

	if [ "$stat1" != "0" ] && [ "$stat2" != "0" ] ; then
		return 1
	elif [ "$stat1" = "0" ] && [ "$stat2" = "0" ] ; then
		return 0
	else
		# This is an error condition.  We received conflicting
	        # reports as to up status of MySQL
		return 2
	fi
}
##################### end of import from mysql.lib ############################


prog="MySQL"
SAFE_MYSQLD_OPTIONS="--defaults-file=/etc/my.cnf --pid-file=$PID_FILE"

start(){
        local sock_path
	touch /var/log/mysqld.log
	chown mysql.mysql /var/log/mysqld.log 
	chmod 0640 /var/log/mysqld.log
	if [ ! -d /var/lib/mysql/mysql ] ; then
	    action $"Initializing MySQL database: " /usr/bin/mysql_install_db
	    ret=$?
	    chown -R mysql.mysql /var/lib/mysql
	    if [ $ret -ne 0 ] ; then
	    	return $ret
	    fi
	fi
	chown mysql.mysql /var/lib/mysql
	chmod 0755 /var/lib/mysql

	update_my_cnf

        sock_path=`my_print_defaults $MY_PRINT_CNF_FILE mysqld | egrep "^--socket=" | cut -d '=' -f2`

	mkdir -p `dirname $sock_path`
	chown mysql:mysql `dirname $sock_path`
	chmod 0755 `dirname $sock_path`

	/usr/bin/safe_mysqld $SAFE_MYSQLD_OPTIONS  >/dev/null 2>&1 &
	ret=$?
	if [ $ret -eq 0 ]; then
	    touch /var/lock/subsys/mysqld

	    # Wait for sock to appear
	    wear_sock
	    if [ $? -ne 0 ]; then
		# This is bad problem if sock does not appear.
		action $"Starting $prog: " /bin/false
		return 1
	    fi
		    
	    # Do a full status check
      	    # PR# 31208
            # If the system was crash, mysql server start up process delay for some time.
            # So do the verification in a 5-loop with sleep of 1 sec.
            for (( i=1; $i <= 5; i++ ))
            do
                verify_running
                ret=$?
                if [ $ret -eq 0 ]; then
                        break
                fi
                sleep 1
            done
            if [ $ret -ne 0 ]; then
		action $"Starting $prog: " /bin/false
		return 1
	    fi

	    action $"Starting $prog: " /bin/true
	else
    	    action $"Starting $prog: " /bin/false
	fi
	chown root.mysql /var/lib/mysql

        if [ x"$sock_path" != x"$ADMIN_SOCK_FILE" ]; then
           rm -f /var/lib/mysql/mysql.sock
           ln -s $TMPL_MYSQL_SOCK_FILE /var/lib/mysql/mysql.sock
           create_virt_hardlinks
        fi

	return $ret
}

stop(){
	# A really paranoid, thorough, patient stop. 
        # See PRs 20077, 23203, 25559, 25985

	# MySQL doesn't appear to unlink the socket so we can't use
	# that as a sign that it died.

	# If MYSQL_SINGLE_DAEMON is not set, then we assume multiple
	# daemons may be running and we cannot be as thorough (cannot
	# use killall, cannot wait for all mysqld processes to
	# disappear).

	# Stage 1: Tell the MySQL process(es) that we wish them dead.

        # Stage 1.1: First try using the pid file, if it's there.

        if [ -f $PID_FILE ]; then
            /bin/kill `cat $PID_FILE 2>/dev/null` \
                >/dev/null 2>&1
            ret=$?
            if [ $ret -ne 0 ]; then
                /sbin/initlog -n mysqld_app_init -s \
                    "Stopping MySQL:  Failed to kill mysqld process"
            fi
        else
            # We couldn't find the pid file
            /sbin/initlog -n mysqld_app_init -s \
                "Stopping MySQL:  Failed to find pid file"
            ret=1
        fi

	# Stage 1.2: Try killall if we couldn't kill the single pid.
        if [ $ret -ne 0 ] && [ "$MYSQL_SINGLE_DAEMON" ]; then
            # We either couldn't find the pid file, or the kill failed
            # for some reason. The return code from killall doesn't
            # tell us what happened so assume, for now, it worked.
            /sbin/initlog -n mysqld_app_init -s \
                "Stopping MySQL:  Falling back to killall"
            /usr/bin/killall $MYSQLD 2>/dev/null
            ret=0    
        fi

	if [ $ret -ne 0 ]; then
	    # Stage 1 failed
	    action $"Stopping $prog: " /bin/false
	    return $ret
	fi

	# Stage 2: Make sure MySQL stops answering telnet connections.

	# Stage 2.1: Wait for a while, give it a chance to shut up.
	wait_telnet
	ret=$?

	# Stage 2.2: If it's not shutting up, try a killall.
        if [ $ret -ne 0 ] && [ "$MYSQL_SINGLE_DAEMON" ]; then
	    # If we thought that killing by pid succeeded above, then
	    # killall might help. If we already tried that, it doesn't
	    # hurt to try it one last time.
            /sbin/initlog -n mysqld_app_init -s \
                "Stopping MySQL:  Trying killall"
            /usr/bin/killall $MYSQLD 2>/dev/null

	    # Now hope the socket disappears
	    wait_telnet
	    ret=$?
	fi

	if [ $ret -ne 0 ]; then
	    # Stage 2 failed
	    action $"Stopping $prog: " /bin/false
	    return $ret
	fi

	# Stage 3: Make sure all MySQL processes die away.
        if [ "$MYSQL_SINGLE_DAEMON" ]; then
	    wait_procs
	    ret=$?
	fi

	if [ $ret -ne 0 ]; then
	    # Stage 3 failed
	    action $"Stopping $prog: " /bin/false
	    return $ret
	fi

	# Woohooooo!!!!
	rm -f /var/lock/subsys/mysqld 
	rm -f /var/lib/mysql/mysql.sock /var/lib/mysql/admin_appl/mysql.sock \
	      $TMPL_MYSQL_SOCK_FILE
	remove_virt_hardlinks
	action $"Stopping $prog: " /bin/true
	return $ret
}

condstart(){
    verify_running || restart
}
 
restart(){
    stop
    sleep $MYSQL_WAIT_MAGIC_NUMBER
    start
}

condrestart(){
    [ -e /var/lock/subsys/mysqld ] && restart || :
}

reload(){
    [ -e /var/lock/subsys/mysqld ] && mysqladmin reload
}

status_mysqld() {
    verify_running
    stat=$?

    if [ "$stat" = "0" ] ; then
	echo "mysql is running"
	return 0
    elif [ "$stat" = "1" ] ; then
	echo "mysql is stopped"
	return 0
    else
	echo "conflicting reports, assuming mysql is stopped"
	return 1
    fi
}

admin(){
    stop
    
    # sock file for admin mode is different
    MYSQL_ADMIN_DIR="/var/lib/mysql/admin_appl"
    MYSQL_SOCK_FILE="${MYSQL_ADMIN_DIR}/mysql.sock"

    # Make sure directory exists and has proper owners
    if [ ! -d $MYSQL_ADMIN_DIR ]; then 
        mkdir -m 0700 $MYSQL_ADMIN_DIR
	if [ $? != 0 ]; then
	   /sbin/initlog -s "mysqld: [warning] Failed to create directory $MYSQL_ADMIN_DIR" 
	fi
    fi
    chown mysql:mysql $MYSQL_ADMIN_DIR

    # don't have to do telnet test since we are connecting via 
    # unix domain socket
    MYSQL_SKIP_VERIFY_RUNNING="1" 

    # admin mode options
    SAFE_MYSQLD_OPTIONS="--defaults-file=/etc/my.cnf.admin_appl --skip-grant-tables --skip-networking"

    # make output nicer
    prog="$prog""in maintenance mode"

    start
    ret=$?

    return $?
}

# See how we were called.
case "$1" in
  start)
    start
    ;;
  admin)
    admin
    ;;
  stop)
    stop
    ;;
  status)
    status_mysqld
    ;;
  reload)
    reload
    ;;
  restart)
    restart
    ;;
  condrestart)
    condrestart
    ;;
  condstart)
    condstart
    ;;
  *)
    echo $"Usage: $0 {start|admin|stop|status|reload|condrestart|restart}"
    exit 1
esac

exit $?
