diff --git a/rc.d/rc.bwbar b/rc.d/rc.bwbar new file mode 100755 index 0000000..c6a50d5 --- /dev/null +++ b/rc.d/rc.bwbar @@ -0,0 +1,124 @@ +#!/bin/bash +# Version: 0.3.0-bwbar +# Copyright (c) 2005-2022: +# Darren 'Tadgy' Austin +# Licensed under the terms of the GNU General Public License version 3. + +BWBAR_EXEC="/opt/bin/bwbar" +DAEMON_EXEC="/usr/bin/daemon" +BWBAR_ARGS=('-f' '/run/bwbar.txt' '-p' '/run/bwbar.png' '-t' '5' '-x' '800' '-y' '8' '-b' '2' '${MONINTERFACE:-eth0}' '$(( ($(ip link show "${MONINTERFACE:-eth0}" | sed -nre "s/.*qlen (.*)$/\1/ p") / 100) * 90 ))') +DAEMON_ARGS=('-N' '-n' "${0##*rc.}" '-r' '-a' '60' '-A' '5' '-L' '3600' '-M' '3' '-o daemon.debug' '--') +RUNUSER="$(whoami)" +MONINTERFACE="eth0" + +# Allow configuration in /etc/default to override. +# Additional available variables: +# ENVIRONMENT=() # Extra environment passed to $EXEC. Must be an array. +# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s. +# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s. +# RUNUSER="" # Username to run the daemon as. Default: User who starts the script. +# MONINTERFACE="" # The interface to monitor for bandwidth usage. Default: eth0. +[[ -e "/etc/default/${0##*rc.}" ]] && source "/etc/default/${0##*rc.}" + +error() { + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${BWBAR_EXEC##*/}" "$*" >&2 +} + +checkconfigured() { + # This function can be used to perform any pre-start tests; hopfully to insure the daemon + # can start correctly, before actually trying to start it. A return value of 0 means the + # tests were passed and the daemon should be started. Any other value prevents the + # daemon from being started, and an error message will be emitted. + id "${RUNUSER:-$(whoami)}" >/dev/null 2>&1 || return 1 + ip link show "${MONINTERFACE:-eth0}" >/dev/null 2>&1 || return 1 + return 0 +} + +checkstatus() { + local RET + if su - "${RUNUSER:-$(whoami)}" -c "\"$DAEMON_EXEC\" --running -n \"${0##*rc.}\""; then + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${BWBAR_EXEC##*/}" "running" + RET=0 + else + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${BWBAR_EXEC##*/}" "running" + RET=1 + fi + return $RET +} + +startdaemon() { + checkconfigured || { + error "not started - pre-start checks failed" + return 1 + } + su - "${RUNUSER:-$(whoami)}" -c "${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} \"$DAEMON_EXEC\" ${DAEMON_ARGS[*]} \"$BWBAR_EXEC\" ${BWBAR_ARGS[*]}" + if (( $? != 0 )); then + error "error starting daemon" + return 1 + else + return 0 + fi +} + +stopdaemon() { + su - "${RUNUSER:-$(whoami)}" -c "\"$DAEMON_EXEC\" -n \"${0##*rc.}\" --stop 2>/dev/null" + sleep "${SLAY_DELAY:-2}" + checkstatus >/dev/null && { + error "failed to stop gracefully - slaying" + su - "${RUNUSER:-$(whoami)}" -c "\"$DAEMON_EXEC\" -n \"${0##*rc.}\" --signal=kill 2>/dev/null" + } + return 0 +} + +for EXEC in "$BWBAR_EXEC" "$DAEMON_EXEC"; do + [[ ! -e "$EXEC" ]] && { + error "$EXEC:" "not found" + return 1 2>/dev/null || exit 1 + } + [[ ! -x "$EXEC" ]] && { + error "$EXEC:" "not executable" + return 1 2>/dev/null || exit 1 + } +done + +case "$1" in + 'start') + if checkstatus >/dev/null; then + error "already running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 + else + startdaemon + RET=$? + fi + ;; + 'stop') + if ! checkstatus >/dev/null; then + error "not running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 + else + stopdaemon + RET=$? + fi + ;; + 'restart') + if checkstatus >/dev/null; then + stopdaemon && sleep "${RESTART_DELAY:-2}" && startdaemon + RET=$? + else + startdaemon + RET=$? + fi + ;; + 'status') + checkstatus + RET=$? + ;; + *) + printf "%s\\n" "Usage: $BASH_SOURCE " >&2 + RET=1 + ;; +esac + +return $RET 2>/dev/null || exit $RET diff --git a/rc.d/rc.proftpd b/rc.d/rc.proftpd index fa5ad37..8661db1 100755 --- a/rc.d/rc.proftpd +++ b/rc.d/rc.proftpd @@ -1,66 +1,79 @@ #!/bin/bash -# Version: 0.2.9 -# Copyright (c) 2005-2017: +# Version: 0.3.0 +# Copyright (c) 2005-2022: # Darren 'Tadgy' Austin # Licensed under the terms of the GNU General Public License version 3. EXEC="/usr/sbin/proftpd" ARGS=() -PIDFILE="/var/run/proftpd.pid" +PIDFILE="/run/proftpd.pid" + +# Allow configuration in /etc/default to override. +# Additional available variables: +# ENVIRONMENT=() # Extra environment passed to $EXEC. Must be an array. +# EXTRA_ARGS=() # Extra arguments passed to $EXEC. Must be an array. +# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s. +# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s. +[[ -e "/etc/default/${0##*rc.}" ]] && source "/etc/default/${0##*rc.}" + +error() { + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "$*" >&2 +} checkconfigured() { # This function can be used to perform any pre-start tests; hopfully to insure the daemon # can start correctly, before actually trying to start it. A return value of 0 means the # tests were passed and the daemon should be started. Any other value prevents the - # daemon from being started and an error message will be emitted. + # daemon from being started, and an error message will be emitted. + ${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} "$EXEC" -t >/dev/null 2>&1 || return 1 return 0 } checkstatus() { - # Note: this has been changed from the standard 'pgrep -f "$EXEC"' as pgrep doesn't match - # the process because proftp changes its argv0. - local RUNPIDS="$(pgrep -F "$PIDFILE" 2>/dev/null)" - if [ ! -z "$RUNPIDS" ]; then - echo -n "${BASH_SOURCE##*/}: ${EXEC##*/}: running" - if [ ! -z "$PIDFILE" ]; then - if [ ! -e "$PIDFILE" ]; then - echo -n ", but .pid file does not exist" - elif ! echo "$RUNPIDS" | grep "\<$(cat "$PIDFILE")\>" >/dev/null 2>&1; then - echo -n ", but .pid file is stale" + local RUNPIDS="$({ pgrep -f "$EXEC"; pgrep -F "$PIDFILE" 2>/dev/null; } | sort -u )" + if [[ ! -z "$RUNPIDS" ]]; then + printf "%s: %s: %s" "${BASH_SOURCE##*/}" "${EXEC##*/}" "running" + if [[ ! -z "$PIDFILE" ]]; then + if [[ ! -e "$PIDFILE" ]]; then + printf "%s" ", but .pid file does not exist" + elif ! grep "\<$(< "$PIDFILE")\>" <<<"$RUNPIDS" >/dev/null 2>&1; then + printf "%s" ", but .pid file is stale" fi fi - echo + printf "\\n" else - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: stopped" + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "stopped" return 1 fi return 0 } startdaemon() { - if ! checkconfigured; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not started - pre-start checks failed" >&2 + if [[ ! -e "$EXEC" ]]; then + error "not found" return 1 - elif [ ! -e "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not found" >&2 + elif [[ ! -x "$EXEC" ]]; then + error "not executable" return 1 - elif [ ! -x "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not executable" >&2 + elif ! checkconfigured; then + error "not started - pre-start checks failed" return 1 fi - env -i -S "$EXEC" "${ARGS[@]}" - return $? + ${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} "$EXEC" ${ARGS[*]} ${EXTRA_ARGS[*]} + if (( $? != 0 )); then + error "error starting daemon" + return 1 + else + return 0 + fi } stopdaemon() { - # Note: this has been changed from the standard way of doing things because we can't use - # 'pgrep -f' to match the process since proftpd changes its argv0. - if ! kill -TERM "$(cat "$PIDFILE" 2>/dev/null)" >/dev/null 2>&1; then - sleep 2 - if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: failed to stop gracefully - slaying" >&2 - kill -KILL "$(pgrep "${EXEC##*/}")" >/dev/null 2>&1 - fi + [[ -e "$PIDFILE" ]] && kill -TERM "$(< "$PIDFILE")" >/dev/null 2>&1 || kill -TERM "$(pgrep -f "$EXEC" | tr $'\n' " ")" >/dev/null 2>&1 + sleep "${SLAY_DELAY:-2}" + if checkstatus >/dev/null; then + error "failed to stop gracefully - slaying" + kill -KILL "$({ cat "$PIDFILE"; pgrep -f "$EXEC"; } 2>/dev/null | sort -u | tr $'\n' " ")" >/dev/null 2>&1 fi return 0 } @@ -68,41 +81,41 @@ stopdaemon() { case "$1" in 'start') if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: already running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "already running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else startdaemon - ERR=$? + RET=$? fi ;; 'stop') if ! checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "not running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else stopdaemon - ERR=$? + RET=$? fi ;; 'restart') if checkstatus >/dev/null; then - stopdaemon && sleep 2 && startdaemon - ERR=$? + stopdaemon && sleep "${RESTART_DELAY:-2}" && startdaemon + RET=$? else startdaemon - ERR=$? + RET=$? fi ;; 'status') checkstatus - ERR=$? + RET=$? ;; *) - echo "Usage: $BASH_SOURCE " >&2 - ERR=1 + printf "%s\\n" "Usage: $BASH_SOURCE " >&2 + RET=1 ;; esac -return $ERR 2>/dev/null || exit $ERR +return $RET 2>/dev/null || exit $RET diff --git a/rc.d/rc.rsyncd b/rc.d/rc.rsyncd index 1e2cb16..4fa7f70 100755 --- a/rc.d/rc.rsyncd +++ b/rc.d/rc.rsyncd @@ -1,63 +1,78 @@ #!/bin/bash -# Version: 0.2.9 -# Copyright (c) 2005-2017: +# Version: 0.3.0 +# Copyright (c) 2005-2022: # Darren 'Tadgy' Austin # Licensed under the terms of the GNU General Public License version 3. EXEC="/usr/bin/rsync" -ARGS=(--daemon --config=/etc/rsyncd/rsyncd.conf) -PIDFILE="/var/run/rsyncd.pid" +ARGS=('--daemon' '--config=/etc/rsyncd/rsyncd.conf') +PIDFILE="/run/rsyncd.pid" + +# Allow configuration in /etc/default to override. +# Additional available variables: +# ENVIRONMENT=() # Extra environment passed to $EXEC. Must be an array. +# EXTRA_ARGS=() # Extra arguments passed to $EXEC. Must be an array. +# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s. +# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s. +[[ -e "/etc/default/${0##*rc.}" ]] && source "/etc/default/${0##*rc.}" + +error() { + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "$*" >&2 +} checkconfigured() { # This function can be used to perform any pre-start tests; hopfully to insure the daemon # can start correctly, before actually trying to start it. A return value of 0 means the # tests were passed and the daemon should be started. Any other value prevents the - # daemon from being started and an error message will be emitted. + # daemon from being started, and an error message will be emitted. return 0 } checkstatus() { - local RUNPIDS="$(pgrep -f "$EXEC")" - if [ ! -z "$RUNPIDS" ]; then - echo -n "${BASH_SOURCE##*/}: ${EXEC##*/}: running" - if [ ! -z "$PIDFILE" ]; then - if [ ! -e "$PIDFILE" ]; then - echo -n ", but .pid file does not exist" - elif ! echo "$RUNPIDS" | grep "\<$(cat "$PIDFILE")\>" >/dev/null 2>&1; then - echo -n ", but .pid file is stale" + local RUNPIDS="$({ pgrep -f "$EXEC"; pgrep -F "$PIDFILE" 2>/dev/null; } | sort -u )" + if [[ ! -z "$RUNPIDS" ]]; then + printf "%s: %s: %s" "${BASH_SOURCE##*/}" "${EXEC##*/}" "running" + if [[ ! -z "$PIDFILE" ]]; then + if [[ ! -e "$PIDFILE" ]]; then + printf "%s" ", but .pid file does not exist" + elif ! grep "\<$(< "$PIDFILE")\>" <<<"$RUNPIDS" >/dev/null 2>&1; then + printf "%s" ", but .pid file is stale" fi fi - echo + printf "\\n" else - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: stopped" + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "stopped" return 1 fi return 0 } startdaemon() { - if ! checkconfigured; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not started - pre-start checks failed" >&2 + if [[ ! -e "$EXEC" ]]; then + error "not found" return 1 - elif [ ! -e "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not found" >&2 + elif [[ ! -x "$EXEC" ]]; then + error "not executable" return 1 - elif [ ! -x "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not executable" >&2 + elif ! checkconfigured; then + error "not started - pre-start checks failed" return 1 fi - "$EXEC" "${ARGS[@]}" - return $? + ${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} "$EXEC" ${ARGS[*]} ${EXTRA_ARGS[*]} + if (( $? != 0 )); then + error "error starting daemon" + return 1 + else + return 0 + fi } stopdaemon() { - if ! kill -TERM "$(cat "$PIDFILE" 2>/dev/null)" >/dev/null 2>&1; then - kill -TERM "$(pgrep -f "$EXEC")" >/dev/null 2>&1 - fi - sleep 2 + [[ -e "$PIDFILE" ]] && kill -TERM "$(< "$PIDFILE")" >/dev/null 2>&1 || kill -TERM "$(pgrep -f "$EXEC" | tr $'\n' " ")" >/dev/null 2>&1 + sleep "${SLAY_DELAY:-2}" if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: failed to stop gracefully - slaying" >&2 - kill -KILL "$(pgrep -f "$EXEC")" >/dev/null 2>&1 + error "failed to stop gracefully - slaying" + kill -KILL "$({ cat "$PIDFILE"; pgrep -f "$EXEC"; } 2>/dev/null | sort -u | tr $'\n' " ")" >/dev/null 2>&1 fi return 0 } @@ -65,41 +80,41 @@ stopdaemon() { case "$1" in 'start') if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: already running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "already running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else startdaemon - ERR=$? + RET=$? fi ;; 'stop') if ! checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "not running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else stopdaemon - ERR=$? + RET=$? fi ;; 'restart') if checkstatus >/dev/null; then - stopdaemon && sleep 2 && startdaemon - ERR=$? + stopdaemon && sleep "${RESTART_DELAY:-2}" && startdaemon + RET=$? else startdaemon - ERR=$? + RET=$? fi ;; 'status') checkstatus - ERR=$? + RET=$? ;; *) - echo "Usage: $BASH_SOURCE " >&2 - ERR=1 + printf "%s\\n" "Usage: $BASH_SOURCE " >&2 + RET=1 ;; esac -return $ERR 2>/dev/null || exit $ERR +return $RET 2>/dev/null || exit $RET diff --git a/rc.d/rc.seeder b/rc.d/rc.seeder new file mode 100755 index 0000000..907bd68 --- /dev/null +++ b/rc.d/rc.seeder @@ -0,0 +1,182 @@ +#!/bin/bash +# Version: 0.3.0-seeder +# Copyright (c) 2005-2022: +# Darren 'Tadgy' Austin +# Licensed under the terms of the GNU General Public License version 3. + +SCREEN_EXEC="/usr/bin/screen" +RTORRENTWRAPPER_EXEC='$HOME/bin/rtorrent-wrapper' +DAEMON_EXEC="/usr/bin/daemon" +SCREEN_ARGS=('-c' '~/.screenrc-seeding' '-S' 'seeding') +RUNUSER="seeder" + +# Allow configuration in /etc/default to override. +# Additional available variables: +# ENVIRONMENT=() # Extra environment passed to $SCREEN_EXEC. Must be an array. +# SEEDS=() # The seeding sessions to start. Must be an array. +# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s. +# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s. +# RUNUSER="" # The username of the seeding user account. Default: seeder. +[[ -e "/etc/default/${0##*rc.}" ]] && source "/etc/default/${0##*rc.}" + +error() { + printf "%s: %s\\n" "${BASH_SOURCE##*/}" "$*" >&2 +} + +checkconfigured() { + # This function can be used to perform any pre-start tests; hopfully to insure the daemon + # can start correctly, before actually trying to start it. A return value of 0 means the + # tests were passed and the daemon should be started. Any other value prevents the + # daemon from being started, and an error message will be emitted. + id "${RUNUSER:-seeder}" >/dev/null 2>&1 || return 1 + return 0 +} + +checkstatus() { + # $@ = Name(s) of a seeding session(s) to check. + local SEED RET=0 + if [[ ! -z "$(su - "${RUNUSER:-seeder}" -c "\"$DAEMON_EXEC\" --list 2>/dev/null")" ]]; then + for SEED in "$@"; do + if su - "${RUNUSER:-seeder}" -c "\"$DAEMON_EXEC\" --running -n \"seeder-$SEED\""; then + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "seed '$SEED'" "running" + RET=${RET:+2} + else + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "seed '$SEED'" "stopped" + RET=${RET:-1} + fi + done + else + printf "%s: %s\\n" "${BASH_SOURCE##*/}" "all seeds stopped" + RET=1 + fi + return $RET +} + +startdaemon() { + # $@ = Name(s) of a seeding session(s) to start. + local EXEC SEED ERR RET + checkconfigured || { + error "seeding not started - pre-start checks failed" + return 1 + } + for EXEC in "$SCREEN_EXEC" "$(su - "${RUNUSER:-seeder}" -c "printf \"%s\" \"$RTORRENTWRAPPER_EXEC\"")"; do + [[ ! -e "$EXEC" ]] && { + error "$EXEC:" "not found" + return 1 + } + [[ ! -x "$EXEC" ]] && { + error "$EXEC:" "not executable" + return 1 + } + done + su - "${RUNUSER:-seeder}" -c "${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} \"$SCREEN_EXEC\" ${SCREEN_ARGS[*]} -ls" | grep -iv "dead" >/dev/null || { + su - "${RUNUSER:-seeder}" -c "${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} \"$SCREEN_EXEC\" ${SCREEN_ARGS[*]} -d -m" + ERR=$? + (( ERR != 0 )) && { + error "failed to start background screen:" "Error code = $ERR" + return $ERR + } + sleep 2 + } + for SEED in "$@"; do + su - "${RUNUSER:-seeder}" -c "${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} \"$SCREEN_EXEC\" ${SCREEN_ARGS[*]} -X screen -t \"$SEED\" \"$RTORRENTWRAPPER_EXEC\" \"$SEED\"" + ERR=$? + (( ERR != 0 )) && { + error "failed to add screen for '$SEED':" "Error code = $ERR" + RET=1 + continue + } + sleep 1 + done + return ${RET:-0} +} + +stopdaemon() { + # $@ = Optional name(s) of a seeding session(s) to stop. + local SEED + for SEED in "$@"; do + su - "${RUNUSER:-seeder}" -c "\"$DAEMON_EXEC\" -n \"seeder-$SEED\" --stop 2>/dev/null" + done + sleep "${SLAY_DELAY:-2}" + for SEED in "$@"; do + checkstatus >/dev/null && { + error "seed '$SEED':" "failed to stop gracefully - slaying" + su - "${RUNUSER:-seeder}" -c "\"$DAEMON_EXEC\" -n \"seeder-$SEED\" --signal=kill 2>/dev/null" + } + done + return 0 +} + +for EXEC in "$SCREEN_EXEC" "$DAEMON_EXEC"; do + [[ ! -e "$EXEC" ]] && { + error "$EXEC:" "not found" + return 1 2>/dev/null || exit 1 + } + [[ ! -x "$EXEC" ]] && { + error "$EXEC:" "not executable" + return 1 2>/dev/null || exit 1 + } +done + +OPT="$1" +shift +[[ -z "${*:-${SEEDS[@]}}" ]] && { + error "no seeding sessions specified in /etc/default/${0##*rc.} or on command line" + return 1 2>/dev/null || exit 1 +} + +case "$OPT" in + 'start') + if checkstatus "${@:-${SEEDS[@]}}" >/dev/null; then + error "seeds already running" + printf " %s\\n" "Try: $BASH_SOURCE status $@" >&2 + RET=1 + else + startdaemon "${@:-${SEEDS[@]}}" + RET=$? + fi + ;; + 'stop') + checkstatus "${@:-${SEEDS[@]}}" >/dev/null + ERR=$? + if (( ERR == 2 )) || (( ERR == 0 )); then + stopdaemon "${@:-${SEEDS[@]}}" + RET=$? + elif (( ERR == 1 )); then + error "seeds already stopped" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 + else + error "unhandled status: $ERR" + RET=1 + break + fi + ;; + 'restart') + checkstatus "${@:-${SEEDS[@]}}" >/dev/null + ERR=$? + if (( ERR == 2 )) || (( ERR == 0 )); then + stopdaemon "${@:-${SEEDS[@]}}" + sleep "${RESTART_DELAY:-2}" + startdaemon "${@:-${SEEDS[@]}}" + RET=$? + elif (( ERR == 1 )); then + startdaemon "${@:-${SEEDS[@]}}" + RET=$? + else + error "unhandled status: $ERR" + RET=1 + break + fi + ;; + 'status') + checkstatus "${@:-${SEEDS[@]}}" + RET=$? + ;; + *) + printf "%s\\n" "Usage: $BASH_SOURCE [seeding session] ..." >&2 + RET=1 + ;; +esac + +return $RET 2>/dev/null || exit $RET diff --git a/rc.d/rc.tftpd b/rc.d/rc.tftpd index 0e56d2d..6272fe4 100755 --- a/rc.d/rc.tftpd +++ b/rc.d/rc.tftpd @@ -1,63 +1,81 @@ #!/bin/bash -# Version: 0.2.9 -# Copyright (c) 2005-2017: +# Version: 0.3.0 +# Copyright (c) 2005-2022: # Darren 'Tadgy' Austin # Licensed under the terms of the GNU General Public License version 3. EXEC="/usr/sbin/in.tftpd" -ARGS=(--listen --address=FIXME --user tftp --secure /data/tftpboot) -PIDFILE="" +ARGS=('-l' '-s' '-u' '${RUNUSER:-tftp}' '-P' '/run/tftpd.pid' '/data/tftpboot') +PIDFILE="/run/tftpd.pid" +RUNUSER="tftp" + +# Allow configuration in /etc/default to override. +# Additional available variables: +# ENVIRONMENT=() # Extra environment passed to $EXEC. Must be an array. +# EXTRA_ARGS=() # Extra arguments passed to $EXEC. Must be an array. +# SLAY_DELAY="" # Delay between the SIGTERM and SIGKILL on a 'stop'. Default: 2s. +# RESTART_DELAY="" # Delay between stopping and starting on a 'restart'. Default: 2s. +# RUNUSER="" # The username to run the tftp daemon as. Default: tftp. +[[ -e "/etc/default/${0##*rc.}" ]] && source "/etc/default/${0##*rc.}" + +error() { + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "$*" >&2 +} checkconfigured() { # This function can be used to perform any pre-start tests; hopfully to insure the daemon # can start correctly, before actually trying to start it. A return value of 0 means the # tests were passed and the daemon should be started. Any other value prevents the - # daemon from being started and an error message will be emitted. + # daemon from being started, and an error message will be emitted. + id "${RUNUSER:-tftp}" >/dev/null 2>&1 || return 1 return 0 } checkstatus() { - local RUNPIDS="$(pgrep -f "$EXEC")" - if [ ! -z "$RUNPIDS" ]; then - echo -n "${BASH_SOURCE##*/}: ${EXEC##*/}: running" - if [ ! -z "$PIDFILE" ]; then - if [ ! -e "$PIDFILE" ]; then - echo -n ", but .pid file does not exist" - elif ! echo "$RUNPIDS" | grep "\<$(cat "$PIDFILE")\>" >/dev/null 2>&1; then - echo -n ", but .pid file is stale" + local RUNPIDS="$({ pgrep -f "$EXEC"; pgrep -F "$PIDFILE" 2>/dev/null; } | sort -u )" + if [[ ! -z "$RUNPIDS" ]]; then + printf "%s: %s: %s" "${BASH_SOURCE##*/}" "${EXEC##*/}" "running" + if [[ ! -z "$PIDFILE" ]]; then + if [[ ! -e "$PIDFILE" ]]; then + printf "%s" ", but .pid file does not exist" + elif ! grep "\<$(< "$PIDFILE")\>" <<<"$RUNPIDS" >/dev/null 2>&1; then + printf "%s" ", but .pid file is stale" fi fi - echo + printf "\\n" else - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: stopped" + printf "%s: %s: %s\\n" "${BASH_SOURCE##*/}" "${EXEC##*/}" "stopped" return 1 fi return 0 } startdaemon() { - if ! checkconfigured; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not started - pre-start checks failed" >&2 + if [[ ! -e "$EXEC" ]]; then + error "not found" return 1 - elif [ ! -e "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not found" >&2 + elif [[ ! -x "$EXEC" ]]; then + error "not executable" return 1 - elif [ ! -x "$EXEC" ]; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not executable" >&2 + elif ! checkconfigured; then + error "not started - pre-start checks failed" return 1 fi - "$EXEC" "${ARGS[@]}" - return $? + ${ENVIRONMENT:+declare ${ENVIRONMENT[*]};} "$EXEC" ${ARGS[*]} ${EXTRA_ARGS[*]} + if (( $? != 0 )); then + error "error starting daemon" + return 1 + else + return 0 + fi } stopdaemon() { - if ! kill -TERM "$(cat "$PIDFILE" 2>/dev/null)" >/dev/null 2>&1; then - kill -TERM "$(pgrep -f "$EXEC")" >/dev/null 2>&1 - fi - sleep 2 + [[ -e "$PIDFILE" ]] && kill -TERM "$(< "$PIDFILE")" >/dev/null 2>&1 || kill -TERM "$(pgrep -f "$EXEC" | tr $'\n' " ")" >/dev/null 2>&1 + sleep "${SLAY_DELAY:-2}" if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: failed to stop gracefully - slaying" >&2 - kill -KILL "$(pgrep -f "$EXEC")" >/dev/null 2>&1 + error "failed to stop gracefully - slaying" + kill -KILL "$({ cat "$PIDFILE"; pgrep -f "$EXEC"; } 2>/dev/null | sort -u | tr $'\n' " ")" >/dev/null 2>&1 fi return 0 } @@ -65,41 +83,41 @@ stopdaemon() { case "$1" in 'start') if checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: already running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "already running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else startdaemon - ERR=$? + RET=$? fi ;; 'stop') if ! checkstatus >/dev/null; then - echo "${BASH_SOURCE##*/}: ${EXEC##*/}: not running" >&2 - echo " Try: $BASH_SOURCE status" >&2 - ERR=1 + error "not running" + printf " %s\\n" "Try: $BASH_SOURCE status" >&2 + RET=1 else stopdaemon - ERR=$? + RET=$? fi ;; 'restart') if checkstatus >/dev/null; then - stopdaemon && sleep 2 && startdaemon - ERR=$? + stopdaemon && sleep "${RESTART_DELAY:-2}" && startdaemon + RET=$? else startdaemon - ERR=$? + RET=$? fi ;; 'status') checkstatus - ERR=$? + RET=$? ;; *) - echo "Usage: $BASH_SOURCE " >&2 - ERR=1 + printf "%s\\n" "Usage: $BASH_SOURCE " >&2 + RET=1 ;; esac -return $ERR 2>/dev/null || exit $ERR +return $RET 2>/dev/null || exit $RET