#!/bin/bash # vim:nu:ai:sw=4:ts=4:nowrap: # # Description: OCF compliant resource agent for Samba on Gentoo # Author: Wolfram Schlich # Support: mailto:wschlich@gentoo.org, xmpp:wschlich@jabber.laber.fasel.org # License: GNU General Public License, version 3 (GPLv3) # Copyright: (c) 2008 Wolfram Schlich # Revision: $Revision$ ($Date$) # # # TODO: # - consider fixing "TODO FIXME" objects # - consider switching from log() to ocf_log() # # # OCF resource parameters: # # OCF_RESKEY_smbd_enabled # OCF_RESKEY_smbd_bin # OCF_RESKEY_smbd_opts # OCF_RESKEY_smbd_pidfile # OCF_RESKEY_nmbd_enabled # OCF_RESKEY_nmbd_bin # OCF_RESKEY_nmbd_opts # OCF_RESKEY_nmbd_pidfile # OCF_RESKEY_winbindd_enabled # OCF_RESKEY_winbindd_bin # OCF_RESKEY_winbindd_opts # OCF_RESKEY_samba_config # OCF_RESKEY_testparm_bin # ## ## functions ## ## logs via syslog and optionally stderr function log() { local log_syslog_facility="daemon" local log_syslog_level="${1}"; shift local log_syslog_pri="${log_syslog_facility}.${log_syslog_level}" local log_syslog_tag="ocf-ra/${0##*/}[${$}]" # scriptname[PID] local logger_args= case "${log_syslog_level}" in err|crit|alert|emerg) ## log err|crit|alert|emerg messages to stderr as well #logger_args='-s' ;; debug) return 0 # comment this line to enable debug logging ;; *) ;; esac logger ${logger_args} -p "${log_syslog_pri}" -t "${log_syslog_tag}" \ -- " ${@}" # ocf_log ${log_syslog_level} "${@}" } ## exits and optionally logs a message function die() { local retval=${1:-1}; shift if [[ ${#} -gt 0 ]]; then if [[ ${retval} -ne 0 ]]; then log crit "${@}" else log notice "${@}" fi fi exit ${retval} } ## start all samba daemons function start_all_samba_daemons() { ## sum of all exitcodes local exitcode_sum declare -i exitcode_sum=0 ## taken from original samba init script on Gentoo unset TMP TMPDIR ## start smbd if enabled if [[ "${smbd_enabled}" -eq 1 ]]; then ${smbd_bin} -D -s "${samba_config}" ${smbd_opts} local smbd_exitcode; declare -i smbd_exitcode=${?} if [[ ${smbd_exitcode} -gt 0 ]]; then let exitcode_sum+=${smbd_exitcode} log err "${FUNCNAME}(): failed to start smbd -- exitcode: ${smbd_exitcode}" else log info "${FUNCNAME}(): smbd started successfully" fi fi ## start nmbd if enabled if [[ "${nmbd_enabled}" -eq 1 ]]; then ${nmbd_bin} -D -s "${samba_config}" ${nmbd_opts} local nmbd_exitcode; declare -i nmbd_exitcode=${?} if [[ ${nmbd_exitcode} -gt 0 ]]; then let exitcode_sum+=${nmbd_exitcode} log err "${FUNCNAME}(): failed to start nmbd -- exitcode: ${nmbd_exitcode}" else log info "${FUNCNAME}(): nmbd started successfully" fi fi ## start winbindd if enabled if [[ "${winbindd_enabled}" -eq 1 ]]; then ${winbindd_bin} -D -s "${samba_config}" ${winbindd_opts} local winbindd_exitcode; declare -i winbindd_exitcode=${?} if [[ ${winbindd_exitcode} -gt 0 ]]; then let exitcode_sum+=${winbindd_exitcode} log err "${FUNCNAME}(): failed to start winbindd -- exitcode: ${winbindd_exitcode}" else log info "${FUNCNAME}(): winbindd started successfully" fi fi ## check exitcodes if [[ ${exitcode_sum} -gt 0 ]]; then log err "${FUNCNAME}(): failed to start some samba daemons" return 1 else log info "${FUNCNAME}(): successfully started all samba daemons" return 0 fi } ## stop all samba daemons function stop_all_samba_daemons() { ## sum of all exitcodes local exitcode_sum declare -i exitcode_sum=0 ## taken from original samba init script on Gentoo unset TMP TMPDIR ## stop smbd if enabled if [[ "${smbd_enabled}" -eq 1 ]]; then log debug "${FUNCNAME}(): trying to stop smbd" killall smbd local smbd_exitcode; declare -i smbd_exitcode=${?} if [[ ${smbd_exitcode} -gt 0 ]]; then # let exitcode_sum+=${smbd_exitcode} ### We're using killall so forcefully making return +=0 log err "${FUNCNAME}(): failed to stop smbd -- exitcode: ${smbd_exitcode}" else log info "${FUNCNAME}(): smbd stopped successfully" fi fi ## stop nmbd if enabled if [[ "${nmbd_enabled}" -eq 1 ]]; then log debug "${FUNCNAME}(): trying to stop nmbd" killall nmbd local nmbd_exitcode; declare -i nmbd_exitcode=${?} if [[ ${nmbd_exitcode} -gt 0 ]]; then # let exitcode_sum+=${nmbd_exitcode} ### We're using killall so forcefully making return +=0 log err "${FUNCNAME}(): failed to stop nmbd -- exitcode: ${nmbd_exitcode}" else log info "${FUNCNAME}(): nmbd stopped successfully" fi fi ## stop winbindd if enabled if [[ "${winbindd_enabled}" -eq 1 ]]; then log debug "${FUNCNAME}(): trying to stop winbindd" killall winbindd local winbindd_exitcode; declare -i winbindd_exitcode=${?} if [[ ${winbindd_exitcode} -gt 0 ]]; then # let exitcode_sum+=${winbindd_exitcode} ### We're using killall so forcefully making return +=0 log err "${FUNCNAME}(): failed to stop winbindd -- exitcode: ${winbindd_exitcode}" else log info "${FUNCNAME}(): winbindd stopped successfully" fi fi ## check exitcodes if [[ ${exitcode_sum} -gt 0 ]]; then log err "${FUNCNAME}(): failed to stop some samba daemons" return 1 else log info "${FUNCNAME}(): successfully stopped all samba daemons" return 0 fi } ## checks if a single given samba daemon is running function check_samba_daemon_running() { local samba_daemon=${1} # smbd nmbd winbindd local samba_daemon_bin local samba_daemon_pidfile local samba_daemon_opts eval samba_daemon_bin=\$${samba_daemon}_bin eval samba_daemon_pidfile=\$${samba_daemon}_pidfile eval samba_daemon_opts=\$${samba_daemon}_opts local samba_daemon_pid; declare -i samba_daemon_pid=0 local samba_daemon_pid_list; declare -a samba_daemon_pid_list local samba_daemon_cmdline ## check pidfile first if [[ -n "${samba_daemon_pidfile}" && -e "${samba_daemon_pidfile}" ]]; then ## read PID from pidfile set -- $(<"${samba_daemon_pidfile}") let samba_daemon_pid=${1} set -- if [[ ${samba_daemon_pid} -eq 0 ]]; then ## pidfile does not contain a PID log debug "${FUNCNAME}(): samba_daemon_pidfile does not contain a (valid) PID" ## fall through to process search below elif [[ ! -d /proc/${samba_daemon_pid} ]]; then log debug "${FUNCNAME}(): ${samba_daemon} is not running with PID ${samba_daemon_pid} contained in samba_daemon_pidfile" ## fall through to process search below else declare -a samba_daemon_pid_list=(${samba_daemon_pid}) log debug "${FUNCNAME}(): ${samba_daemon} PID from samba_daemon_pidfile: ${samba_daemon_pid}" fi fi ## well, no PID was found so far, but maybe a matching ## process is running nonetheless... search for one! if [[ "${#samba_daemon_pid_list[@]}" -eq 0 ]]; then declare -a samba_daemon_pid_list=($(pgrep -x "${samba_daemon_bin##*/}" 2>/dev/null)) if [[ "${#samba_daemon_pid_list[@]}" -eq 0 ]]; then log debug "${FUNCNAME}(): failed to find any running ${samba_daemon} process" return 1 fi log debug "${FUNCNAME}(): ${samba_daemon} PID list from process search: ${samba_daemon_pid_list[@]}" fi ## loop through list of samba_daemon PIDs for samba_daemon_pid in ${samba_daemon_pid_list[@]}; do log debug "${FUNCNAME}(): checking PID ${samba_daemon_pid}" ## check whether the process that is contained in the pidfile is really the samba_daemon binary local running_exe=$(readlink -f /proc/${samba_daemon_pid}/exe 2>/dev/null) log debug "${FUNCNAME}(): running_exe: ${running_exe}" if [[ -z ${running_exe} ]]; then log debug "${FUNCNAME}(): failed to check exe of process with PID ${samba_daemon_pid}" return 1 elif [[ ${running_exe} != ${samba_daemon_bin} ]]; then log debug "${FUNCNAME}(): a process other than ${samba_daemon} is running with PID ${samba_daemon_pid}: '${running_exe}'" return 1 else ## check cmdline of the process samba_daemon_cmdline=$(xargs -r -0 -a /proc/${samba_daemon_pid}/cmdline 2>/dev/null) if [[ -z "${samba_daemon_cmdline}" ]]; then log err "${FUNCNAME}(): failed to check cmdline of ${samba_daemon} process with PID ${samba_daemon_pid}" fi ## smbd + nmbd + winbindd have the same command line scheme case "${samba_daemon_cmdline}" in ## instance _without_ optional ${samba_daemon_opts} "${samba_daemon_bin} -D -s ${samba_config}") log debug "${FUNCNAME}(): a matching ${samba_daemon} process is running with PID ${samba_daemon_pid}" return 0 ;; ## instance _with_ optional ${samba_daemon_opts} "${samba_daemon_bin} -D -s ${samba_config} ${samba_daemon_opts}") log debug "${FUNCNAME}(): a matching ${samba_daemon} process is running with PID ${samba_daemon_pid}" return 0 ;; ## any other (unexpected) instance *) log debug "${FUNCNAME}(): a ${samba_daemon} process with an unexpected cmdline is running with PID ${samba_daemon_pid}: '${samba_daemon_cmdline}'" ;; esac fi done ## default: failed to find any matching running instance return 1 } ## check whether all samba daemons are already running function check_all_samba_daemons_running() { local samba_daemons_not_running declare -i samba_daemons_not_running=0 if [[ "${smbd_enabled}" -eq 1 ]]; then if ! check_samba_daemon_running smbd; then let samba_daemons_not_running+=1 log debug "${FUNCNAME}(): smbd is not running" fi fi if [[ "${nmbd_enabled}" -eq 1 ]]; then if ! check_samba_daemon_running nmbd; then let samba_daemons_not_running+=1 log debug "${FUNCNAME}(): nmbd is not running" fi fi if [[ "${winbindd_enabled}" -eq 1 ]]; then if ! check_samba_daemon_running winbindd; then let samba_daemons_not_running+=1 log debug "${FUNCNAME}(): winbindd is not running" fi fi if [[ ${samba_daemons_not_running} -ne 0 ]]; then log debug "${FUNCNAME}(): ${samba_daemons_not_running} samba daemons are not running" return 1 else log debug "${FUNCNAME}(): all samba daemons are running" return 0 fi } ## check whether no samba daemons are running function check_no_samba_daemons_running() { local samba_daemons_running declare -i samba_daemons_running=0 if [[ "${smbd_enabled}" -eq 1 ]]; then if check_samba_daemon_running smbd; then let samba_daemons_running+=1 log debug "${FUNCNAME}(): smbd is running" fi fi if [[ "${nmbd_enabled}" -eq 1 ]]; then if check_samba_daemon_running nmbd; then let samba_daemons_running+=1 log debug "${FUNCNAME}(): nmbd is running" fi fi if [[ "${winbindd_enabled}" -eq 1 ]]; then if check_samba_daemon_running winbindd; then let samba_daemons_running+=1 log debug "${FUNCNAME}(): winbindd is running" fi fi if [[ ${samba_daemons_running} -ne 0 ]]; then log debug "${FUNCNAME}(): ${samba_daemons_running} samba daemons are running" return 1 else log debug "${FUNCNAME}(): no samba daemons are running" return 0 fi } ## OCF RA validate-all function ocf_ra_validate_all() { ## check smbd_enabled if [[ "${smbd_enabled}" -ne 0 && "${smbd_enabled}" -ne 1 ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): smbd_enabled '${smbd_enabled}' is invalid (has to be 0/1)" ## only check other smbd options when smbd is enabled elif [[ "${smbd_enabled}" -eq 1 ]]; then ## check smbd_bin if [[ ! -e "${smbd_bin}" ]]; then die ${OCF_ERR_INSTALLED} "${FUNCNAME}(): smbd_bin '${smbd_bin}' does not exist" elif [[ ! -x "${smbd_bin}" ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): smbd_bin '${smbd_bin}' is not executable" fi fi ## check nmbd_enabled if [[ "${nmbd_enabled}" -ne 0 && "${nmbd_enabled}" -ne 1 ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): nmbd_enabled '${nmbd_enabled}' is invalid (has to be 0/1)" ## only check other nmbd options when nmbd is enabled elif [[ "${nmbd_enabled}" -eq 1 ]]; then ## check nmbd_bin if [[ ! -e "${nmbd_bin}" ]]; then die ${OCF_ERR_INSTALLED} "${FUNCNAME}(): nmbd_bin '${nmbd_bin}' does not exist" elif [[ ! -x "${nmbd_bin}" ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): nmbd_bin '${nmbd_bin}' is not executable" fi fi ## check winbindd_enabled if [[ "${winbindd_enabled}" -ne 0 && "${winbindd_enabled}" -ne 1 ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): winbindd_enabled '${winbindd_enabled}' is invalid (has to be 0/1)" ## only check other winbindd options when winbindd is enabled elif [[ "${winbindd_enabled}" -eq 1 ]]; then ## check winbindd_bin if [[ ! -e "${winbindd_bin}" ]]; then die ${OCF_ERR_INSTALLED} "${FUNCNAME}(): winbindd_bin '${winbindd_bin}' does not exist" elif [[ ! -x "${winbindd_bin}" ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): winbindd_bin '${winbindd_bin}' is not executable" fi fi ## check samba_config if [[ ! -e "${samba_config}" ]]; then die ${OCF_ERR_CONFIGURED} "${FUNCNAME}(): samba_config '${samba_config}' does not exist" elif [[ ! -r "${samba_config}" ]]; then die ${OCF_ERR_CONFIGURED} "${FUNCNAME}(): samba_config '${samba_config}' is not readable" fi ## check testparm_bin if [[ ! -e "${testparm_bin}" ]]; then die ${OCF_ERR_INSTALLED} "${FUNCNAME}(): testparm_bin '${testparm_bin}' does not exist" elif [[ ! -x "${testparm_bin}" ]]; then die ${OCF_ERR_ARGS} "${FUNCNAME}(): testparm_bin '${testparm_bin}' is not executable" fi ## all parameters are valid log info "${FUNCNAME}(): all parameters are valid" return 0 } ## OCF RA meta-data function ocf_ra_meta_data() { cat <<-"EOF" 1.0 OCF Resource Agent compliant Samba control script for Gentoo. OCF Resource Agent compliant Samba control script for Gentoo. Controls whether smbd shall be started Controls whether smbd shall be started Full qualified path to the smbd binary Full qualified path to the smbd binary smbd binary command line options smbd binary command line options Full qualified path to the smbd pidfile Full qualified path to the smbd pidfile Controls whether nmbd shall be started Controls whether nmbd shall be started Full qualified path to the nmbd binary Full qualified path to the nmbd binary nmbd binary command line options nmbd binary command line options Full qualified path to the nmbd pidfile Full qualified path to the nmbd pidfile Controls whether winbindd shall be started Controls whether winbindd shall be started Full qualified path to the winbindd binary Full qualified path to the winbindd binary winbindd binary command line options winbindd binary command line options Full qualified path to the samba config Full qualified path to the samba config Full qualified path to the testparm binary Full qualified path to the testparm binary EOF return 0 } ## ## main() ## ## set the umask (restrictive default) umask 0077 ## source OCF shell functions provided by Heartbeat source ${OCF_ROOT:-/usr/lib/ocf}/resource.d/heartbeat/.ocf-shellfuncs || exit 1 ## check for required helper binaries check_binary cat check_binary logger check_binary mktemp check_binary pgrep check_binary ps check_binary readlink check_binary rm check_binary xargs ## check for OCF resource parameters ## -> smbd_enabled: optional if [[ -z "${OCF_RESKEY_smbd_enabled}" ]]; then smbd_enabled=1 else smbd_enabled=${OCF_RESKEY_smbd_enabled} fi ## -> smbd_bin: optional if [[ -z "${OCF_RESKEY_smbd_bin}" ]]; then smbd_bin="/usr/sbin/smbd" else smbd_bin=${OCF_RESKEY_smbd_bin} fi ## -> smbd_opts: optional if [[ -z "${OCF_RESKEY_smbd_opts}" ]]; then smbd_opts="" else smbd_opts=${OCF_RESKEY_smbd_opts} fi ## -> smbd_pidfile: optional if [[ -z "${OCF_RESKEY_smbd_pidfile}" ]]; then smbd_pidfile="/var/run/smbd.pid" else smbd_pidfile=${OCF_RESKEY_smbd_pidfile} fi ## -> nmbd_enabled: optional if [[ -z "${OCF_RESKEY_nmbd_enabled}" ]]; then nmbd_enabled=1 else nmbd_enabled=${OCF_RESKEY_nmbd_enabled} fi ## -> nmbd_bin: optional if [[ -z "${OCF_RESKEY_nmbd_bin}" ]]; then nmbd_bin="/usr/sbin/nmbd" else nmbd_bin=${OCF_RESKEY_nmbd_bin} fi ## -> nmbd_opts: optional if [[ -z "${OCF_RESKEY_nmbd_opts}" ]]; then nmbd_opts="" else nmbd_opts=${OCF_RESKEY_nmbd_opts} fi ## -> nmbd_pidfile: optional if [[ -z "${OCF_RESKEY_nmbd_pidfile}" ]]; then nmbd_pidfile="/var/run/nmbd.pid" else nmbd_pidfile=${OCF_RESKEY_nmbd_pidfile} fi ## -> winbindd_enabled: optional if [[ -z "${OCF_RESKEY_winbindd_enabled}" ]]; then winbindd_enabled=0 else winbindd_enabled=${OCF_RESKEY_winbindd_enabled} fi ## -> winbindd_bin: optional if [[ -z "${OCF_RESKEY_winbindd_bin}" ]]; then winbindd_bin="/usr/sbin/winbindd" else winbindd_bin=${OCF_RESKEY_winbindd_bin} fi ## -> winbindd_opts: optional if [[ -z "${OCF_RESKEY_winbindd_opts}" ]]; then winbindd_opts="" else winbindd_opts=${OCF_RESKEY_winbindd_opts} fi ## -> samba_config: optional if [[ -z "${OCF_RESKEY_samba_config}" ]]; then samba_config="/etc/samba/smb.conf" else samba_config=${OCF_RESKEY_samba_config} fi ## -> testparm_bin: optional if [[ -z "${OCF_RESKEY_testparm_bin}" ]]; then testparm_bin="/usr/bin/testparm" else testparm_bin=${OCF_RESKEY_testparm_bin} fi ## process command ocf_ra_cmd=${1} case "${ocf_ra_cmd}" in start) ## check whether all samba daemons are already running if check_all_samba_daemons_running; then log info "all samba daemons are already running" exit ${OCF_SUCCESS} elif ! check_no_samba_daemons_running; then log err "some but not all samba daemons are already running" exit ${OCF_ERR_GENERIC} ## give heartbeat the chance to cleanly restart us fi ## check whether testparm is passed samba_testparm_logfile=$(mktemp -q -t ${0##*/}.testparm.XXXXXX) if [[ -z "${samba_testparm_logfile}" ]]; then die ${OCF_ERR_GENERIC} "failed to create temporary testparm logfile" elif ! "${testparm_bin}" -s "${samba_config}" &>"${samba_testparm_logfile}"; then die ${OCF_ERR_GENERIC} "testparm failed -- see '${samba_testparm_logfile}' for details" else ## remove temporary logfile if ! rm -f "${samba_testparm_logfile}"; then ## this is non-fatal log warning "failed to remove temporary testparm logfile '${samba_testparm_logfile}'" fi log info "testparm ok" fi ## start all daemons if ! start_all_samba_daemons; then die ${OCF_ERR_GENERIC} "failed to start all samba daemons" else ## check whether all daemons are actually running after we started them. ## might of course run into the resource agents 'start' action ## timeout (that possibility is desired) sleep 1 while ! check_all_samba_daemons_running; do log notice "some samba daemons are not (yet?) running, although we started them before!" log notice "trying start run check again after 1s" sleep 1 done fi ## that's it log info "samba started successfully" exit ${OCF_SUCCESS} ;; stop) ## check whether all samba daemons are already stopped if check_no_samba_daemons_running; then log info "all samba daemons are already stopped" exit ${OCF_SUCCESS} elif ! check_all_samba_daemons_running; then log warning "some but not all samba daemons are already stopped" ## do NOT exit here as we want to stop all remaining daemons fi ## stop all samba daemons if ! stop_all_samba_daemons; then die ${OCF_ERR_GENERIC} "failed to stop all samba daemons" else ## check whether any daemons are still running after we stopped them. ## might of course run into the resource agents 'stop' action ## timeout (that possibility is desired) sleep 1 while ! check_no_samba_daemons_running; do log debug "some samba daemons are still running, although we stopped them before!" log debug "trying stop run check again after 1s" sleep 1 done # TODO FIXME: maybe we should try to kill all remaining # smbd/nmbd/winbindd processes? fi ## that's it log info "samba stopped successfully" exit ${OCF_SUCCESS} ;; monitor) ## check whether all samba daemons are running if check_no_samba_daemons_running; then die ${OCF_NOT_RUNNING} "no samba daemons are running" elif ! check_all_samba_daemons_running; then die ${OCF_NOT_RUNNING} "some samba daemons are not running" fi ## that's it log info "samba seems to be fine" exit ${OCF_SUCCESS} ;; meta-data) ocf_ra_meta_data ## that's it log debug "finished." exit ${OCF_SUCCESS} ;; validate-all) ocf_ra_validate_all ## that's it log debug "finished." exit ${OCF_SUCCESS} ;; *) die ${OCF_ERR_UNIMPLEMENTED} "Usage: ${0##*/} {start|stop|monitor|meta-data|validate-all}" ;; esac