#!@BASH_PATH@ watchman_version='@VERSION@' msg() { printf '%s\n' "$*"; } err() { printf '%s\n' "$*" >&2; } usage() { while read; do msg "$REPLY"; done <<- 'EOF' Usage: watchman-svc <-p pidfile> [options] command Flags: -p -l -r # Respawn the process if it dies. -h # Show this message. -v # Show version. EOF } cleanup() { for i in "$respawn_pid" "$job_pid"; do kill_wait "$i" || { err "Failed to stop child: $i" exit 13 } done rm -f "$job_pidfile" } respawn_cleanup() { kill_wait "$job_pid" || { err "Failed to stop child: $i" exit 13 } return 0 } respawn_passthrough() { kill -"$1" "$job_pid" } kill_wait() { kill "$1" &>/dev/null counter=0 while kill -0 "$1" &>/dev/null; do sleep 1 (( counter >= 10 )) && { return 1; } (( counter++ )) done return 0 } job_run() { "${cmd[@]}" >&3 2>&3 & job_pid=$! export job_pid return 0 } job_respawn() { trap 'respawn_cleanup; return' INT TERM trap 'respawn_passthrough 1' HUP trap 'respawn_passthrough 10' USR1 trap 'respawn_passthrough 12' USR2 while job_run; do last_run=$SECONDS if kill -0 "$job_pid"; then wait "$job_pid" fi curtime=$SECONDS if (( last_run + 1 > ( curtime - 2 ) )); then err "The job exists right as we start it. Bailing." return 1 fi done } job_wait() { trap cleanup INT TERM if (( flag_respawn )); then job_respawn & respawn_pid=$! printf '%s' "$respawn_pid" > "$job_pidfile" wait "$respawn_pid" else job_run printf '%s' "$job_pid" > "$job_pidfile" wait "$job_pid" fi cleanup } main() { while (( $# )); do case "$1" in (-h) usage; return 0;; (-p) job_pidfile="$2"; shift;; (-l) job_logfile="$2"; shift;; (-r) flag_respawn=1;; (-v) printf '%s\n' "$watchman_version" exit 0 ;; (--) shift; break;; (-*) err "Unknown key: $1" usage return 1 ;; (*) break;; esac shift done if [[ -z "$job_pidfile" ]]; then usage return 1 fi cmd=( "$@" ) if [[ "$job_logfile" ]]; then exec 3>"$job_logfile" else exec 3>&1 fi job_wait & return 0 } main "$@"