#!/bin/sh
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
# 
# start/stop script for mysqld
#
# Notes: In Solaris prior to Solaris 10 start/stop scripts are always executed by /bin/sh!
#
#        This script can run either as start/stop method in SMF called by svc.startd or
#        as start/stop script called manually by the user
#
#        use man smf_method for additional information regarding the SMF methods
#
#
# The code start, stop, and check the application is in the functions
#   start_application
#   stop_application
# and
#   check_application
#
#
# The script reads the following service properties if defined:
#   mysql/datadir
#   mysql/mysqld_binary
#   mysql/verbose
#
#
# Return codes if called manually
#
#     0 - everything okay (start/stop okay, status: the application is running)
#     1 - usage message printed and exit
#     2 - action not implemented yet
#   251 - script aborted by QUIT signal
#   252 - script aborted by CTRL-C
#   253 - script aborted by TERM signal
#   254 - script aborted by an unknown signal
#
#
#  Return codes if called from svc.startd (defined in /lib/svc/share/smf_include.sh) 
#
#    SMF_EXIT_OK=0
#      success
#
#    SMF_EXIT_ERR_FATAL=95
#      failed, administrative action required
#
#    SMF_EXIT_ERR_CONFIG=96
#       unrecoverable configuration error (e.g. a config file is missing)
#
#    SMF_EXIT_MON_DEGRADE=97
#       service is in degraded mode
#
#    SMF_EXIT_MON_OFFLINE=98
#       service is non-responsive and offline
#
#    SMF_EXIT_ERR_NOSMF=99
#       method called outside of SMF
#
#    SMF_EXIT_ERR_PERM=100
#       permission for the method missing
# 
# Environment variables defined in /lib/svc/share/smf_include.sh:
#
#  SMF_FMRI        
#   The service fault management resource  identifier  (FMRI) of the instance for which the
#   method is invoked.
#
#  SMF_METHOD      
#    The full method name of the method that is invoked
#
#  SMF_RESTARTER   
#    The service FMRI of the restarter that invokes the method
#
#
#  Method Tokens
#     A set of tokens are parsed  and  expanded  with  appropriate
#     values   from   the   method  invocation  by  the  restarter
#     svc.startd.  Other  restarters  might  not  support   method
#     tokens.   The   delegated   restarter   for  inet  services,
#     inetd(1M), does not support the following method expansions.
#
#     %%              %
#
#     %r              Name of the restarter, such as svc.startd
#
#     %m              Name of the method, such as start or stop
#
#     %s              Name of the service
#
#     %i              Name of the instance
#
#     %f              FMRI of the instance
#
#     %{prop[:,]}     Value(s) of a property. The prop might be  a
#                     property  FMRI,  a property group name and a
#                     property name separated by a /,  or  a  pro-
#                     perty   name  in  the  application  property
#                     group. These values can be followed by  a  ,
#                     (comma)  or  :   (colon).  If  present,  the
#                     separators are  used  to  separate  multiple
#                     e.g. %{start/user} 
#
#    Note that these tokens are only replaced with values if they are used 
#    in the command to call a method
#    e.g.
#   (bash):root@ferrari:/var/develop/script_templates # svcprop mysql | grep "start/exec"
#   start/exec astring /etc/my_smf_scripts/mysql.server\ start\ \"%r\ +\ \ %m\ +\ %s\ +\ %i\ +\ %f\ %{start/user}\ +\ %{start/group}\"\
#
#
# History: 
#   17.01.2006 /bs initial release
#   23.03.2006 /bs added support for Solaris 10 SMF
#
# Author
#   Bernd.Schemmer@gmx.de
#

# FMRI of the application (used if SMF is installed and the script is NOT called by svc.startd)
#
  __SVC_FMRI="svc:/application/mysql:default"

# name of the application to start/stop with this script (for messages only)
#
  __APPLICATION_NAME="mysqld"


# constants for true and false
  __TRUE=0
  __FALSE=1


# user that should execute this script ("" for don't care)
#
# Note: This variable is only evaluated if this script is called on a machine without running SMF!
#
  THIS_USER=""


# name of this script without the path
#
  __THISSCRIPT=` basename $0` 
  
#  change the name of the logfile to your need; use __LOGFILE=""
#  to suppress using a logfile at all
#
#  __LOGFILE="/var/tmp/${__THISSCRIPT}.log"
  __LOGFILE=""

