222 lines
7.1 KiB
Bash
Executable file
222 lines
7.1 KiB
Bash
Executable file
#!/bin/bash
|
|
# Version: 0.5.0.
|
|
# Variant: service.
|
|
# Copyright (c) 2005-2023:
|
|
# Darren 'Tadgy' Austin <darren (at) afterdark.org.uk>
|
|
# Licensed under the terms of the GNU General Public License version 3.
|
|
|
|
SERVICE_EXEC="/usr/sbin/samba"
|
|
SERVICE_ARGS=()
|
|
SERVICE_ENV=()
|
|
SERVICE_PIDFILE="/run/samba.pid"
|
|
|
|
# Allow configuration in /etc/default to override.
|
|
# Additional available variables:
|
|
# SERVICE_EXTRA_ARGS=() # Extra arguments passed to $SERVICE_EXEC. Must be an array.
|
|
# SERVICE_EXTRA_ENV=() # Extra environment passed to $SERVICE_EXEC. Must be an array.
|
|
# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s.
|
|
# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s.
|
|
[[ -e "/etc/default/${0##*rc.}" ]] && {
|
|
# shellcheck disable=SC1090
|
|
source "/etc/default/${0##*rc.}" 2>/dev/null || {
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "failed sourcing '/etc/default/${0##*rc.}'" >&2
|
|
exit 2
|
|
}
|
|
}
|
|
|
|
# Now all possible variable changes are complete, expand out the embedded variables, if any.
|
|
eval "$(declare -p SERVICE_EXEC SERVICE_ARGS SERVICE_ENV SERVICE_PIDFILE SERVICE_EXTRA_ARGS SERVICE_EXTRA_ENV \
|
|
SLAY_DELAY RESTART_DELAY 2>/dev/null | sed -re 's/\\\$/$/g')" || {
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "failed expanding embedded variables" >&2
|
|
exit 2
|
|
}
|
|
|
|
# This function can be used to perform any pre-start tests; hopfully to insure the daemon can start
|
|
# correctly, before actually trying to start it.
|
|
checkconfigured() {
|
|
# Returns:
|
|
# 0 - The pre-start tests passed and the service should be started.
|
|
# >0 - Pre-start tests failed - the service should not be started.
|
|
return 0
|
|
}
|
|
|
|
checkstatus() {
|
|
# Returns:
|
|
# 0 - Service is running.
|
|
# 1 - Service is running, but there is a problem with the .pid file.
|
|
# 2 - Service is not running.
|
|
# shellcheck disable=SC2155
|
|
local RET=0 RUNPIDS="$({ pgrep -f "$SERVICE_EXEC"; pgrep -F "$SERVICE_PIDFILE" 2>/dev/null; } | sort -u)"
|
|
if [[ -n "$RUNPIDS" ]]; then
|
|
printf "%s: %s: %s" "${BASH_SOURCE[0]##*/}" "status" "service running"
|
|
if [[ -n "$SERVICE_PIDFILE" ]]; then
|
|
if [[ ! -e "$SERVICE_PIDFILE" ]]; then
|
|
printf "%s" ", but .pid file does not exist"
|
|
RET=1
|
|
elif ! grep "\<$(<"$SERVICE_PIDFILE")\>" <<<"$RUNPIDS" >/dev/null 2>&1; then
|
|
printf "%s" ", but .pid file is stale"
|
|
RET=1
|
|
fi
|
|
fi
|
|
printf "\\n"
|
|
else
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "status" "service stopped"
|
|
RET=2
|
|
fi
|
|
return "$RET"
|
|
}
|
|
|
|
startdaemon() {
|
|
# Returns:
|
|
# 0 - Service started successfully.
|
|
# 1 - Sanity or pre-start check failed.
|
|
# 2 - Error code returned when starting service.
|
|
local ERR
|
|
if [[ ! -e "$SERVICE_EXEC" ]]; then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "not started - '$SERVICE_EXEC' not found" >&2
|
|
return 1
|
|
elif [[ ! -x "$SERVICE_EXEC" ]]; then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "not started - '$SERVICE_EXEC' not executable" >&2
|
|
return 1
|
|
elif ! checkconfigured; then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "not started - pre-start checks failed" >&2
|
|
return 1
|
|
fi
|
|
mkdir /run/samba 2>/dev/null
|
|
env "${SERVICE_ENV[@]@Q}" "${SERVICE_EXTRA_ENV[@]@Q}" "$SERVICE_EXEC" "${SERVICE_ARGS[@]@Q}" "${SERVICE_EXTRA_ARGS[@]@Q}" >/dev/null 2>&1
|
|
ERR=$?
|
|
(( ERR != 0 )) && {
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "failed to start service (error code '$ERR)'" >&2
|
|
return 2
|
|
}
|
|
return 0
|
|
}
|
|
|
|
stopdaemon() {
|
|
# Returns:
|
|
# 0 - The service was stopped sucessfully with a SIGTERM.
|
|
# 1 - The service was stopped sucessfully with a SIGKILL.
|
|
# 2 - An error occured while stopping service.
|
|
local ERR RET=0 T="${SLAY_DELAY:-2}"
|
|
kill -TERM "$(pgrep -f "$SERVICE_EXEC" | tr $'\n' ' ')" >/dev/null 2>&1
|
|
sleep 0.5
|
|
T="$(awk -v T="$T" 'BEGIN {print T - 0.5}')"
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
if (( ERR <= 1 )); then
|
|
[[ -n "$SERVICE_PIDFILE" ]] && [[ -e "$SERVICE_PIDFILE" ]] && {
|
|
kill -TERM "$(<"$SERVICE_PIDFILE")" >/dev/null 2>&1
|
|
sleep 0.5
|
|
T="$(awk -v T="$T" 'BEGIN {print T - 0.5}')"
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
(( ERR <= 1 )) && sleep "$T"
|
|
}
|
|
elif (( ERR == 0 )); then
|
|
if kill -KILL "$({ pgrep -f "$SERVICE_EXEC"; cat "$SERVICE_PIDFILE" 2>/dev/null; } | sort -u | tr $'\n' ' ')" >/dev/null 2>&1; then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "warning" "failed to stop service gracefully - slayed" >&2
|
|
RET=1
|
|
else
|
|
RET=2
|
|
fi
|
|
fi
|
|
return "$RET"
|
|
}
|
|
|
|
RET=0
|
|
case "$1" in
|
|
'start')
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
if (( ERR <= 1 )); then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "service running" >&2
|
|
printf "%s\\n" "Try: ${BASH_SOURCE[0]} status" >&2
|
|
RET=1
|
|
elif (( ERR == 2 )); then
|
|
startdaemon
|
|
ERR=$?
|
|
if (( ERR == 1 )); then
|
|
RET=3
|
|
elif (( ERR == 2 )); then
|
|
RET=5
|
|
fi
|
|
fi
|
|
;;
|
|
'stop')
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
if (( ERR <= 1 )); then
|
|
stopdaemon
|
|
ERR=$?
|
|
(( ERR == 2 )) && {
|
|
sleep 0.1
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
(( ERR <= 1 )) && {
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "service failed to stop" >&2
|
|
RET=5
|
|
}
|
|
}
|
|
elif (( ERR == 2 )); then
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "service stopped" >&2
|
|
printf "%s\\n" "Try: ${BASH_SOURCE[0]} status" >&2
|
|
RET=1
|
|
fi
|
|
;;
|
|
'restart')
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
(( ERR <= 1 )) && {
|
|
stopdaemon
|
|
ERR=$?
|
|
if (( ERR <= 1 )); then
|
|
sleep "${RESTART_DELAY:-2}"
|
|
RET=-1
|
|
elif (( ERR == 2 )); then
|
|
sleep 0.1
|
|
checkstatus >/dev/null
|
|
ERR=$?
|
|
(( ERR <= 1 )) && {
|
|
printf "%s: %s: %s\\n" "${BASH_SOURCE[0]##*/}" "error" "service failed to stop" >&2
|
|
RET=5
|
|
}
|
|
fi
|
|
}
|
|
(( RET <= 0 )) && {
|
|
startdaemon
|
|
ERR=$?
|
|
if (( ERR == 0 )); then
|
|
RET=0
|
|
elif (( ERR == 1 )); then
|
|
RET=3
|
|
elif (( ERR == 2 )); then
|
|
RET="$(( RET + 5 ))"
|
|
fi
|
|
}
|
|
;;
|
|
'status')
|
|
checkstatus
|
|
ERR=$?
|
|
if (( ERR == 1 )); then
|
|
RET=4
|
|
elif (( ERR == 2 )); then
|
|
RET=5
|
|
fi
|
|
;;
|
|
*)
|
|
printf "%s\\n" "Usage: ${BASH_SOURCE[0]} <start|stop|restart|status>" >&2
|
|
printf "%s\\n" "Error codes:" >&2
|
|
printf " %s: %s\\n" "0" "For 'start', 'restart' and 'stop': Requested action succeeded." >&2
|
|
printf " %s\\n" "For 'status': Service is running." >&2
|
|
printf " %s: %s\\n" "1" "Usage error." >&2
|
|
printf " %s: %s\\n" "2" "A general error occurred." >&2
|
|
printf " %s: %s\\n" "3" "Sanity or pre-start check failed." >&2
|
|
printf " %s: %s\\n" "4" "For 'start', 'restart' and 'stop': Partial failure to complete action." >&2
|
|
printf " %s\\n" "For 'status': Service is running, but a problem exists with the .pid file." >&2
|
|
printf " %s: %s\\n" "5" "For 'start', 'restart' and 'stop': Total failure to complete action." >&2
|
|
printf " %s\\n" "For 'status': Service is not running." >&2
|
|
RET=1
|
|
;;
|
|
esac
|
|
|
|
exit "$RET"
|