From 03b4f6ebd3c9e1f1bb6edb09bce67071417ed526 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Fri, 01 Jun 2018 13:36:36 -0400 Subject: bin/rc: Daemonize, add status cmd, and run svcs And pass old and new session type lists to services instead of list of added or removed session type and ancestor types. --- diff --git a/bin/rc b/bin/rc index 1b6c1cd..277c2aa 100755 --- a/bin/rc +++ b/bin/rc @@ -2,12 +2,14 @@ set -eu -RC_MAGIC='~/rc' +MAGIC='~/rc' progname= rc_fifo= +res_fifo= +sessions=',' -error() +info() { local fmt="${1}" shift 1 @@ -17,6 +19,16 @@ error() return 0 } +error() +{ + local fmt="${1}" + shift 1 + + printf "%s: Error: ${fmt}\n" "${progname}" "${@}" 1>&2 + + return 0 +} + valid_session_type() { local session_type="${1}" @@ -28,59 +40,97 @@ valid_session_type() 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() +run_services() { - 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 + local old_sessions="${1}" + local new_sessions="${1}" + shift 1 + local service_script= - 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%:*}" + for service_script in "${XDG_CACHE_HOME:-${HOME}/.cache}/homerc/"*; do + "$(dirname ${0})/svc" "${service_script##*/}" \ + "${old_sessions};${new_sessions}" done - - diff="${diff%,}" } beg_session() { local session_type="${1}" shift 1 + local s_type= + local add= + local new_sessions= + local old_sessions= + + s_type="$(printf '%s' "${session_type}" | tr ':' '_')" + + if eval "[ \${sessions_${s_type}:-0} -eq 0 ]"; then + add=true + else + add=false + fi + + # Increment. + eval "sessions_${s_type}=\$((\${sessions_${s_type}:-0} + 1))" - chg_session "${session_type}" 1 '+' - return ${?} + if ${add}; then + new_sessions="${sessions}${session_type}," + old_sessions="${sessions}" + sessions="${new_sessions}" + run_services "${old_sessions}" "${new_sessions}" + return ${?} + fi + + return 0 } end_session() { local session_type="${1}" shift 1 + local s_type= + local new_sessions= + local old_sessions= - chg_session "${session_type}" -1 '-' - return ${?} + s_type="$(printf '%s' "${session_type}" | tr ':' '_')" + + if eval "[ \${sessions_${s_type}:-0} -eq 0 ]"; then + error 'No running sessions of type %s' "${session_type}" + return 1 + fi + + # Decrement. + eval "sessions_${s_type}=\$((\${sessions_${s_type}} - 1))" + + if eval "[ \${sessions_${s_type}} -eq 0 ]"; then + eval "unset sessions_${s_type}" + new_sessions="${sessions%,${session_type},*}" + new_sessions="${new_sessions},${sessions#*,${session_type},}" + old_sessions="${sessions}" + sessions="${new_sessions}" + run_services "${old_sessions}" "${new_sessions}" + return ${?} + fi + + return 0 +} + +list_sessions() +{ + local printed= + local session= + + printed=false + IFS=',' + for session in ${sessions}; do + unset IFS + if ${printed}; then + printf ', ' + fi + eval "printf '%s (%d)' '${session}' \${sessions_${session}}" + printed=true + done + unset IFS } listen() @@ -91,43 +141,72 @@ listen() while :; do if read -r magic cmd arg; then - case "${magic}" in "${RC_MAGIC}");; *) + case "${magic}" in "${MAGIC}");; *) continue esac + 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 + ;; + 'who') + { + printf '%s ' "${MAGIC}" + list_sessions + printf '\n' + } 1>"${arg}" + ;; + 'bye') + break + ;; + *) + 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}" } +run_daemon() +{ + local session_type="${1}" + shift 1 + local piddir= + + exec 0<&- 1>&- 2>&- + # TODO: + # Disassociate from its process group (usually a shell), to insulate + # itself from signals (such as HUP) sent to the process group + # Ignore all terminal I/O signals + + piddir="${XDG_CACHE_HOME:-${HOME}/.cache}/homerc" + mkdir -p "${piddir}" + rm -f "${piddir}/"* + + beg_session "${session_type}" + listen + rm "${rc_fifo}" + rm -f "${piddir}/"* + + return 0 +} + start() { local session_type="${1}" shift 1 - if mkfifo "${rc_fifo}" 2>/dev/null; then - beg_session "${session_type}" - listen - rm "${rc_fifo}" + if mkfifo -m 0600 "${rc_fifo}" 2>/dev/null; then + run_daemon "${session_type}" & else # Signal the running rc daemon. - printf "%s beg %s\n" "${RC_MAGIC}" "${session_type}" \ + printf "%s beg %s\n" "${MAGIC}" "${session_type}" \ 1>"${rc_fifo}" fi @@ -139,24 +218,58 @@ 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. + if mkfifo -m 0600 "${rc_fifo}" 2>/dev/null; then + # Daemonizing 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}" \ + printf "%s end %s\n" "${MAGIC}" "${session_type}" \ 1>"${rc_fifo}" fi return 0 } +status() +{ + local magic= + local list= + + if mkfifo -m 0600 "${rc_fifo}" 2>/dev/null; then + # Daemonizing just to list non-existent sessions makes no sense. + error 'No running daemon found' + rm "${rc_fifo}" + return 1 + else + # Establish response FIFO. + if ! mkfifo -m 0600 "${res_fifo}" 2>/dev/null; then + error 'Failed to communicate with running daemon' + return 1 + fi + # Signal the running rc daemon. + printf "%s who %s\n" "${MAGIC}" "${res_fifo}" \ + 1>"${rc_fifo}" + if read -r magic list; then + case "${magic}" in "${MAGIC}");; *) + continue + esac + info 'Sessions: %s' "${list}" + else + error 'Failed to communicate with running daemon' + rm "${res_fifo}" + return 1 + fi + fi + + return 0 +} + usage() { printf 'Usage: %s {start|stop} \n' "${0}" + printf ' or: %s status\n' "${0}" return 0 } @@ -180,6 +293,7 @@ main() progname="${0##*/}" rc_fifo="/tmp/homercrc-$(id -u)" + res_fifo="/tmp/homercres-${$}" case "${action}" in 'start') @@ -188,6 +302,9 @@ main() 'stop') stop "${session_type}" ;; + 'status') + status + ;; *) usage 1>&2 return 1 -- cgit v0.9.1