#!/bin/sh # DaemonTamer: simple and portable local service manager in pure sh # that allows to quickly daemonize any command and manage it as a service # Depends on POSIX versions of sh, nohup, cut and grep # the unreg option also depends on mktemp (not POSIX but present everywhere) # Run sh dt help to see the parameters # Created by Luxferre in 2025, released into public domain with no warranties err() { echo $* exit 1 } msgexit() { echo $* exit 0 } find_service() { sline="$(grep -E "^$1\s+" $CONF)" [ -z "$sline" ] && err "No such service found in the config!" echo "$sline" } CONF="$HOME/.dt.conf" TMPDIR="$(dirname $(mktemp -u))" srv_name="$2" [ "$1" != "help" ] && [ -z "$srv_name" ] && err "Service name is required!" pidfile="$TMPDIR/$srv_name.pid" case $1 in help) echo 'DaemonTamer v2' echo '--------------' echo "Usage: $0 {reg|unreg|start|stop|restart} SERVICE_NAME [REG_PARAMS]" echo 'Parameters for the reg subcommand:' echo "$0 reg 'COMMAND' [WORKDIR] [STDOUT_LOG_FILE] [STDERR_LOG_FILE] [PRESTART] [POSTSTART] [PRESTOP] [POSTSTOP]" echo '(the COMMAND must be specified in single quotes and without nohup)' echo echo 'Created by Luxferre in 2025, released into public domain with no warranties' ;; reg) srv_cmd="$3" [ -z "$srv_cmd" ] && err "Service runner command is required!" srv_wdir="$4" srv_outlog="$5" srv_errlog="$6" srv_prestart="$7" srv_poststart="$8" srv_prestop="$9" srv_poststop="$10" [ -z "$srv_wdir" ] && srv_wdir='-' [ -z "$srv_outlog" ] && srv_outlog='/dev/null' [ -z "$srv_errlog" ] && srv_errlog='/dev/null' [ -z "$srv_prestart" ] && srv_prestart='-' [ -z "$srv_poststart" ] && srv_poststart='-' [ -z "$srv_prestop" ] && srv_prestop='-' [ -z "$srv_poststop" ] && srv_poststop='-' printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" "$srv_name" "$srv_cmd" \ "$srv_wdir" "$srv_outlog" "$srv_errlog" "$srv_prestart" "$srv_poststart" \ "$srv_prestop" "$srv_poststop" >> $CONF echo "Service $srv_name registered" ;; unreg) srvline="$(find_service "$srv_name")" TCONF="$(mktemp)" grep -v "$srv_name" $CONF > $TCONF && mv $TCONF $CONF echo "Service $srv_name unregistered" ;; start) [ -f "$pidfile" ] && msgexit "Service $srv is already running"; srvline="$(find_service "$srv_name")" srv_cmd="$(echo "$srvline" | cut -f2)" srv_wdir="$(echo "$srvline" | cut -f3)" srv_outlog="$(echo "$srvline" | cut -f4)" srv_errlog="$(echo "$srvline" | cut -f5)" srv_prestart="$(echo "$srvline" | cut -f6)" srv_poststart="$(echo "$srvline" | cut -f7)" echo "Starting service $srv_name" [ "$srv_wdir" != "-" ] && cd "$srv_wdir" [ "$srv_prestart" != "-" ] && $SHELL -c "$srv_prestart" nohup $srv_cmd >$srv_outlog 2>$srv_errlog & echo $! > $pidfile [ "$srv_poststart" != "-" ] && $SHELL -c "$srv_poststart" echo "Service $srv_name started" ;; stop) [ ! -f "$pidfile" ] && msgexit "Service $srv is not running"; srvline="$(find_service "$srv_name")" srv_prestop="$(echo "$srvline" | cut -f8)" srv_poststop="$(echo "$srvline" | cut -f9)" echo "Stopping service $srv_name" [ "$srv_prestop" != "-" ] && $SHELL -c "$srv_prestop" kill $(cat $pidfile) rm -f $pidfile [ "$srv_poststop" != "-" ] && $SHELL -c "$srv_poststop" echo "Service $srv_name stopped" ;; restart) srvline="$(find_service "$srv_name")" $SHELL $0 stop $srv_name $SHELL $0 start $srv_name ;; *) echo 'Invalid operation! Pick start, stop, restart, reg, unreg or help' ;; esac