#!/bin/sh set -eu RC_MAGIC='~/rc' progname= rc_fifo= error() { local fmt="${1}" shift 1 printf "%s: ${fmt}\n" "${progname}" "${@}" return 0 } valid_session_type() { local session_type="${1}" shift 1 case "${session_type}" in *[!A-Za-z0-9:]* | '' | ':'* | *':') return 1 esac return 0 } # Returns 0 if the session is the first of its type or was last of its type # TODO: Handle decrement from 0. inc_session() { local s_type="${1}" local dir=${2} shift 2 local ret= ret=1 s_type="$(printf '%s' "${s_type}" | tr ':' '_')" eval "[ \${sessions_${s_type}:-0} -eq 0 ] && ret=0" eval "sessions_${s_type}=\$((\${sessions_${s_type}:-0} + ${dir}))" eval "[ \${sessions_${s_type}} -eq 0 ] && ret=0" return ${ret} } chg_session() { local session_type="${1}" local inc_dir=${2} local diff="${3}" shift 3 while :; do case "${session_type}" in *:*);; *) break;; esac if inc_session "${session_type}" ${inc_dir}; then diff="${diff}${session_type}," fi session_type="${session_type%:*}" done diff="${diff%,}" } beg_session() { local session_type="${1}" shift 1 chg_session "${session_type}" 1 '+' return ${?} } end_session() { local session_type="${1}" shift 1 chg_session "${session_type}" -1 '-' return ${?} } listen() { local magic= local cmd= local arg= while :; do if read -r magic cmd arg; then case "${magic}" in "${RC_MAGIC}");; *) continue esac fi case "${cmd}" in 'beg') if valid_session_type "${arg}"; then beg_session "${arg}" fi ;; 'end') if valid_session_type "${arg}"; then end_session "${arg}" fi ;; 'bye') break ;; *) continue ;; esac done 0<"${rc_fifo}" } start() { local session_type="${1}" shift 1 if mkfifo "${rc_fifo}" 2>/dev/null; then beg_session "${session_type}" listen rm "${rc_fifo}" else # Signal the running rc daemon. printf "%s beg %s\n" "${RC_MAGIC}" "${session_type}" \ 1>"${rc_fifo}" fi return 0 } stop() { local session_type="${1}" shift 1 if mkfifo "${rc_fifo}" 2>/dev/null; then # Assuming the daemon role just to end a non-existent session # makes no sense. error 'No running daemon found' rm "${rc_fifo}" return 1 else # Signal the running rc daemon. printf "%s end %s\n" "${RC_MAGIC}" "${session_type}" \ 1>"${rc_fifo}" fi return 0 } usage() { printf 'Usage: %s {start|stop} \n' "${0}" return 0 } main() { local action= local session_type= if [ ${#} -ne 2 ]; then usage 1>&2 return 1 fi action="${1}" session_type="${2}" if ! valid_session_type; then error 'Invalid session type' return 1 fi progname="${0##*/}" rc_fifo="/tmp/homercrc-$(id -u)" case "${action}" in 'start') start "${session_type}" ;; 'stop') stop "${session_type}" ;; *) usage 1>&2 return 1 ;; esac return 0 } main "${@}"