# ---------------------------------------
#
# save the parameter
#
  __ACTION="$1"
  [ $# -ne 0 ] && shift
  __ACTION_PARAMETER="$*"

# ---------------------------------------
#
# predefined variables
#

# return code of the script
  __MAIN_RC=0

# variable to check for script aborts (for example because of a syntax error)
  __EXIT_VIA_DIE=${__FALSE}

#
# set __VERBOSE to __TRUE for debugging (use LogInfo for debugging messages)
#
  __VERBOSE=${__FALSE}
#  __VERBOSE=${__TRUE}


  __HOSTNAME=` uname -n `

  __OS=` uname -s `

# __OS_VERSION - Operating system version (e.g 5.9 or 5.10)
#
  __OS_VERSION=` uname -r `

  __RUNLEVEL=`who -r | tr -s " " | cut -f8 -d " " `

#
# set __USER_BREAK_ALLOWED to ${__FALSE} to suppress user aborts with CTRL-C
#
  __USER_BREAK_ALLOWED=${__TRUE}


# 
# return codes for the signal handler if the script is NOT called from svc.startd
#
  __QUIT_SIGNAL_RECEIVED_RC=251
  __BREAK_SIGNAL_RECEIVED_RC=252
  __TERM_SIGNAL_RECEIVED_RC=253
  __UNKNOWN_SIGNAL_RECEIVED_RC=254


# define the SMF return codes so that we can use them even if SMF is not installed
# or the variable names change in future releases
# If /lib/svc/share/smf_include.sh exists these variables will be overwritten by that script
#
  SMF_EXIT_OK=0
  SMF_EXIT_ERR_FATAL=95
  SMF_EXIT_ERR_CONFIG=96
  SMF_EXIT_MON_DEGRADE=97
  SMF_EXIT_MON_OFFLINE=98
  SMF_EXIT_ERR_NOSMF=99
  SMF_EXIT_ERR_PERM=100

  
# ---------------------------------------
#
# define variables here
#
# Note: Do not use leading underscores (__) for variable names -
#      these names are reserved for internal variables
#
 
# ---------------------------------------
#
# sub routines
#

# ---------------------------------------
#
# Usage: automatically called in the sub routine die
#
cleanup() {

  LogInfo "Doing house keeping ..."

## add code for house keeping here

  if [ ${__SMF_PRESENT} = 0  ] ; then

# script called from svc.startd
  
    case ${__ACTION} in

      start  )
          :
          ;;
          
      stop  )
          :
          ;;

      refresh )
          :
          ;;
          

      * )
          : Unknown action
          ;;
          
    esac

  else
  
# script called manually by a script or the user

    case ${__ACTION} in

      start | enable )
          :
          ;;
          
      stop | disable )
          :
          ;;

      restart )
          :
          ;;
          
      refresh )
          :
          ;;
          
      clear )
          :
          ;;
          
      mark )
          :
          ;;
          
      status )
          :
          ;;
          
      * )
          : Unknown action
          ;;
          
    esac
    
  fi
  
}

# ---------------------------------------
# 
# Usage: LogMsg [message]
#
LogMsg() {
  LogMsg_THISMSG="${__THISSCRIPT} - $*"
  echo "${LogMsg_THISMSG}"
  [ "${__LOGFILE}"x != ""x ] && echo "${LogMsg_THISMSG}" >>"${__LOGFILE}"
}

# ---------------------------------------
# 
# Usage: LogInfo [message]
#
# Note: LogInfo only prints messages if __VERBOSE is true
#
LogInfo() {
  [ ${__VERBOSE} -eq ${__TRUE} ] && LogMsg "INFO: $*"
}

# ---------------------------------------
#
# Usage: LogWarning [message]
#
LogWarning() {
  LogMsg "WARNING: $*!" 
}


# ---------------------------------------
#
# Usage: LogError [message]
#
# Note: Error messages are written to STDERR
#
LogError() {
  LogMsg "ERROR: $*!" >&2
}


