diff options
Diffstat (limited to 'sbin/runscript.sh')
-rwxr-xr-x | sbin/runscript.sh | 258 |
1 files changed, 146 insertions, 112 deletions
diff --git a/sbin/runscript.sh b/sbin/runscript.sh index 005d7bb..d1960a7 100755 --- a/sbin/runscript.sh +++ b/sbin/runscript.sh @@ -17,14 +17,14 @@ svcrestart="no" myscript="$1" if [[ -L $1 && ! -L "/etc/init.d/${1##*/}" ]] ; then - myservice="$(readlink $1)" + myservice="$(readlink "$1")" else myservice="$1" fi myservice="${myservice##*/}" export SVCNAME="${myservice}" -mylevel="$(<${svcdir}/softlevel)" +mylevel="$(< "${svcdir}/softlevel")" svc_trap() { trap 'eerror "ERROR: \"${myservice}\" caught an interrupt"; exit 1' \ @@ -64,22 +64,22 @@ if [[ ${NETSERVICE} == "yes" ]] ; then conf="$(add_suffix /etc/conf.d/net)" [[ -e ${conf} ]] && source "${conf}" fi -conf="$(add_suffix /etc/conf.d/${myservice})" +conf="$(add_suffix "/etc/conf.d/${myservice}")" [[ -e ${conf} ]] && source "${conf}" conf="$(add_suffix /etc/rc.conf)" [[ -e ${conf} ]] && source "${conf}" # Call svc_quit if we abort AND we have obtained a lock -svcbegun=1 service_started "${myservice}" -svcstarted=$? +svcstarted="$?" +service_inactive "${myservice}" +svcinactive="$?" svc_quit() { - eerror "ERROR: \"${myservice}\" caught an interrupt" - if [[ ${svcbegun} == 0 ]] ; then - end_service "${myservice}" - svcbegun=1 - fi - if [[ ${svcstarted} == 0 ]] ; then + eerror "ERROR: ${myservice} caught an interrupt" + end_service "${myservice}" + if service_inactive "${myservice}" || [[ ${svcinactive} == 0 ]] ; then + mark_service_inactive "${myservice}" + elif [[ ${svcstarted} == 0 ]] ; then mark_service_started "${myservice}" else mark_service_stopped "${myservice}" @@ -101,13 +101,13 @@ stop() { } start() { - eerror "ERROR: \"${myservice}\" does not have a start function." + eerror "ERROR: ${myservice} does not have a start function." # Return failure so the symlink doesn't get created return 1 } restart() { - svc_restart || return $? + svc_restart } status() { @@ -115,8 +115,33 @@ status() { return 0 } +svc_schedule_restart() { + local service="$1" restart="$2" + [[ ! -d "${svcdir}/restart/${service}" ]] \ + && mkdir -p "${svcdir}/restart/${service}" + [[ ! -e "${svcdir}/restart/${service}/${restart}" ]] \ + && ln -snf "/etc/init.d/${service}" \ + "${svcdir}/restart/${service}/${restart}" +} + +svc_start_restart() { + [[ ! -d "${svcdir}/restart/${myservice}" ]] && return + local x= services= scripts="$(dolisting "${svcdir}/restart/${myservice}/")" + + for x in ${scripts} ; do + services="${services} ${x##*/}" + done + + for x in $(trace_dependencies "${services}") ; do + service_stopped "${x}" && start_service "${x}" + rm -f "${svcdir}/restart/${myservice}/${x}" + done + + rmdir "${svcdir}/restart/${myservice}" +} + svc_stop() { - local x= mydep= mydeps= retval=0 was_inactive=false + local x= mydep= mydeps= retval=0 local -a servicelist=() # Do not try to stop if it had already failed to do so on runlevel change @@ -125,13 +150,12 @@ svc_stop() { fi if service_stopped "${myservice}" ; then - ewarn "WARNING: \"${myservice}\" has not yet been started." + ewarn "WARNING: ${myservice} has not yet been started." return 0 fi - service_inactive "${myservice}" && was_inactive=true if ! mark_service_stopping "${myservice}" ; then - ewarn "WARNING: \"${myservice}\" is already stopping." + ewarn "WARNING: ${myservice} is already stopping." return 0 fi # Lock service starting too ... @@ -141,7 +165,6 @@ svc_stop() { trap "svc_quit" INT QUIT TSTP begin_service "${myservice}" - svcbegun=$? service_message "Stopping service ${myservice}" @@ -155,13 +178,10 @@ svc_stop() { # A net.* service if in_runlevel "${myservice}" "${BOOTLEVEL}" || \ in_runlevel "${myservice}" "${mylevel}" ; then - # Only worry about net.* services if this is the last one running, - # or if RC_NET_STRICT_CHECKING is set ... - if ! is_net_up ; then - mydeps="net" - fi + # Only worry about net.* services if this is the last one + # running or if RC_NET_STRICT_CHECKING is set ... + ! is_net_up && mydeps="net" fi - mydeps="${mydeps} ${myservice}" else mydeps="${myservice}" @@ -182,7 +202,14 @@ svc_stop() { done done + [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait + for x in "${service_list[@]}" ; do + # We need to test if the service has been marked stopped + # as the fifo may still be around if called by custom code + # such as postup from a net script. + service_stopped "${mynetservice}" && continue + wait_service "${x}" if ! service_stopped "${x}" ; then retval=1 @@ -194,19 +221,28 @@ svc_stop() { if [[ ${retval} != 0 ]] ; then eerror "ERROR: problems stopping dependent services." - eerror " \"${myservice}\" is still up." + eerror " ${myservice} is still up." else + # Now that deps are stopped, stop our service + ( + exit() { + RC_QUIET_STDOUT="no" + eerror "DO NOT USE EXIT IN INIT.D SCRIPTS" + eerror "This IS a bug, please fix your broken init.d" + unset -f exit + exit "$@" + } # Stop einfo/ebegin/eend from working as parallel messes us up [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes" - - # Now that deps are stopped, stop our service - ( stop ) - retval=$? + stop + ) + retval="$?" # If a service has been marked inactive, exit now as something # may attempt to start it again later if service_inactive "${myservice}" ; then - [[ ${svcbegun} == 0 ]] && end_service "${myservice}" 0 + svcinactive=0 + end_service "${myservice}" 0 return 0 fi fi @@ -218,7 +254,7 @@ svc_stop() { # If we are halting the system, do it as cleanly as possible if [[ ${SOFTLEVEL} != "reboot" && ${SOFTLEVEL} != "shutdown" ]] ; then - if ${was_inactive} ; then + if [[ ${svcinactive} == 0 ]] ; then mark_service_inactive "${myservice}" else mark_service_started "${myservice}" @@ -230,18 +266,15 @@ svc_stop() { # If we're stopped from a daemon that sets ${IN_BACKGROUND} such as # wpa_monitor when we mark as inactive instead of taking the down svcstarted=1 - if ${IN_BACKGROUND:-false} ; then - mark_service_inactive "${myservice}" + if service_inactive "${myservice}" ; then + svcinactive=0 else mark_service_stopped "${myservice}" fi service_message "Stopped service ${myservice}" fi - if [[ ${svcbegun} == 0 ]] ; then - end_service "${myservice}" "${retval}" - svcbegun=1 - fi + end_service "${myservice}" "${retval}" # Reset the trap svc_trap @@ -250,7 +283,7 @@ svc_stop() { } svc_start() { - local x= y= retval=0 was_inactive=false startfail="no" + local x= y= retval=0 startfail= startinactive= # Do not try to start if i have done so already on runlevel change if is_runlevel_start && service_failed "${myservice}" ; then @@ -258,21 +291,20 @@ svc_start() { fi if service_started "${myservice}" ; then - ewarn "WARNING: \"${myservice}\" has already been started." + ewarn "WARNING: ${myservice} has already been started." return 0 elif service_stopping "${myservice}" ; then - eerror "ERROR: please wait for \"${myservice}\" to stop first." + eerror "ERROR: please wait for ${myservice} to stop first." return 1 elif service_inactive "${myservice}" ; then if [[ ${IN_BACKGROUND} != "true" ]] ; then - ewarn "WARNING: \"${myservice}\" has already been started." + ewarn "WARNING: ${myservice} has already been started." return 0 fi fi - service_inactive "${myservice}" && was_inactive=true if ! mark_service_starting "${myservice}" ; then - ewarn "WARNING: \"${myservice}\" is already starting." + ewarn "WARNING: ${myservice} is already starting." return 0 fi @@ -280,25 +312,25 @@ svc_start() { trap "svc_quit" INT QUIT TSTP begin_service "${myservice}" - svcbegun=$? - service_message "Starting service ${myservice}" + + # Save the IN_BACKGROUND var as we need to clear it for starting depends + local ib_save="${IN_BACKGROUND}" + unset IN_BACKGROUND local startupservices="$(trace_dependencies $(ineed "${myservice}") \ - $(valid_iuse ${myservice}))" + $(valid_iuse "${myservice}"))" local netservices="$(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \ $(dolisting "/etc/runlevels/${mylevel}/net.*")" - local mynetservice= + local startupnetservices= # Start dependencies, if any. # We don't handle "after" deps here as it's the job of rc to start them. for x in ${startupservices} ; do if [[ ${x} == "net" && ${NETSERVICE} != "yes" ]] && ! is_net_up ; then for y in ${netservices} ; do - mynetservice="${y##*/}" - if service_stopped "${mynetservice}" ; then - start_service "${mynetservice}" - fi + y="${y##*/}" + service_stopped "${y}" && start_service "${y}" done elif [[ ${x} != "net" ]] ; then if service_stopped "${x}" ; then @@ -307,102 +339,116 @@ svc_start() { fi done + [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait + # We also wait for any services we're after to finish incase they # have a "before" dep but we don't dep on them. if is_runlevel_start ; then - startupservices="${startupservices} $(valid_iafter ${myservice})" + startupservices="${startupservices} $(valid_iafter "${myservice}")" fi # Wait for dependencies to finish. for x in ${startupservices} ; do if [[ ${x} == "net" && ${NETSERVICE} != "yes" ]] ; then for y in ${netservices} ; do - mynetservice="${y##*/}" - - wait_service "${mynetservice}" - - if ! service_started "${mynetservice}" ; then + y="${y##*/}" + # Don't wait if it's already been started + service_started "${y}" && continue + wait_service "${y}" + if ! service_started "${y}" ; then # A 'need' dependency is critical for startup if ineed -t "${myservice}" "${x}" >/dev/null ; then - # Only worry about a net.* service if we do not have one - # up and running already, or if RC_NET_STRICT_CHECKING - # is set .... if ! is_net_up ; then - startfail="yes" + if service_inactive "${y}" ; then + svc_schedule_restart "${y}" "${myservice}" + startinactive="${y}" + else + startfail="${y}" + fi + break fi fi fi done elif [[ ${x} != "net" ]] ; then + # Don't wait if it's already been started + service_started "${x}" && continue wait_service "${x}" if ! service_started "${x}" ; then # A 'need' dependacy is critical for startup if ineed -t "${myservice}" "${x}" >/dev/null ; then - startfail="yes" + if service_inactive "${x}" ; then + svc_schedule_restart "${x}" + startinactive="${x}" + else + startfail="${x}" + fi + break fi fi fi done if [[ ${startfail} == "yes" ]] ; then - eerror "ERROR: Problem starting needed services." - eerror " \"${myservice}\" was not started." + eerror "ERROR: Problem starting needed service ${startfail}." + eerror " ${myservice} was not started." + retval=1 + elif [[ -n ${startinactive} ]] ; then + ewarn "WARNING: ${myservice} is scheduled to start when ${startinactive} has started." retval=1 elif broken "${myservice}" ; then eerror "ERROR: Some services needed are missing. Run" eerror " './${myservice} broken' for a list of those" - eerror " services. \"${myservice}\" was not started." + eerror " services. ${myservice} was not started." retval=1 else + IN_BACKGROUND="${ib_save}" ( exit() { RC_QUIET_STDOUT="no" eerror "DO NOT USE EXIT IN INIT.D SCRIPTS" eerror "This IS a bug, please fix your broken init.d" unset -f exit - exit $@ + exit "$@" } # Stop einfo/ebegin/eend from working as parallel messes us up [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && RC_QUIET_STDOUT="yes" start ) - retval=$? + retval="$?" # If a service has been marked inactive, exit now as something # may attempt to start it again later if service_inactive "${myservice}" ; then - [[ ${svcbegun} == 0 ]] && end_service "${myservice}" 1 + svcinactive=0 + end_service "${myservice}" 1 return 1 fi fi if [[ ${retval} != 0 ]] ; then - is_runlevel_start && mark_service_failed "${myservice}" - # Remove link if service didn't start; but only if we're not booting # If we're booting, we need to continue and do our best to get the # system up. if [[ ${SOFTLEVEL} != "${BOOTLEVEL}" ]] ; then - if ${was_inactive} ; then + if [[ ${svcinactive} == 0 ]] ; then mark_service_inactive "${myservice}" else mark_service_stopped "${myservice}" fi fi - service_message "eerror" "FAILED to start service ${myservice}!" + if [[ -z ${startinactive} ]] ; then + is_runlevel_start && mark_service_failed "${myservice}" + service_message "eerror" "FAILED to start service ${myservice}!" + fi else svcstarted=0 mark_service_started "${myservice}" - service_message "Service ${myservice} started OK" fi - if [[ ${svcbegun} == 0 ]] ; then - end_service "${myservice}" "${retval}" - svcbegun=1 - fi - + end_service "${myservice}" "${retval}" # Reset the trap svc_trap @@ -413,7 +459,7 @@ svc_restart() { if ! service_stopped "${myservice}" ; then svc_stop || return "$?" fi - svc_start || return "$?" + svc_start } svc_status() { @@ -448,12 +494,13 @@ svc_status() { && ${efunc} "status: ${state}" status - [[ ${efunc} != "eerror" ]] + # Return 0 if started, otherwise 1 + [[ ${state} == "started" ]] } -rcscript_errors="$(bash -n ${myscript} 2>&1)" || { +rcscript_errors="$(bash -n "${myscript}" 2>&1)" || { [[ -n ${rcscript_errors} ]] && echo "${rcscript_errors}" >&2 - eerror "ERROR: \"${myscript}\" has syntax errors in it; aborting ..." + eerror "ERROR: ${myscript} has syntax errors in it; aborting ..." exit 1 } @@ -517,7 +564,7 @@ for arg in $* ; do case "${arg}" in stop) if [[ -e "${svcdir}/restart/${myservice}" ]] ; then - rm -f "${svcdir}/restart/${myservice}" + rm -Rf "${svcdir}/restart/${myservice}" fi # Stoped from the background - treat this as a restart so that @@ -525,33 +572,27 @@ for arg in $* ; do if [[ ${IN_BACKGROUND} == "true" ]] ; then rm -rf "${svcdir}/snapshot/$$" mkdir -p "${svcdir}/snapshot/$$" - cp -a "${svcdir}"/started/* "${svcdir}/snapshot/$$/" + cp -pP "${svcdir}"/started/* "${svcdir}/snapshot/$$/" fi svc_stop - + retval="$?" + if [[ ${IN_BACKGROUND} == "true" ]] ; then - res= for x in $(dolisting "${svcdir}/snapshot/$$/") ; do if service_stopped "${x##*/}" ; then - res="${res}${x##*/} " + svc_schedule_restart "${myservice}" "${x##*/}" fi done - [[ -n ${res} ]] && echo "${res}" > "${svcdir}/restart/${myservice}" fi + + exit "${retval}" ;; start) svc_start retval=$? - if ! is_runlevel_start && [[ -s "${svcdir}/restart/${myservice}" ]] ; then - for x in $(trace_dependencies $(< "${svcdir}/restart/${myservice}")) ; do - service_stopped "${x}" && start_service "${x}" - done - fi - if [[ -e "${svcdir}/restart/${myservice}" ]] ; then - rm -f "${svcdir}/restart/${myservice}" - fi - exit ${retval} + service_started "${myservice}" && svc_start_restart + exit "${retval}" ;; needsme|ineed|usesme|iuse|broken) trace_dependencies "-${arg}" @@ -579,7 +620,7 @@ for arg in $* ; do # Create a snapshot of started services rm -rf "${svcdir}/snapshot/$$" mkdir -p "${svcdir}/snapshot/$$" - cp -a "${svcdir}"/started/* "${svcdir}/snapshot/$$/" + cp -pP "${svcdir}"/started/* "${svcdir}/snapshot/$$/" # Simple way to try and detect if the service use svc_{start,stop} # to restart if it have a custom restart() funtion. @@ -599,27 +640,20 @@ for arg in $* ; do restart fi + [[ -e "${svcdir}/restart/${myservice}" ]] \ + && rm -f "${svcdir}/restart/${myservice}" + # Restart dependencies as well - if service_started "${myservice}" ; then - for x in $(trace_dependencies \ - $(dolisting "${svcdir}/snapshot/$$/") ) ; do - if service_stopped "${x##*/}" ; then - start_service "${x##*/}" - fi - done - elif service_inactive "${myservice}" ; then - res= + if service_inactive "${myservice}" ; then for x in $(dolisting "${svcdir}/snapshot/$$/") ; do if service_stopped "${x##*/}" ; then - res="${res}${x##*/} " + svc_schedule_restart "${myservice}" "${x##*/}" fi done - [[ -n ${res} ]] && echo "${res}" > "${svcdir}/restart/${myservice}" + elif service_started "${myservice}" ; then + svc_start_restart fi - # Wait for any services that may still be running ... - [[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait - rm -rf "${svcdir}/snapshot/$$" svcrestart="no" ;; |