var
Signed-off-by: fbt <fbt@fleshless.org>
This commit is contained in:
parent
a633061d30
commit
758e841e1e
693
ssm
693
ssm
|
@ -2,16 +2,78 @@
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
## Make setting default values a bit less awkward
|
is_function() [[ $(type -t $1 2>/dev/null) == 'function' ]]
|
||||||
default() {
|
|
||||||
declare -n _p=$1; shift
|
|
||||||
|
|
||||||
[[ "$_p" ]] || {
|
var() {
|
||||||
for v in "$@"; do
|
declare varname=$1; shift
|
||||||
_p+=( "$v" )
|
|
||||||
done
|
if ! is_function "$varname"; then
|
||||||
}
|
eval "
|
||||||
}; readonly -f default
|
${varname}() {
|
||||||
|
declare mode=set
|
||||||
|
declare -n _var=\"${varname}\"
|
||||||
|
|
||||||
|
if (( \$# )); then
|
||||||
|
case \"\$1\" in
|
||||||
|
('=') mode=set;;
|
||||||
|
('+=') mode=append;;
|
||||||
|
('_=') mode=prepend;;
|
||||||
|
(':=') mode=default;;
|
||||||
|
|
||||||
|
('==') mode=compare;;
|
||||||
|
('=~') mode=regex;;
|
||||||
|
|
||||||
|
(*) die 71 \"Syntax error in \$FUNCNAME!\";;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
mode='bool'
|
||||||
|
fi
|
||||||
|
|
||||||
|
case \"\$mode\" in
|
||||||
|
(set) _var=( \"\$@\" );;
|
||||||
|
(append) _var+=( \"\$@\" );;
|
||||||
|
(prepend) _var=( \"\$@\" \"\${var[@]}\" );;
|
||||||
|
(default) [[ \"\$_var\" ]] || _var=( \"\$@\" );;
|
||||||
|
|
||||||
|
(compare) [[ \"\$_var\" == \"\$*\" ]];;
|
||||||
|
(regex) [[ \"\$_var\" =~ \$@ ]];;
|
||||||
|
|
||||||
|
(bool)
|
||||||
|
case \"\${_var,,}\" in
|
||||||
|
(''|'false'|'0') return 1;;
|
||||||
|
(*) return 0;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}; readonly -f \"${varname}\"
|
||||||
|
|
||||||
|
${varname}++() {
|
||||||
|
declare -n _var=\"${varname}\"
|
||||||
|
(( ${varname}++ ))
|
||||||
|
}
|
||||||
|
|
||||||
|
${varname}--() {
|
||||||
|
declare -n _var=\"${varname}\"
|
||||||
|
(( ${varname}-- ))
|
||||||
|
}
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( $# )); then
|
||||||
|
case "$1" in
|
||||||
|
('='|'=='|'=~'|'+='|'_='|':=')
|
||||||
|
"$varname" "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
(*)
|
||||||
|
for v in "$@"; do
|
||||||
|
var "$v"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
## Die. Why not?
|
## Die. Why not?
|
||||||
die() {
|
die() {
|
||||||
|
@ -24,6 +86,7 @@ die() {
|
||||||
## Run the command and wait for it to die
|
## Run the command and wait for it to die
|
||||||
svc() {
|
svc() {
|
||||||
declare job_pid
|
declare job_pid
|
||||||
|
var job_pid
|
||||||
|
|
||||||
svc::cleanup() {
|
svc::cleanup() {
|
||||||
kill -n "$service_stop_signal" "$job_pid"
|
kill -n "$service_stop_signal" "$job_pid"
|
||||||
|
@ -36,7 +99,7 @@ svc() {
|
||||||
kill -n "$service_reload_signal" "$job_pid"
|
kill -n "$service_reload_signal" "$job_pid"
|
||||||
}; trap 'svc::reload' HUP
|
}; trap 'svc::reload' HUP
|
||||||
|
|
||||||
"$@" & job_pid=$!
|
"$@" & job_pid = "$!"
|
||||||
|
|
||||||
printf '%s' "$job_pid" > "$svc_pidfile"
|
printf '%s' "$job_pid" > "$svc_pidfile"
|
||||||
wait "$job_pid"
|
wait "$job_pid"
|
||||||
|
@ -46,7 +109,8 @@ svc() {
|
||||||
|
|
||||||
## Respawn
|
## Respawn
|
||||||
respawn() {
|
respawn() {
|
||||||
declare jobs job_pid
|
declare job_pid
|
||||||
|
var job_pid
|
||||||
|
|
||||||
respawn::cleanup() {
|
respawn::cleanup() {
|
||||||
kill -n "$service_stop_signal" "$job_pid"
|
kill -n "$service_stop_signal" "$job_pid"
|
||||||
|
@ -58,7 +122,10 @@ respawn() {
|
||||||
}; trap 'respawn::cleanup' TERM
|
}; trap 'respawn::cleanup' TERM
|
||||||
|
|
||||||
respawn::sigpass() {
|
respawn::sigpass() {
|
||||||
declare sig=$1 pid=$2
|
declare sig pid
|
||||||
|
var sig = "$1"
|
||||||
|
var pid = "$2"
|
||||||
|
|
||||||
kill -n "$sig" "$pid"
|
kill -n "$sig" "$pid"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +136,7 @@ respawn() {
|
||||||
}; respawn::set_traps
|
}; respawn::set_traps
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
exec "$@" & job_pid=$!
|
exec "$@" & job_pid = "$!"
|
||||||
|
|
||||||
while nullexec kill -n 0 "$job_pid"; do
|
while nullexec kill -n 0 "$job_pid"; do
|
||||||
wait "$job_pid"
|
wait "$job_pid"
|
||||||
|
@ -83,39 +150,29 @@ readonly -f nullexec
|
||||||
|
|
||||||
## Wait for a pid to die
|
## Wait for a pid to die
|
||||||
pid_wait() {
|
pid_wait() {
|
||||||
declare cnt=0
|
declare cnt
|
||||||
|
var cnt = 0
|
||||||
|
|
||||||
while nullexec kill -0 "$1"; do
|
while nullexec kill -0 "$1"; do
|
||||||
(( cnt >= (service_stop_timeout*10) )) && return 1
|
(( cnt >= (service_stop_timeout*10) )) && return 1
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
(( cnt++ ))
|
cnt++
|
||||||
done
|
done
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}; readonly -f pid_wait
|
}; readonly -f pid_wait
|
||||||
|
|
||||||
## See if NAME is a function
|
|
||||||
is_function() {
|
|
||||||
declare name=$1 name_type
|
|
||||||
|
|
||||||
name_type=$( type -t "$name" )
|
|
||||||
|
|
||||||
if [[ $name_type == 'function' ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}; readonly -f is_function
|
|
||||||
|
|
||||||
## Simple timer
|
## Simple timer
|
||||||
timer() {
|
timer() {
|
||||||
declare cnt=0 timeout=$1
|
declare cnt timeout
|
||||||
|
var cnt = 0
|
||||||
|
var timeout = "$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
while ! "$@"; do
|
while ! "$@"; do
|
||||||
(( cnt >= (timeout*10) )) && return 1
|
(( cnt >= (timeout*10) )) && return 1
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
(( cnt++ ))
|
cnt++
|
||||||
done
|
done
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -136,7 +193,7 @@ depend() {
|
||||||
for s in "$@"; do
|
for s in "$@"; do
|
||||||
if ! "$_self" "$s" qstatus; then
|
if ! "$_self" "$s" qstatus; then
|
||||||
nullexec "$_self" "$s" start || {
|
nullexec "$_self" "$s" start || {
|
||||||
failed_deps+=( "$s" )
|
failed_deps += "$s"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
@ -177,14 +234,14 @@ depend_ready() {
|
||||||
|
|
||||||
for s in "$@"; do
|
for s in "$@"; do
|
||||||
"$_self" "$s" wait_ready || {
|
"$_self" "$s" wait_ready || {
|
||||||
failed_deps+=( "$s" )
|
failed_deps += "$s"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
done
|
done
|
||||||
}; readonly -f depend_ready
|
}; readonly -f depend_ready
|
||||||
|
|
||||||
result() {
|
result() {
|
||||||
declare rc=$1; shift
|
declare rc; var rc = "$1"; shift
|
||||||
declare -A msgs
|
declare -A msgs
|
||||||
|
|
||||||
while (( $# )); do
|
while (( $# )); do
|
||||||
|
@ -200,70 +257,34 @@ result() {
|
||||||
}; readonly -f result
|
}; readonly -f result
|
||||||
|
|
||||||
read_systemd_service() {
|
read_systemd_service() {
|
||||||
declare section key value
|
declare section key value line
|
||||||
|
var key value line
|
||||||
|
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
[[ $line =~ ^\[(.+)\] ]] && section=${BASH_REMATCH[1],,}
|
line =~ '^\[(.+)\]' && var section = "${BASH_REMATCH[1],,}"
|
||||||
[[ $line =~ ^([^=]+)=(.+) ]] && {
|
line =~ '^([^=]+)=(.+)' && {
|
||||||
key=${BASH_REMATCH[1],,}
|
key = "${BASH_REMATCH[1],,}"
|
||||||
value=${BASH_REMATCH[2]}
|
value = "${BASH_REMATCH[2]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
case $section in
|
case $section in
|
||||||
(service)
|
(service)
|
||||||
case $key in
|
case $key in
|
||||||
(pidfile) service_pidfile=$value;;
|
(pidfile) service_pidfile = "$value";;
|
||||||
(execstart) eval "service_command=( $value )";;
|
(execstart) eval "service_command=( $value )";;
|
||||||
(execstop) eval "stop() { $value; }";;
|
(execstop) eval "stop() { $value; }";;
|
||||||
(execreload) eval "reload() { $value; }";;
|
(execreload) eval "reload() { $value; }";;
|
||||||
(restart) [[ $value == 'always' ]] && service_respawn=1;;
|
(restart) [[ $value == 'always' ]] && service_respawn = 1;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done < "$1"
|
done < "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Some DSL for the config
|
|
||||||
setter() {
|
|
||||||
for i in "$@"; do
|
|
||||||
declare varname=$i
|
|
||||||
eval "
|
|
||||||
${varname}() {
|
|
||||||
declare mode=set
|
|
||||||
declare -n _var=${varname}
|
|
||||||
|
|
||||||
while (( \$# )); do
|
|
||||||
case \$1 in
|
|
||||||
(=) mode=set;;
|
|
||||||
(+=) mode=append;;
|
|
||||||
(_=) mode=prepend;;
|
|
||||||
(--) shift; break;;
|
|
||||||
(*) break;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
case \$mode in
|
|
||||||
(append) _var+=( \"\$@\" );;
|
|
||||||
(prepend) _var=( \"\$@\" \"\${_var[@]}\" );;
|
|
||||||
(set) _var=( \"\$@\" );;
|
|
||||||
esac
|
|
||||||
}; readonly -f ${varname}
|
|
||||||
"
|
|
||||||
done
|
|
||||||
}; readonly setter
|
|
||||||
|
|
||||||
setter \
|
|
||||||
service_path \
|
|
||||||
service_workdir \
|
|
||||||
service_stop_timeout service_ready_timeout \
|
|
||||||
service_stop_signal service_reload_signal service_signals \
|
|
||||||
systemd systemd_service_path
|
|
||||||
|
|
||||||
# Overloadable functions
|
# Overloadable functions
|
||||||
## Start the service, write down the svc pid
|
## Start the service, write down the svc pid
|
||||||
start() {
|
start() {
|
||||||
(( service_running )) && return 3
|
service_running && return 3
|
||||||
|
|
||||||
rm -f "$service_stopped_flag"
|
rm -f "$service_stopped_flag"
|
||||||
|
|
||||||
|
@ -274,8 +295,8 @@ start() {
|
||||||
|
|
||||||
mktmpfiles || return 13
|
mktmpfiles || return 13
|
||||||
|
|
||||||
if (( service_managed )); then
|
if service_managed; then
|
||||||
if (( service_respawn )); then
|
if service_respawn; then
|
||||||
svc respawn "${service_command[@]}" &>"$service_logfile" &
|
svc respawn "${service_command[@]}" &>"$service_logfile" &
|
||||||
else
|
else
|
||||||
svc "${service_command[@]}" &>"$service_logfile" &
|
svc "${service_command[@]}" &>"$service_logfile" &
|
||||||
|
@ -286,9 +307,9 @@ start() {
|
||||||
else
|
else
|
||||||
return 5
|
return 5
|
||||||
fi
|
fi
|
||||||
elif (( service_oneshot )); then
|
elif service_oneshot; then
|
||||||
"${service_command[@]}" &>"$service_logfile"; res=$?
|
"${service_command[@]}" &>"$service_logfile"; res=$?
|
||||||
(( $res )) && return "$res"
|
(( res )) && return "$res"
|
||||||
printf '1' > "$service_enabled_flag"
|
printf '1' > "$service_enabled_flag"
|
||||||
else
|
else
|
||||||
exec "${service_command[@]}" &
|
exec "${service_command[@]}" &
|
||||||
|
@ -300,7 +321,7 @@ start() {
|
||||||
## Reload the service
|
## Reload the service
|
||||||
## Usually just sends HUP
|
## Usually just sends HUP
|
||||||
reload() {
|
reload() {
|
||||||
(( service_running )) || return 3
|
service_running || return 3
|
||||||
|
|
||||||
kill -n "$service_reload_signal" "$service_pid"
|
kill -n "$service_reload_signal" "$service_pid"
|
||||||
}
|
}
|
||||||
|
@ -309,14 +330,14 @@ reload() {
|
||||||
## Returns:
|
## Returns:
|
||||||
## 3: Service is not running.
|
## 3: Service is not running.
|
||||||
stop() {
|
stop() {
|
||||||
if (( service_oneshot )); then
|
if service_oneshot; then
|
||||||
(( service_enabled )) || return 3
|
service_enabled || return 3
|
||||||
|
|
||||||
rm -f "$service_enabled_flag"
|
rm -f "$service_enabled_flag"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
(( service_running )) || return 3
|
service_running || return 3
|
||||||
|
|
||||||
nullexec kill -n "$service_stop_signal" "$service_pid" || return 1
|
nullexec kill -n "$service_stop_signal" "$service_pid" || return 1
|
||||||
|
|
||||||
|
@ -328,34 +349,32 @@ stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
info() {
|
info() {
|
||||||
declare \
|
declare _status_label _status _type _info_items
|
||||||
_status_label='Running' \
|
var _status_label = 'Running'
|
||||||
_status='no'
|
var _status = 'no'
|
||||||
_type='daemon'
|
var _type = 'daemon'
|
||||||
_info_items=()
|
var _info_items
|
||||||
|
|
||||||
(( service_oneshot )) && {
|
service_oneshot && {
|
||||||
_status_label='Enabled'
|
_status_label = 'Enabled'
|
||||||
_type='oneshot'
|
_type = 'oneshot'
|
||||||
}
|
}
|
||||||
|
|
||||||
status && _status='yes'
|
status && _status = 'yes'
|
||||||
|
|
||||||
_info_items=(
|
_info_items = \
|
||||||
"Name" "$service_name"
|
"Name" "$service_name" \
|
||||||
"Type" "$_type"
|
"Type" "$_type" \
|
||||||
"$_status_label" "$_status"
|
"$_status_label" "$_status" \
|
||||||
"Exec" "${service_command[*]} ${service_args[*]}"
|
"Exec" "${service_command[*]} ${service_args[*]}" \
|
||||||
"Respawn" "${service_respawn:-false}"
|
"Respawn" "${service_respawn:-false}" \
|
||||||
"Config path" "${service_config}"
|
"Config path" "${service_config}" \
|
||||||
)
|
|
||||||
|
|
||||||
[[ "$_status" == 'yes' ]] && {
|
if _status == 'yes'; then
|
||||||
_info_items+=(
|
_info_items += \
|
||||||
"PIDfile" "${service_pidfile:-none}"
|
"PIDfile" "${service_pidfile:-none}" \
|
||||||
"PID" "${service_pid:-none}"
|
"PID" "${service_pid:-none}"
|
||||||
)
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
printf "%12s: %s\n" "${_info_items[@]}"
|
printf "%12s: %s\n" "${_info_items[@]}"
|
||||||
}
|
}
|
||||||
|
@ -366,8 +385,8 @@ restart() {
|
||||||
"$_self" "$service_name" start
|
"$_self" "$service_name" start
|
||||||
}
|
}
|
||||||
|
|
||||||
edit() { "${EDITOR:-vim}" "$service_config"; }
|
edit() { $EDITOR "$service_config"; }
|
||||||
logs() { ${PAGER:-less} "$service_logfile"; }
|
logs() { $PAGER "$service_logfile"; }
|
||||||
|
|
||||||
## Status is a bit of a special case. It's talkative.
|
## Status is a bit of a special case. It's talkative.
|
||||||
status() {
|
status() {
|
||||||
|
@ -385,234 +404,260 @@ qstatus() { nullexec status; }
|
||||||
ready() { :; }
|
ready() { :; }
|
||||||
|
|
||||||
# Main code
|
# Main code
|
||||||
main() {
|
# Figure out our full path
|
||||||
# Figure out our full path
|
case "$0" in
|
||||||
case "$0" in
|
(/*) var _self = "$0";;
|
||||||
(/*) _self=$0;;
|
(*) var _self = "$PWD/$0";;
|
||||||
(*) _self="$PWD/$0";;
|
esac
|
||||||
esac
|
|
||||||
|
|
||||||
# Needs to be global
|
# check for some environment stuff
|
||||||
declare -g service_pid
|
var EDITOR := 'vim'
|
||||||
|
var PAGER := 'less'
|
||||||
|
|
||||||
# Let's set some defaults
|
# Empty declarations
|
||||||
service_managed=1
|
var service_pid
|
||||||
usrdir='/usr/share/ssm'
|
var service_pidfile
|
||||||
systemd_service_path=( /etc/systemd/system /run/systemd/system /lib/systemd/system )
|
var service_type
|
||||||
|
var service_depends_ready
|
||||||
|
var service_command
|
||||||
|
var service_config
|
||||||
|
var service_path
|
||||||
|
var service_name
|
||||||
|
var service_args
|
||||||
|
var service_logfile
|
||||||
|
var service_ready_flag
|
||||||
|
var service_enabled_flag
|
||||||
|
var service_stopped_flag
|
||||||
|
var failed_deps
|
||||||
|
var svc_pidfile
|
||||||
|
var cfg_path
|
||||||
|
var cfg_dir
|
||||||
|
var rundir
|
||||||
|
var logdir
|
||||||
|
|
||||||
# XDG stuff
|
# Let's set some defaults
|
||||||
default XDG_CONFIG_HOME "$HOME/.config"
|
var service_managed = 0
|
||||||
default XDG_RUNTIME_DIR "/run/user/$UID"
|
var service_respawn = 0
|
||||||
|
var service_oneshot = 0
|
||||||
|
var service_running = 0
|
||||||
|
var service_enabled = 0
|
||||||
|
var service_stopped = 0
|
||||||
|
var service_systemd = 0
|
||||||
|
var service_workdir = '/'
|
||||||
|
var service_stop_timeout = 30
|
||||||
|
var service_ready_timeout = 15
|
||||||
|
var service_stop_signal = 15
|
||||||
|
var service_reload_signal = 1
|
||||||
|
var service_signals = 1 10 12
|
||||||
|
var systemd = 0
|
||||||
|
var systemd_service_path = /etc/systemd/system /run/systemd/system /lib/systemd/system
|
||||||
|
var ssm_config = 0
|
||||||
|
var usrdir = '/usr/share/ssm'
|
||||||
|
|
||||||
if (( $UID )); then
|
# XDG stuff
|
||||||
rundir="$XDG_RUNTIME_DIR/ssm"
|
var XDG_CONFIG_HOME := "$HOME/.config"
|
||||||
logdir="$HOME/log/ssm"
|
var XDG_RUNTIME_DIR := "/run/user/$UID"
|
||||||
else
|
|
||||||
rundir='/run/ssm'
|
if (( $UID )); then
|
||||||
logdir='/var/log/ssm'
|
rundir = "$XDG_RUNTIME_DIR/ssm"
|
||||||
|
logdir = "$HOME/log/ssm"
|
||||||
|
else
|
||||||
|
rundir = '/run/ssm'
|
||||||
|
logdir = '/var/log/ssm'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Warn the user of deprecated stuff.
|
||||||
|
for p in "/etc/ssm/init.d" "$XDG_CONFIG_HOME/ssm/init.d"; do
|
||||||
|
if [[ -d "$p" ]]; then
|
||||||
|
printf 'WARNING: `%s` was renamed to `%s`! Please move your scripts accordingly!\n' "$p" "${p%init.d}services" >&2
|
||||||
|
service_path += "$p"
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Warn the user of deprecated stuff.
|
# Common service path
|
||||||
for p in "/etc/ssm/init.d" "$XDG_CONFIG_HOME/ssm/init.d"; do
|
service_path += "$XDG_CONFIG_HOME/ssm/services" '/etc/ssm/services' "$rundir/services" "$usrdir/services"
|
||||||
if [[ -d "$p" ]]; then
|
|
||||||
printf 'WARNING: `%s` was renamed to `%s`! Please move your scripts accordingly!\n' "$p" "${p%init.d}services" >&2
|
|
||||||
service_path+=( "$p" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Common service path
|
# Common config path
|
||||||
service_path+=( "$XDG_CONFIG_HOME/ssm/services" '/etc/ssm/services' "$rundir/services" "$usrdir/services" )
|
cfg_path = "$XDG_CONFIG_HOME/ssm" '/etc/ssm'
|
||||||
|
|
||||||
# Common config path
|
# Load custom config and functions, reversing the PATH order
|
||||||
cfg_path+=( "$XDG_CONFIG_HOME/ssm" '/etc/ssm' )
|
for (( idx=${#cfg_path[@]}-1; idx>=0; idx-- )); do
|
||||||
|
cfg_dir = "${cfg_path[idx]}"
|
||||||
|
|
||||||
# Load custom config and functions, reversing the PATH order
|
ssm_config || {
|
||||||
for (( idx=${#cfg_path[@]}-1; idx>=0; idx-- )); do
|
[[ -f "$cfg_dir/ssm.conf" ]] && {
|
||||||
cfg_dir="${cfg_path[idx]}"
|
source "$cfg_dir/ssm.conf" || die 37 "Failed to load config: $cfg_dir/ssm.conf"
|
||||||
|
ssm_config = 1
|
||||||
(( ssm_config )) || {
|
|
||||||
[[ -f "$cfg_dir/ssm.conf" ]] && {
|
|
||||||
source "$cfg_dir/ssm.conf" || die 37 "Failed to load config: $cfg_dir/ssm.conf"
|
|
||||||
ssm_config=1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for f in "$cfg_dir/functions"/*; do
|
|
||||||
source "$f" || die 9 "Failed to source functions from $f"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
# Now create the needed runtime stuff
|
|
||||||
for d in "$rundir" "$logdir"; do
|
|
||||||
mkdir -p "$d" || die 3 "Failed to create runtime dir: $d"
|
|
||||||
done
|
|
||||||
|
|
||||||
# If $1 is a full path, source it.
|
|
||||||
# If not, search for it in the service path.
|
|
||||||
if [[ $1 == /* ]]; then
|
|
||||||
service_config=$1
|
|
||||||
else
|
|
||||||
for i in "${service_path[@]/%//$1}"; do
|
|
||||||
[[ -f "$i" ]] && {
|
|
||||||
service_config=$i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ $service_config ]] || {
|
|
||||||
# Search for a systemd service too
|
|
||||||
(( systemd )) && {
|
|
||||||
for i in "${systemd_service_path[@]/%//$1.service}"; do
|
|
||||||
[[ -f "$i" ]] && {
|
|
||||||
service_name=$1
|
|
||||||
service_systemd=1
|
|
||||||
service_config=$i
|
|
||||||
read_systemd_service "$i"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Die if there is no service config file
|
|
||||||
[[ "$service_config" ]] || die 19 "Service not found: $1"
|
|
||||||
|
|
||||||
# We can handle other people's service configs, poorly
|
|
||||||
if (( service_systemd )); then
|
|
||||||
# I'm pretty sure we'll need this
|
|
||||||
:
|
|
||||||
else
|
|
||||||
# Service name is the basename
|
|
||||||
service_name="${1##*/}"
|
|
||||||
|
|
||||||
# Get the service defaults
|
|
||||||
for p in "${cfg_path[@]/%//$service_name}"; do
|
|
||||||
[[ -f "$p" ]] && {
|
|
||||||
source "$p" || die 5 "Failed to read service defaults: $p"
|
|
||||||
}
|
|
||||||
done
|
|
||||||
|
|
||||||
# Get the service config
|
|
||||||
source -- "$service_config" "${@:3}" || die 7 "Failed to read the service config: $service_config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Legacy
|
|
||||||
[[ "$service_args" ]] && service_command=( "${service_command[@]}" "${service_args[@]}" )
|
|
||||||
[[ "$service_respawn" == 'true' ]] && service_respawn=1
|
|
||||||
[[ "$service_type" == 'oneshot' ]] && service_oneshot=1
|
|
||||||
|
|
||||||
(( service_oneshot )) && service_managed=0
|
|
||||||
[[ "$service_pidfile" ]] && service_managed=0
|
|
||||||
|
|
||||||
if ! (( service_managed )); then
|
|
||||||
(( service_respawn )) && die 21 "Refusing to respawn a service that manages itself."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Semi-hardcoded stuff
|
|
||||||
svc_pidfile="$rundir/$service_name.pid"
|
|
||||||
|
|
||||||
# Service-level defaults
|
|
||||||
default service_pidfile "$svc_pidfile"
|
|
||||||
default service_logfile "$logdir/$service_name.log"
|
|
||||||
default service_ready_flag "$rundir/$service_name.ready"
|
|
||||||
default service_enabled_flag "$rundir/$service_name.enabled"
|
|
||||||
default service_stopped_flag "$rundir/$service_name.stopped"
|
|
||||||
default service_workdir '/'
|
|
||||||
default service_stop_timeout 30
|
|
||||||
default service_ready_timeout 15
|
|
||||||
default service_stop_signal 15
|
|
||||||
default service_reload_signal 1
|
|
||||||
default service_signals 1 10 12
|
|
||||||
|
|
||||||
# Let's see if there's a PID
|
|
||||||
if [[ -f "$service_pidfile" ]]; then
|
|
||||||
service_pid=$(<$service_pidfile)
|
|
||||||
|
|
||||||
# Let's see if it's running
|
|
||||||
if nullexec kill -0 "$service_pid"; then
|
|
||||||
service_running=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Maybe the service is enabled?
|
|
||||||
if [[ -f "$service_enabled_flag" ]]; then
|
|
||||||
# Yay, it is!
|
|
||||||
service_enabled=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Let's see if the service was deliberately stopped
|
|
||||||
if [[ -f "$service_stopped_flag" ]]; then
|
|
||||||
# Ooh, it was.
|
|
||||||
service_stopped=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if action is even defined
|
|
||||||
is_function "$2" || die 17 "Function $2 is not defined for $service_name."
|
|
||||||
|
|
||||||
# cd into the workdir, if defined.
|
|
||||||
[[ "$service_workdir" ]] && {
|
|
||||||
cd "$service_workdir" || die $?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run pre_$action function
|
for f in "$cfg_dir/functions"/*; do
|
||||||
if is_function "pre_$2"; then
|
source "$f" || die 9 "Failed to source functions from $f"
|
||||||
"pre_$2" || {
|
done
|
||||||
printf 'pre_%s failed!\n' "$2"
|
done
|
||||||
die 13
|
|
||||||
|
# Now create the needed runtime stuff
|
||||||
|
for d in "$rundir" "$logdir"; do
|
||||||
|
mkdir -p "$d" || die 3 "Failed to create runtime dir: $d"
|
||||||
|
done
|
||||||
|
|
||||||
|
# If $1 is a full path, source it.
|
||||||
|
# If not, search for it in the service path.
|
||||||
|
if [[ $1 == /* ]]; then
|
||||||
|
service_config = "$1"
|
||||||
|
else
|
||||||
|
for i in "${service_path[@]/%//$1}"; do
|
||||||
|
[[ -f "$i" ]] && {
|
||||||
|
service_config = "$i"
|
||||||
|
break
|
||||||
}
|
}
|
||||||
fi
|
done
|
||||||
|
|
||||||
# Run the function
|
service_config || {
|
||||||
"$2"; res=$?
|
# Search for a systemd service too
|
||||||
|
systemd && {
|
||||||
|
for i in "${systemd_service_path[@]/%//$1.service}"; do
|
||||||
|
[[ -f "$i" ]] && {
|
||||||
|
var service_name = "$1"
|
||||||
|
var service_systemd = 1
|
||||||
|
var service_config = "$i"
|
||||||
|
|
||||||
case "$2" in
|
read_systemd_service "$i"
|
||||||
stop)
|
break
|
||||||
result "$res" \
|
}
|
||||||
0 "Stopped $service_name" \
|
done
|
||||||
3 "$service_name is not running" \
|
|
||||||
5 "Operation timed out"
|
|
||||||
;;
|
|
||||||
|
|
||||||
start)
|
|
||||||
result "$res" \
|
|
||||||
0 "Started $service_name" \
|
|
||||||
3 "$service_name is already running" \
|
|
||||||
5 "Readyness check for $service_name timed out" \
|
|
||||||
7 "Failed to start dependencies for $service_name: ${failed_deps[@]}" \
|
|
||||||
9 "service_command does not exist: ${service_command[0]}" \
|
|
||||||
13 "Failed to create temporary files for $service_name"
|
|
||||||
;;
|
|
||||||
|
|
||||||
reload)
|
|
||||||
result "$res" \
|
|
||||||
0 "Reloaded $service_name"
|
|
||||||
;;
|
|
||||||
|
|
||||||
status)
|
|
||||||
if (( service_oneshot )); then
|
|
||||||
result "$res" \
|
|
||||||
0 "$service_name is enabled" \
|
|
||||||
1 "$service_name is not enabled"
|
|
||||||
else
|
|
||||||
result "$res" \
|
|
||||||
0 "$service_name is running" \
|
|
||||||
1 "$service_name is not running" \
|
|
||||||
7 "$service_name was stopped"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
(( res )) && return "$res"
|
|
||||||
|
|
||||||
# Run post_$action function
|
|
||||||
if is_function "post_$2"; then
|
|
||||||
"post_$2" || {
|
|
||||||
printf 'post_%s failed!\n' "$2"
|
|
||||||
die 15
|
|
||||||
}
|
}
|
||||||
fi
|
}
|
||||||
}; readonly -f main
|
fi
|
||||||
|
|
||||||
main "$@"
|
# Die if there is no service config file
|
||||||
|
service_config || die 19 "Service not found: $1"
|
||||||
|
|
||||||
|
# We can handle other people's service configs, poorly
|
||||||
|
if service_systemd; then
|
||||||
|
# I'm pretty sure we'll need this
|
||||||
|
:
|
||||||
|
else
|
||||||
|
# Service name is the basename
|
||||||
|
service_name = "${1##*/}"
|
||||||
|
|
||||||
|
# Get the service defaults
|
||||||
|
for p in "${cfg_path[@]/%//$service_name}"; do
|
||||||
|
[[ -f "$p" ]] && {
|
||||||
|
source "$p" || die 5 "Failed to read service defaults: $p"
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get the service config
|
||||||
|
source -- "$service_config" "${@:3}" || die 7 "Failed to read the service config: $service_config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Legacy
|
||||||
|
service_args && service_command += "${service_args[@]}"
|
||||||
|
service_respawn == 'true' && service_respawn = 1
|
||||||
|
service_type == 'oneshot' && service_oneshot = 1
|
||||||
|
|
||||||
|
service_oneshot && service_managed = 0
|
||||||
|
service_pidfile && service_managed = 0
|
||||||
|
|
||||||
|
if ! service_managed; then
|
||||||
|
service_respawn && die 21 "Refusing to respawn a service that manages itself."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Semi-hardcoded stuff
|
||||||
|
svc_pidfile = "$rundir/$service_name.pid"
|
||||||
|
|
||||||
|
# Service-level defaults
|
||||||
|
service_pidfile := "$svc_pidfile"
|
||||||
|
service_logfile := "$logdir/$service_name.log"
|
||||||
|
service_ready_flag := "$rundir/$service_name.ready"
|
||||||
|
service_enabled_flag := "$rundir/$service_name.enabled"
|
||||||
|
service_stopped_flag := "$rundir/$service_name.stopped"
|
||||||
|
|
||||||
|
# Let's see if there's a PID
|
||||||
|
if [[ -f "$service_pidfile" ]]; then
|
||||||
|
service_pid = "$(<$service_pidfile)"
|
||||||
|
|
||||||
|
# Let's see if it's running
|
||||||
|
if nullexec kill -0 "$service_pid"; then
|
||||||
|
service_running = 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Maybe the service is enabled?
|
||||||
|
if [[ -f "$service_enabled_flag" ]]; then
|
||||||
|
# Yay, it is!
|
||||||
|
service_enabled = 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Let's see if the service was deliberately stopped
|
||||||
|
if [[ -f "$service_stopped_flag" ]]; then
|
||||||
|
# Ooh, it was.
|
||||||
|
service_stopped = 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if action is even defined
|
||||||
|
is_function "$2" || die 17 "Function $2 is not defined for $service_name."
|
||||||
|
|
||||||
|
# cd into the workdir, if defined.
|
||||||
|
service_workdir && {
|
||||||
|
cd "$service_workdir" || die $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run pre_$action function
|
||||||
|
if is_function "pre_$2"; then
|
||||||
|
"pre_$2" || {
|
||||||
|
printf 'pre_%s failed!\n' "$2"
|
||||||
|
die 13
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the function
|
||||||
|
"$2"; res=$?
|
||||||
|
|
||||||
|
case "$2" in
|
||||||
|
stop)
|
||||||
|
result "$res" \
|
||||||
|
0 "Stopped $service_name" \
|
||||||
|
3 "$service_name is not running" \
|
||||||
|
5 "Operation timed out"
|
||||||
|
;;
|
||||||
|
|
||||||
|
start)
|
||||||
|
result "$res" \
|
||||||
|
0 "Started $service_name" \
|
||||||
|
3 "$service_name is already running" \
|
||||||
|
5 "Readyness check for $service_name timed out" \
|
||||||
|
7 "Failed to start dependencies for $service_name: ${failed_deps[@]}" \
|
||||||
|
9 "service_command does not exist: ${service_command[0]}" \
|
||||||
|
13 "Failed to create temporary files for $service_name"
|
||||||
|
;;
|
||||||
|
|
||||||
|
reload)
|
||||||
|
result "$res" \
|
||||||
|
0 "Reloaded $service_name"
|
||||||
|
;;
|
||||||
|
|
||||||
|
status)
|
||||||
|
if service_oneshot; then
|
||||||
|
result "$res" \
|
||||||
|
0 "$service_name is enabled" \
|
||||||
|
1 "$service_name is not enabled"
|
||||||
|
else
|
||||||
|
result "$res" \
|
||||||
|
0 "$service_name is running" \
|
||||||
|
1 "$service_name is not running" \
|
||||||
|
7 "$service_name was stopped"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
(( res )) && return "$res"
|
||||||
|
|
||||||
|
# Run post_$action function
|
||||||
|
if is_function "post_$2"; then
|
||||||
|
"post_$2" || {
|
||||||
|
printf 'post_%s failed!\n' "$2"
|
||||||
|
die 15
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
Loading…
Reference in New Issue
Block a user