# ---------------------------------------
#
# Usage: die [returncode] [message]
# 
die() {  
  die_THISRC=$1
  [ $# -ne 0 ] && shift
  die_THISMSG="$*"
  __EXIT_VIA_DIE=${__TRUE}

  cleanup

  if [ $# -ne 0 ] ; then
    if [ "${die_THISRC}"x = "0"x ] ; then
      LogMsg "${die_THISMSG}"
    else
      LogError "${die_THISMSG}"
    fi
  fi

  exit ${die_THISRC}
}


# ---------------------------------------
# GENERAL_SIGNAL_HANDLER
#
# general trap handler 
#
# usage: called automatically (parameter $1 is the signal number)
#
# returns: -
#
GENERAL_SIGNAL_HANDLER() {

  case $1 in 

    1 )
        LogInfo "HUP signal received."
        ;;

    2 )
        if [ ${__USER_BREAK_ALLOWED} -eq ${__TRUE} ] ; then
          die ${__BREAK_SIGNAL_RECEIVED_RC} "Script aborted by the user via signal BREAK (CTRL-C)" 
        else
          LogInfo "Break signal (CTRL-C) received and ignored (Break is disabled)."
        fi
        ;;

    3 )
        die ${__QUIT_SIGNAL_RECEIVED_RC} "QUIT signal received" 
        ;;

   15 )
        die ${__TERM_SIGNAL_RECEIVED_RC} "Script aborted by the external signal TERM" 
        ;;

   "exit" | 0 )
        if [ "${__EXIT_VIA_DIE}"x != "${__TRUE}"x ] ; then
          LogWarning "You should use the function \"die\" to end the program"
        fi    

        ;;
       
    * ) die ${__UNKNOWN_SIGNAL_RECEIVED_RC=} "Unknown signal catched: $1 "
        ;;

  esac
}


# ---------------------------------------
# PrintVariables
#
# for debugging only
#
PrintVariables() {
  
  for PrintVariables_CURVAR in __THISSCRIPT __LOGFILE __HOSTNAME __OS __OS_VERSION __RUNLEVEL ; do
    eval "PrintVariables_CURVALUE=\${${PrintVariables_CURVAR}}"
    LogInfo "${PrintVariables_CURVAR} is \"${PrintVariables_CURVALUE}\" "
  done

}

# ---------------------------------------
# sample subroutine
#
mysubroutine() {
  mysubroutine_THISRC=0

  return ${mysubroutine_THISRC}
}


# ---------------------------------------
# code to start the application 
#
start_application() {
  start_application_THISRC=${SMF_EXIT_OK}

  [ ${__SMF_PRESENT} = 0 ] && smf_clear_env

  if [ ${start_application_THISRC} = ${SMF_EXIT_OK} ] ; then
#
# mysql binary does not exist or is not executable
#
    [ ! -x "${MYSQLD_BINARY}" ] &&  start_application_THISRC=${SMF_EXIT_ERR_FATAL}
  fi

  if [ ${start_application_THISRC} = ${SMF_EXIT_OK} ] ; then
#
# mysql data dir does not exist 
#
    [ ! -d "${MYSQLD_DATA_DIR}" ] && start_application_THISRC=${SMF_EXIT_ERR_CONFIG}
  fi
  
  if [ ${start_application_THISRC} = ${SMF_EXIT_OK} ] ; then
    LogMsg "Starting ${__APPLICATION_NAME} ..." 
    ${MYSQLD_BINARY} & 
    if [ $? -eq 0 ] ; then 
      start_application_THISRC=${SMF_EXIT_OK}
    else
      start_application_THISRC=${SMF_EXIT_ERR_FATAL}
    fi
  fi
  
  return ${start_application_THISRC}
}

# ---------------------------------------
# code to stop the application 
#
stop_application() {
  stop_application_THISRC=0
  LogMsg "Stopping ${__APPLICATION_NAME} (PID is ${PROCESS_PID}) ..." 

  [ ${__SMF_PRESENT} = 0 ] && smf_clear_env

  kill ${PROCESS_PID}
  stop_application_THISRC=${SMF_EXIT_OK}

  return ${stop_application_THISRC}
}



# ---------------------------------------
# code to stop the application 
#
check_application() {

# ??? sample code to get the PID of a process:
#
#  PROCESS_NAME="..."
#  PROCESS_PID=` ps -ef | grep ${PROCESS_NAME} | grep -v grep | awk '{print $2}' `
#  [ "${PROCESS_PID}"x != ""x ] && PROCESS_RUNNING=${__TRUE} || PROCESS_RUNNING=${__FALSE}
#
# or use
#
#  PROCESS_PID=` pgrep ${PROCESS_NAME} `
#  [ "${PROCESS_PID}"x != ""x ] && PROCESS_RUNNING=${__TRUE} || PROCESS_RUNNING=${__FALSE}
#

  PID_FILE="${MYSQLD_PID_FILE}"
  [ -f ${PID_FILE} ]  && PROCESS_PID=` cat ${PID_FILE} `
  [ "${PROCESS_PID}"x != ""x ] && PROCESS_PID=`/usr/bin/ps -p ${PROCESS_PID} -o pid=`
  [ "${PROCESS_PID}"x != ""x ] && PROCESS_RUNNING=${__TRUE} || PROCESS_RUNNING=${__FALSE} 

  return ${PROCESS_RUNNING}
}

