| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | #!/usr/bin/env bash | 
					
						
							|  |  |  | shopt -s nullglob | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Utility functions | 
					
						
							|  |  |  | ## Make setting default values a bit less awkward | 
					
						
							|  |  |  | default() { | 
					
						
							| 
									
										
										
										
											2017-12-08 14:39:50 +03:00
										 |  |  | 	declare -n _p=$1; shift | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	[[ "$_p" ]] || { | 
					
						
							|  |  |  | 		for v in "$@"; do | 
					
						
							|  |  |  | 			_p+=( "$v" ) | 
					
						
							|  |  |  | 		done | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Die. Why not? | 
					
						
							|  |  |  | die() { | 
					
						
							|  |  |  | 	declare code=${1:-0} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	[[ "$2" ]] && printf '%s\n' "$2" | 
					
						
							|  |  |  | 	exit "$code" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Run the command and wait for it to die | 
					
						
							|  |  |  | svc() { | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	declare job_pid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	svc::cleanup() { | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		kill -n "$service_stop_signal" "$job_pid" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 		pid_wait "$job_pid" && { | 
					
						
							| 
									
										
										
										
											2017-03-11 17:36:07 +03:00
										 |  |  | 			rm -f "$svc_pidfile" "$service_ready_flag" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-13 15:37:53 +03:00
										 |  |  | 	}; trap 'svc::cleanup' TERM | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	"$@" & job_pid=$! | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 	printf '%s' "$job_pid" > "$svc_pidfile" | 
					
						
							|  |  |  | 	wait "$job_pid" | 
					
						
							| 
									
										
										
										
											2017-03-11 17:36:07 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	svc::cleanup | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | ## Respawn | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | respawn() { | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	declare jobs job_pid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	respawn::cleanup() { | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		jobs=( $(jobs -p) ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if [[ "$jobs" ]]; then | 
					
						
							|  |  |  | 			kill -n 15 "${jobs[@]}" | 
					
						
							|  |  |  | 			wait "${jobs[@]}" | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 17:37:31 +03:00
										 |  |  | 		rm -f "$svc_pidfile" "$service_ready_flag" | 
					
						
							| 
									
										
										
										
											2017-03-11 17:36:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		exit 0 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	}; trap 'respawn::cleanup' TERM | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 	respawn::sigpass() { | 
					
						
							|  |  |  | 		declare sig=$1 pid=$2 | 
					
						
							|  |  |  | 		kill -n "$sig" "$pid" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	respawn::set_traps() { | 
					
						
							|  |  |  | 		for s in "${service_signals[@]}"; do | 
					
						
							|  |  |  | 			trap "respawn::sigpass $s \$job_pid" "$s" | 
					
						
							|  |  |  | 		done | 
					
						
							|  |  |  | 	}; respawn::set_traps | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	while true; do | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		exec "$@" & job_pid=$! | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		while nullexec kill -n 0 "$job_pid"; do | 
					
						
							|  |  |  | 			wait "$job_pid" | 
					
						
							|  |  |  | 		done | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Run a command with its output discarded | 
					
						
							|  |  |  | nullexec() { | 
					
						
							|  |  |  | 	"$@" &>/dev/null | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Wait for a pid to die | 
					
						
							|  |  |  | pid_wait() { | 
					
						
							|  |  |  | 	declare cnt=0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while nullexec kill -0 "$1"; do | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 		(( cnt >= (service_stop_timeout*10) )) && return 1 | 
					
						
							|  |  |  | 		sleep 0.1 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		(( cnt++ )) | 
					
						
							|  |  |  | 	done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## See if NAME is a function | 
					
						
							|  |  |  | is_function() { | 
					
						
							| 
									
										
										
										
											2017-07-13 16:20:57 +03:00
										 |  |  | 	declare name=$1 name_type | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	name_type=$( type -t "$name" ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if [[ $name_type == 'function' ]]; then | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | ## Simple timer | 
					
						
							|  |  |  | timer() { | 
					
						
							| 
									
										
										
										
											2017-07-13 16:25:41 +03:00
										 |  |  | 	declare cnt=0 timeout=$1 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	shift | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ! "$@"; do | 
					
						
							|  |  |  | 		(( cnt >= (timeout*10) )) && return 1 | 
					
						
							|  |  |  | 		sleep 0.1 | 
					
						
							|  |  |  | 		(( cnt++ )) | 
					
						
							|  |  |  | 	done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Is a service ready? | 
					
						
							|  |  |  | is_ready() [[ -f "$service_ready_flag" ]] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Wait for this service to get ready | 
					
						
							|  |  |  | wait_ready() { | 
					
						
							|  |  |  | 	timer "$service_ready_timeout" is_ready | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Depend on other services to be started | 
					
						
							|  |  |  | depend() { | 
					
						
							|  |  |  | 	declare s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for s in "$@"; do | 
					
						
							| 
									
										
										
										
											2017-12-14 07:07:48 +03:00
										 |  |  | 		if ! "$_self" "$s" qstatus; then | 
					
						
							|  |  |  | 			nullexec "$_self" "$s" start || { | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 				failed_deps+=( "$s" ) | 
					
						
							|  |  |  | 				return 1 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 	done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | ## Create tmpfiles | 
					
						
							|  |  |  | mktmpfiles() { | 
					
						
							|  |  |  | 	declare f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for f in "${service_tmpfiles[@]}"; do | 
					
						
							|  |  |  | 		IFS=':' read -r f_path f_type f_args <<< "$f" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ! [[ -e $f_path ]]; then | 
					
						
							|  |  |  | 			case "$f_type" in | 
					
						
							|  |  |  | 				symlink) ln -s "$f_args" "$f_path";; | 
					
						
							|  |  |  | 				file|dir) IFS=':' read -r f_perms f_owner f_group <<< "$f_args" | 
					
						
							|  |  |  | 					if [[ $f_type == 'file' ]]; then | 
					
						
							|  |  |  | 						> "$f_path" | 
					
						
							|  |  |  | 						chmod "${f_perms:-644}" "$f_path" | 
					
						
							|  |  |  | 					elif [[ "$f_type" == 'dir' ]]; then | 
					
						
							|  |  |  | 						mkdir -p -m "${f_perms:-755}" "$f_path" | 
					
						
							|  |  |  | 					fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if [[ "$f_owner" || "$f_group" ]]; then | 
					
						
							|  |  |  | 						chown "${f_owner:-root}:${f_group:-root}" "$f_path" | 
					
						
							|  |  |  | 					fi;; | 
					
						
							|  |  |  | 			esac | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 	done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | ## Depend on other services to be ready | 
					
						
							|  |  |  | depend_ready() { | 
					
						
							|  |  |  | 	declare s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	depend "$@" || return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for s in "$@"; do | 
					
						
							| 
									
										
										
										
											2017-12-14 07:07:48 +03:00
										 |  |  | 		"$_self" "$s" wait_ready || { | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 			failed_deps+=( "$s" ) | 
					
						
							|  |  |  | 			return 1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	done | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Super functions | 
					
						
							|  |  |  | ## Start the service, write down the svc pid | 
					
						
							|  |  |  | super_start() { | 
					
						
							|  |  |  | 	(( service_running )) && return 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 	rm -f "$service_stopped_flag" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	[[ -f "${service_command[0]}" ]] || return 9 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	depend "${service_depends[@]}" || return 7 | 
					
						
							|  |  |  | 	depend_ready "${service_depends_ready[@]}" || return 7 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 	mktmpfiles || return 13 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	if (( service_managed )); then | 
					
						
							|  |  |  | 		if (( service_respawn )); then | 
					
						
							|  |  |  | 			svc respawn "${service_command[@]}" &>"$service_logfile" & | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			svc "${service_command[@]}" &>"$service_logfile" & | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		if timer "$service_ready_timeout" ready; then | 
					
						
							|  |  |  | 			printf '1' > "$service_ready_flag" | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return 5 | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 	elif (( service_oneshot )); then | 
					
						
							| 
									
										
										
										
											2016-11-17 12:26:23 +03:00
										 |  |  | 		"${service_command[@]}" &>"$service_logfile"; res=$? | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		(( $res )) && return "$res" | 
					
						
							|  |  |  | 		printf '1' > "$service_enabled_flag" | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		exec "${service_command[@]}" & | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | # A separate function for oneshot services | 
					
						
							|  |  |  | super_oneshot() { | 
					
						
							|  |  |  | 	(( service_enabled )) && return 3 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | ## Reload the service | 
					
						
							|  |  |  | ## Usually just sends HUP | 
					
						
							|  |  |  | super_reload() { | 
					
						
							|  |  |  | 	(( service_running )) || return 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	if (( service_managed )); then | 
					
						
							|  |  |  | 		kill -n 1 "$service_pid" | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		kill -n "$service_reload_signal" "$service_pid" | 
					
						
							|  |  |  | 	fi | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Stop the service | 
					
						
							|  |  |  | ## Returns: | 
					
						
							|  |  |  | ##   3: Service is not running. | 
					
						
							|  |  |  | super_stop() { | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	if (( service_oneshot )); then | 
					
						
							|  |  |  | 		(( service_enabled )) || return 3 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		rm -f "$service_enabled_flag" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 		return 0 | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		(( service_running )) || return 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nullexec kill -n "$service_stop_signal" "$service_pid" || return 1 | 
					
						
							|  |  |  | 		pid_wait "$service_pid" || return 5 | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 		> "$service_stopped_flag" | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	fi | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 17:36:07 +03:00
										 |  |  | info() { | 
					
						
							| 
									
										
										
										
											2017-03-11 17:57:16 +03:00
										 |  |  | 	declare \ | 
					
						
							|  |  |  | 		_status_label='Running' \ | 
					
						
							|  |  |  | 		_status='no' | 
					
						
							|  |  |  | 		_type='daemon' | 
					
						
							|  |  |  | 		_info_items=() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(( service_oneshot )) && { | 
					
						
							|  |  |  | 		_status_label='Enabled' | 
					
						
							|  |  |  | 		_type='oneshot' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	status && _status='yes' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_info_items=( | 
					
						
							|  |  |  | 		"Name"            "$service_name" | 
					
						
							|  |  |  | 		"Type"            "$_type" | 
					
						
							|  |  |  | 		"$_status_label"  "$_status" | 
					
						
							| 
									
										
										
										
											2017-11-14 16:58:53 +03:00
										 |  |  | 		"Exec"            "${service_command[*]} ${service_args[*]}" | 
					
						
							| 
									
										
										
										
											2017-03-11 17:57:16 +03:00
										 |  |  | 		"Respawn"         "${service_respawn:-false}" | 
					
						
							| 
									
										
										
										
											2017-12-10 19:48:22 +03:00
										 |  |  | 		"Config path"     "${service_config}" | 
					
						
							| 
									
										
										
										
											2017-03-11 17:57:16 +03:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	[[ "$_status" == 'yes' ]] && { | 
					
						
							|  |  |  | 		_info_items+=( | 
					
						
							|  |  |  | 			"PIDfile"  "${service_pidfile:-none}" | 
					
						
							|  |  |  | 			"PID"      "${service_pid:-none}" | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printf "%12s: %s\n" "${_info_items[@]}" | 
					
						
							| 
									
										
										
										
											2017-03-11 17:36:07 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | result() { | 
					
						
							|  |  |  | 	declare rc=$1; shift | 
					
						
							|  |  |  | 	declare -A msgs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (( $# )); do | 
					
						
							|  |  |  | 		[[ "$2" ]] || return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		msgs["$1"]="$2" | 
					
						
							|  |  |  | 		shift 2 | 
					
						
							|  |  |  | 	done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	[[ "${msgs[$rc]}" ]] || msgs["$rc"]="Failed!" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printf '%s\n' "${msgs[$rc]}" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | # Overloadable functions | 
					
						
							|  |  |  | start() { super_start; } | 
					
						
							|  |  |  | stop() { super_stop; } | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | reload() { super_reload; } | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | restart() { | 
					
						
							| 
									
										
										
										
											2017-12-14 07:07:48 +03:00
										 |  |  | 	"$_self" "$service_name" stop | 
					
						
							|  |  |  | 	"$_self" "$service_name" start | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-14 16:58:53 +03:00
										 |  |  | logs() { ${PAGER:-less} "$service_logfile"; } | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Status is a bit of a special case. It's talkative. | 
					
						
							|  |  |  | status() { | 
					
						
							|  |  |  | 	(( service_running )) && return 0 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	(( service_enabled )) && return 0 | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 	(( service_stopped )) && return 7 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	return 1 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## For use in scripts | 
					
						
							|  |  |  | qstatus() { nullexec status; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## By default there is no ready check | 
					
						
							|  |  |  | ready() { :; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | # Code | 
					
						
							|  |  |  | main() { | 
					
						
							| 
									
										
										
										
											2017-12-14 07:07:48 +03:00
										 |  |  | 	# Figure out our full path | 
					
						
							|  |  |  | 	case "$0" in | 
					
						
							|  |  |  | 		(/*) _self=$0;; | 
					
						
							|  |  |  | 		(*) _self="$PWD/$0";; | 
					
						
							|  |  |  | 	esac | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 	# Needs to be global | 
					
						
							|  |  |  | 	declare -g service_pid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# Let's set some defaults | 
					
						
							|  |  |  | 	service_managed=1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 15:16:03 +03:00
										 |  |  | 	usrdir='/usr/share/ssm' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	if (( $UID )); then | 
					
						
							|  |  |  | 		# XDG stuff | 
					
						
							|  |  |  | 		default XDG_CONFIG_HOME "$HOME/.config" | 
					
						
							|  |  |  | 		default XDG_RUNTIME_DIR "/run/user/$UID" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-10 19:27:51 +03:00
										 |  |  | 		service_path=( "$XDG_CONFIG_HOME/ssm/services" ) | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 		cfg_path=( "$XDG_CONFIG_HOME/ssm" ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-10 19:42:25 +03:00
										 |  |  | 		# Warn the user of deprecated stuff. | 
					
						
							|  |  |  | 		if [[ -d "$XDG_CONFIG_HOME/ssm/init.d" ]]; then | 
					
						
							|  |  |  | 			printf 'WARNING: `%s` was renamed to `%s`! Please move your scripts accordingly!\n' \ | 
					
						
							|  |  |  | 				"$XDG_CONFIG_HOME/ssm/init.d" \ | 
					
						
							|  |  |  | 				"$XDG_CONFIG_HOME/ssm/services" >&2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			service_path+=( "$XDG_CONFIG_HOME/ssm/init.d" ) | 
					
						
							|  |  |  | 		fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 19:20:10 +03:00
										 |  |  | 		rundir="$XDG_RUNTIME_DIR/ssm" | 
					
						
							|  |  |  | 		logdir="$HOME/log/ssm" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2016-11-13 19:20:10 +03:00
										 |  |  | 		rundir='/run/ssm' | 
					
						
							|  |  |  | 		logdir='/var/log/ssm' | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-10 19:42:25 +03:00
										 |  |  | 	# Warn the user of deprecated stuff. | 
					
						
							|  |  |  | 	if [[ -d "/etc/ssm/init.d" ]]; then | 
					
						
							|  |  |  | 		printf 'WARNING: `/etc/ssm/init.d` was renamed to `/etc/ssm/services`! Please move your scripts accordingly!\n' >&2 | 
					
						
							|  |  |  | 		service_path+=( "/etc/ssm/init.d" ) | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 	# Common service path | 
					
						
							| 
									
										
										
										
											2017-12-10 19:27:51 +03:00
										 |  |  | 	service_path+=( '/etc/ssm/services' "$rundir/services" "$usrdir/services" ) | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	# Common config path | 
					
						
							| 
									
										
										
										
											2017-12-10 20:13:51 +03:00
										 |  |  | 	cfg_path+=( '/etc/ssm' ) | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# Load custom functions | 
					
						
							| 
									
										
										
										
											2017-12-08 16:49:34 +03:00
										 |  |  | 	for (( idx=${#cfg_path[@]}-1; idx>=0; idx-- )); do | 
					
						
							|  |  |  | 		cfg_dir="${cfg_path[idx]}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for f in "$cfg_dir/functions"/*; do | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 			source "$f" || die 9 "Failed to source functions from $f" | 
					
						
							|  |  |  | 		done | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-14 06:31:53 +03:00
										 |  |  | 	# If $1 is a full path, source it. | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 	# If not, search for it in the service path. | 
					
						
							| 
									
										
										
										
											2016-11-14 06:31:53 +03:00
										 |  |  | 	if [[ $1 == /* ]]; then | 
					
						
							|  |  |  | 		service_config=$1 | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 		for i in "${service_path[@]}"; do | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 			[[ -f "$i/$1" ]] && { | 
					
						
							|  |  |  | 				service_config="$i/$1" | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 		done | 
					
						
							| 
									
										
										
										
											2016-11-14 06:31:53 +03:00
										 |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# Die if there is no such file | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 	[[ "$service_config" ]] || die 19 "Service not found: $1" | 
					
						
							| 
									
										
										
										
											2016-11-14 06:31:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	# Service name is the basename | 
					
						
							|  |  |  | 	service_name="${1##*/}" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	# Semi-hardcoded stuff | 
					
						
							|  |  |  | 	svc_pidfile="$rundir/$service_name.pid" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# Get the service defaults | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 	for p in "${cfg_path[@]}"; do | 
					
						
							|  |  |  | 		[[ -f "$p/conf.d/$service_name" ]] && { | 
					
						
							|  |  |  | 			source "$p/conf.d/$service_name" || die 5 "Failed to read service defaults: $p/conf.d/$service_name" | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	done | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	# Get the service config | 
					
						
							| 
									
										
										
										
											2017-12-08 16:39:05 +03:00
										 |  |  | 	source -- "$service_config" "${@:3}" || die 7 "Failed to read the service config: $service_config" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	# Legacy | 
					
						
							|  |  |  | 	[[ "$service_args" ]] && service_command=( "${service_command[@]}" "${service_args[@]}" ) | 
					
						
							|  |  |  | 	[[ "$service_respawn" == 'true' ]] && service_respawn=1 | 
					
						
							| 
									
										
										
										
											2017-03-12 04:30:36 +03:00
										 |  |  | 	[[ "$service_type" == 'oneshot' ]] && service_oneshot=1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(( service_oneshot )) && service_managed=0 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	[[ "$service_pidfile" ]] && service_managed=0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ! (( service_managed )); then | 
					
						
							|  |  |  | 		(( service_respawn )) && die 21 "Refusing to respawn a service that manages itself." | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# Service-level defaults | 
					
						
							| 
									
										
										
										
											2017-12-08 14:39:50 +03:00
										 |  |  | 	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" | 
					
						
							| 
									
										
										
										
											2017-12-14 07:07:48 +03:00
										 |  |  | 	default service_workdir         '/' | 
					
						
							| 
									
										
										
										
											2017-12-08 14:39:50 +03:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2016-11-13 17:33:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 16:31:17 +03:00
										 |  |  | 	# Maybe the service is enabled? | 
					
						
							|  |  |  | 	if [[ -f "$service_enabled_flag" ]]; then | 
					
						
							|  |  |  | 		# Yay, it is! | 
					
						
							|  |  |  | 		service_enabled=1 | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 	# Let's see if the service was deliberately stopped | 
					
						
							|  |  |  | 	if [[ -f "$service_stopped_flag" ]]; then | 
					
						
							|  |  |  | 		# Ooh, it was. | 
					
						
							|  |  |  | 		service_stopped=1 | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# Check if action is even defined | 
					
						
							|  |  |  | 	is_function "$2" || die 17 "Function $2 is not defined for $service_name." | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 	# cd into the workdir, if defined. | 
					
						
							|  |  |  | 	[[ "$service_workdir" ]] && { | 
					
						
							|  |  |  | 		cd "$service_workdir" || die $? | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# Run pre_$action function | 
					
						
							|  |  |  | 	if is_function "pre_$2"; then | 
					
						
							|  |  |  | 		"pre_$2" || { | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 			printf 'pre_%s failed!\n' "$2" | 
					
						
							|  |  |  | 			die 13 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	# Run the function | 
					
						
							| 
									
										
										
										
											2017-07-13 15:37:53 +03:00
										 |  |  | 	"$2"; res=$? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	case "$2" in | 
					
						
							|  |  |  | 		stop) | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | 			result "$res" \ | 
					
						
							|  |  |  | 				0 "Stopped $service_name" \ | 
					
						
							|  |  |  | 				3 "$service_name is not running" \ | 
					
						
							|  |  |  | 				5 "Operation timed out" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		;; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		start) | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | 			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" | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		;; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 		reload) | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | 			result "$res" \ | 
					
						
							|  |  |  | 				0 "Reloaded $service_name" | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 		;; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		status) | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | 			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" \ | 
					
						
							| 
									
										
										
										
											2017-11-09 04:19:26 +03:00
										 |  |  | 					1 "$service_name is not running" \ | 
					
						
							|  |  |  | 					7 "$service_name was stopped" | 
					
						
							| 
									
										
										
										
											2016-11-17 13:11:11 +03:00
										 |  |  | 			fi | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 		;; | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	esac | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 	(( res )) && return "$res" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 	# Run post_$action function | 
					
						
							|  |  |  | 	if is_function "post_$2"; then | 
					
						
							|  |  |  | 		"post_$2" || { | 
					
						
							| 
									
										
										
										
											2016-11-13 14:47:20 +03:00
										 |  |  | 			printf 'post_%s failed!\n' "$2" | 
					
						
							|  |  |  | 			die 15 | 
					
						
							| 
									
										
										
										
											2016-11-13 11:11:47 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | main "$@" |