# -------------------------------------------------------------------------------------------------
#
# main code
#

# install trap handler
  trap "GENERAL_SIGNAL_HANDLER  1"  1
  trap "GENERAL_SIGNAL_HANDLER  2"  2
  trap "GENERAL_SIGNAL_HANDLER  3"  3
  trap "GENERAL_SIGNAL_HANDLER 15" 15
  trap "GENERAL_SIGNAL_HANDLER exit" 0

# -------------------------------------------------------------------------------------------------

# check the logfile
  if [ "${__LOGFILE}"x != ""x ] ; then
    touch "${__LOGFILE}"
    [ $? -ne 0 ] && __LOGFILE=""
  fi

# -------------------------------------------------------------------------------------------------


# ---------------------------------------
# check if we are called by the SMF or manually
#
# results:
#   __SMF_PRESENT = 0 -> SMF exists and script is called from within SMF
#   __SMF_PRESENT = 1 -> SMF exists but script is NOT called from within SMF
#   __SMF_PRESENT = 2 -> SMF does not exist
#

  __SMF_INCLUDE_SCRIPT="/lib/svc/share/smf_include.sh"
  __SMF_PRESENT=2
  if [ -f "${__SMF_INCLUDE_SCRIPT}" ] ; then
    . "${__SMF_INCLUDE_SCRIPT}"
    smf_present && __SMF_PRESENT=1
    if [ "${SMF_FMRI}"x != ""x ] ; then

# the script is called from the svc.startd
      __SMF_PRESENT=0

# read the properties from the service definition
      [ "`svcprop -p mysql/verbose ${SMF_FMRI} 2>/dev/null`"x = "true"x ] && __VERBOSE=${__TRUE}

      LogMsg "Reading the values from the service definition ..."

      svcprop -q -p mysql/datadir "${SMF_FMRI}"
      if [ $? -eq 0 ] ; then
        MYSQLD_DATA_DIR=` svcprop -p mysql/datadir "${SMF_FMRI}"` 
        LogMsg "MYSQL data dir is \"${MYSQLD_DATA_DIR}\""
      fi

      svcprop -q -p mysql/mysqld_binary "${SMF_FMRI}"
      if [ $? -eq 0 ] ; then
        MYSQLD_BINARY=` svcprop -p mysql/mysqld_binary "${SMF_FMRI}"` 
        LogMsg "MYSQL binary is \"${MYSQLD_BINARY}\""
      fi

#
# redefine the return codes for the signal handler
#
      __QUIT_SIGNAL_RECEIVED_RC=${SMF_EXIT_ERR_FATAL}
      __BREAK_SIGNAL_RECEIVED_RC=${SMF_EXIT_ERR_FATAL}
      __TERM_SIGNAL_RECEIVED_RC=${SMF_EXIT_ERR_FATAL}
      __UNKNOWN_SIGNAL_RECEIVED_RC=${SMF_EXIT_ERR_FATAL}

    fi   
  fi

# ---------------------------------------
# restart the script as specified user if required
#
# Note: Use the approbiate service configuration to start the script
#       under a specific user account if called from within SMF!
#
  if [ "${__SMF_PRESENT}"x != "0"x -a "${THIS_USER}"x != ""x ] ; then
    if [ "`/usr/ucb/whoami`"x != "${THIS_USER}"x ] ; then
      LogInfo "Restarting the script as user \"${THIS_USER}\" ..."
      su - "${THIS_USER}" -c "cd ` pwd` ; $0 $*"
      exit $?
    fi
  fi

# -------------------------------------------------------------------------------------------------


# use the default for MYSQLD_BINARY if the value is not defined in the service definition
#
  if [ "${MYSQLD_BINARY}"x = ""x ] ; then
    MYSQLD_BINARY="/usr/local/libexec/mysqld"
    if [ ! -x "${MYSQLD_BINARY}" ] ; then
      MYSQLD_BINARY="/opt/mysql/mysql/libexec/mysqld"
    fi
  fi
 
# use the default for MYSQLD_DATA_DIR if the value is not defined in the service definition
#
  [ "${MYSQLD_DATA_DIR}"x = ""x ] && MYSQLD_DATA_DIR="/var/applications/mysql"
  MYSQLD_PID_FILE="${MYSQLD_DATA_DIR}/` hostname `.pid"
 

# -------------------------------------------------------------------------------------------------
# for debugging only

  LogInfo "Action is \"${__ACTION}\""
  LogInfo "Actionparameter are \"${__ACTION_PARAMETER}\""

  if [ ${__SMF_PRESENT} = 0  ] ; then
#
# the script is called from the svc.startd
#
    LogInfo "SMF_FMRI is \"${SMF_FMRI}\""
    LogInfo "SMF_METHOD is \"${SMF_METHOD}\""
    LogInfo "SMF_RESTARTER is \"${SMF_RESTARTER}\""    
  fi
  
# -------------------------------------------------------------------------------------------------

  if [ ${__SMF_PRESENT} = 1  ] ; then

# -------------------------------------------------------------------------------------------------
# SMF installed but not called from SMF -> use SMF commands
#
    SVC_STATUS=`svcs -Ho state ${__SVC_FMRI} `
     
    case ${__ACTION} in

      start | enable ) 
        if [ "${SVC_STATUS}"x != "disabled"x ] ; then
          LogMsg "${__APPLICATION_NAME} not disabled "
          __MAIN_RC=1
        else	
          LogMsg "Starting ${__APPLICATION_NAME} ..." 
          svcadm enable -s "${__SVC_FMRI}"
          __MAIN_RC=$?
        fi
        ;;

      restart ) 
        svcadm restart  "${__SVC_FMRI}"
        __MAIN_RC=$?
        ;;

      refresh ) 
        svcadm refresh  "${__SVC_FMRI}"
        __MAIN_RC=$?
        ;;

      clear ) 
        if [ "${SVC_STATUS}"x != "maintenance"x ] ; then
          LogMsg "${__APPLICATION_NAME} not in maintenance "
          __MAIN_RC=1
        else	
          svcadm clear  "${__SVC_FMRI}"
          __MAIN_RC=$?
        fi
        ;;

      mark )
        MARK_NAME="${__ACTION_PARAMETER:=maintenance}"
    
        svcadm mark ${MARK_NAME} "${__SVC_FMRI}"
        __MAIN_RC=$?
        ;;

      status )
        if [ "${SVC_STATUS}"x != "online"x -a "${SVC_STATUS}"x != "degraded"x ] ; then
          LogMsg "${__APPLICATION_NAME} not running"
          __MAIN_RC=1
        else	
          LogMsg "${__APPLICATION_NAME} is running" 
          __MAIN_RC=0
        fi
        ;;

      stop | disable )
        if [ "${SVC_STATUS}"x != "online"x -a "${SVC_STATUS}"x != "degraded"x ] ; then
          LogMsg "${__APPLICATION_NAME} is not running"
          __MAIN_RC=0
        else	
          LogMsg "Stopping ${__APPLICATION_NAME} ..." 
          svcadm disable -s "${__SVC_FMRI}"
          __MAIN_RC=$?
        fi
        ;;

      * ) 
        LogMsg "Usage: ${__THISSCRIPT} [start|stop|status|refresh|restart|clear|mark]"
        __MAIN_RC=1
        ;;

    esac

    NEW_SVC_STATUS=`svcs -Ho state "${__SVC_FMRI}" `
    LogMsg "The status of the application is \"${NEW_SVC_STATUS}\""

else

# -------------------------------------------------------------------------------------------------
# called from the SMF daemon svc.startd or manual and no SMF is running
#

# check if the application is running
    check_application

    case ${__ACTION} in

      start ) 
        if [ ${PROCESS_RUNNING} = ${__TRUE} ] ; then
          __MAIN_RC=${SMF_EXIT_OK}
        else
          start_application
          __MAIN_RC=$?
        fi
        ;;

      refresh )
# Note: DO NOT KILL THE PROCESS IN THE REFRESH METHOD!
        die ${SMF_EXIT_ERR_FATAL} "Method Refresh not implemented yet"
        ;;

      stop )
        if [ ${PROCESS_RUNNING} = ${__TRUE} ] ; then
          stop_application
          __MAIN_RC=$?
        else
          LogMsg "${__APPLICATION_NAME} is not running"
          __MAIN_RC=${SMF_EXIT_OK}
        fi     
        ;;

      * ) 
        die ${SMF_EXIT_ERR_FATAL} "Method \"${__ACTION}\" not implemented yet"
        ;;

    esac
  fi

# ---------------------------------------
 
  die ${__MAIN_RC}

# ---------------------------------------

