normalize indentation to spaces

This commit is contained in:
Tilman Kranz 2025-03-29 18:52:25 +01:00
parent a6218a0d96
commit 2b07a5ee42

View File

@ -32,135 +32,135 @@ config="$config_dir"/config.inc.sh
# Functions # Functions
_ssh() { _ssh() {
if ssh -S "$USER"-pulseaudio "$remote_user"@"$remote_ip" "$@" ; then if ssh -S "$USER"-pulseaudio "$remote_user"@"$remote_ip" "$@" ; then
return 0 return 0
else else
echo "ERROR: SSH remote_ip=$remote_ip failed." >&2 echo "ERROR: SSH remote_ip=$remote_ip failed." >&2
return 1 return 1
fi fi
} }
# Perform setup operation # Perform setup operation
do_setup() { do_setup() {
if test -e "$config" ; then if test -e "$config" ; then
read -r -p "config=$config already exists, overwrite it? (Y|n) " answer read -r -p "config=$config already exists, overwrite it? (Y|n) " answer
case "$answer" in case "$answer" in
y|Y|"") y|Y|"")
if ! test -w "$config" ; then if ! test -w "$config" ; then
echo "ERROR: config=$config is not writable." >&2 ; echo "ERROR: config=$config is not writable." >&2 ;
return 1 ; return 1 ;
elif ! test -r "$config" ; then elif ! test -r "$config" ; then
echo "ERROR: config=$config is not readable." >&2 ; echo "ERROR: config=$config is not readable." >&2 ;
return 1 ; return 1 ;
else else
. "$config" . "$config"
fi fi
;; ;;
*) *)
echo "ERROR: Setup aborted." >&2 echo "ERROR: Setup aborted." >&2
return 1 return 1
esac esac
elif ! test -e "$config_dir" ; then elif ! test -e "$config_dir" ; then
mkdir -p "$config_dir" || { mkdir -p "$config_dir" || {
echo "ERROR: Could not create config_dir=$config_dir." >&2 ; echo "ERROR: Could not create config_dir=$config_dir." >&2 ;
return 1 ; return 1 ;
} }
elif ! test -d "$config_dir" ; then elif ! test -d "$config_dir" ; then
echo "ERROR: config_dir=$config_dir is not a directory." >&2 echo "ERROR: config_dir=$config_dir is not a directory." >&2
return 1 return 1
elif ! test -w "$config_dir" ; then elif ! test -w "$config_dir" ; then
echo "ERROR: config_dir=$config_dir is not writable." >&2 echo "ERROR: config_dir=$config_dir is not writable." >&2
return 1 return 1
fi fi
while true ; do while true ; do
read -r -p "Enter IP address of remote host ($remote_ip): " remote_ip_in read -r -p "Enter IP address of remote host ($remote_ip): " remote_ip_in
if test -n "$remote_ip_in" ; then if test -n "$remote_ip_in" ; then
break break
elif test -n "$remote_ip" ; then elif test -n "$remote_ip" ; then
remote_ip_in=$remote_ip remote_ip_in=$remote_ip
break break
fi fi
done done
while true ; do while true ; do
read -r -p "Enter username on remote host $remote_ip ($remote_user): " remote_user_in read -r -p "Enter username on remote host $remote_ip ($remote_user): " remote_user_in
if test -n "$remote_user_in" ; then if test -n "$remote_user_in" ; then
break break
elif test -n "$remote_user" ; then elif test -n "$remote_user" ; then
remote_user_in=$remote_user remote_user_in=$remote_user
break break
fi fi
done done
inbound=${inbound:-true} inbound=${inbound:-true}
while true ; do while true ; do
if "$inbound" ; then if "$inbound" ; then
prompt="Y/n" prompt="Y/n"
else else
prompt="y/N" prompt="y/N"
fi fi
read -r -p "Enable inbound audio ($prompt): " inbound_in read -r -p "Enable inbound audio ($prompt): " inbound_in
case "$inbound_in" in case "$inbound_in" in
"") "")
if test -n "$inbound" ; then if test -n "$inbound" ; then
inbound_in=$inbound inbound_in=$inbound
break 2 break 2
fi fi
;; ;;
y|Y) y|Y)
inbound_in=true inbound_in=true
break 2 break 2
;; ;;
n|N) n|N)
inbound_in=false inbound_in=false
break 2 break 2
;; ;;
*) *)
echo "ERROR: Please type \"y\" or \"n\"." >&2 echo "ERROR: Please type \"y\" or \"n\"." >&2
;; ;;
esac esac
done done
outbound=${outbound:-true} outbound=${outbound:-true}
while true ; do while true ; do
if "$outbound" ; then if "$outbound" ; then
prompt="Y/n" prompt="Y/n"
else else
prompt="y/N" prompt="y/N"
fi fi
read -r -p "Enable outbound audio ($prompt): " outbound_in read -r -p "Enable outbound audio ($prompt): " outbound_in
case "$outbound_in" in case "$outbound_in" in
"") "")
if test -n "$outbound" ; then if test -n "$outbound" ; then
outbound_in=$outbound outbound_in=$outbound
break 2 break 2
fi fi
;; ;;
y|Y) y|Y)
outbound_in=true outbound_in=true
break 2 break 2
;; ;;
n|N) n|N)
outbound_in=false outbound_in=false
break 2 break 2
;; ;;
*) *)
echo "ERROR: Please type \"y\" or \"n\"." >&2 echo "ERROR: Please type \"y\" or \"n\"." >&2
;; ;;
esac esac
done done
cat > "$config" << EOF cat > "$config" << EOF
# Configuration file for pulseaudio-tcp # Configuration file for pulseaudio-tcp
# Generated on $(LC_ALL=C date) by $USER using $0 # Generated on $(LC_ALL=C date) by $USER using $0
@ -180,231 +180,227 @@ EOF
# Check if SSH port forwarding is running # Check if SSH port forwarding is running
check_pa_ssh() { check_pa_ssh() {
for pid in $(pidof ssh) ; do for pid in $(pidof ssh) ; do
if grep -Fq "$USER"-pulseaudio /proc/"$pid"/cmdline ; then if grep -Fq "$USER"-pulseaudio /proc/"$pid"/cmdline && grep -Fq -e -L /proc/"$pid"/cmdline ; then
grep -Fq -e -L /proc/"$pid"/cmdline || { return 0
echo "ERROR: No SSH port forwarding to remote server is established." >&2 fi
return 1 ; done
}
fi
done
echo "ERROR: No SSH is established." >&2 return 1
return 1
} }
# Perform status operation # Perform status operation
do_status() { do_status() {
rv=0 rv=0
if ! check_pa_ssh ; then if ! check_pa_ssh ; then
rv=1 rv=1
fi fi
if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then
echo "ERROR: PulseAudio module \"module-native-protocol-tcp\" is not loaded on remote_ip=$remote_ip." >&2 echo "ERROR: PulseAudio module \"module-native-protocol-tcp\" is not loaded on remote_ip=$remote_ip." >&2
rv=1 rv=1
fi fi
if "$outbound" ; then if "$outbound" ; then
if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then
echo "ERROR: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2 echo "ERROR: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2
rv=1 rv=1
fi fi
if ! pactl get-default-sink | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then if ! pactl get-default-sink | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then
echo "ERROR: \"tunnel-sink.tcp:127.0.0.1\" is not the default PulseAudio sink." >&2 echo "ERROR: \"tunnel-sink.tcp:127.0.0.1\" is not the default PulseAudio sink." >&2
rv=1 rv=1
fi fi
fi fi
if "$inbound" ; then if "$inbound" ; then
if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then
echo "ERROR: PulseAudio module \"module-tunnel-source\" is not loaded." >&2 echo "ERROR: PulseAudio module \"module-tunnel-source\" is not loaded." >&2
rv=1 rv=1
fi fi
fi fi
if test "$rv" -eq 0 ; then if test "$rv" -eq 0 ; then
echo "INFO: All checks passed; pulseaudio-tcp status is okay." >&2 echo "INFO: All checks passed; pulseaudio-tcp status is okay." >&2
fi fi
return "$rv" return "$rv"
} }
# Acquire PulseAudio cookie from remote host # Acquire PulseAudio cookie from remote host
sync_pa_cookie() { sync_pa_cookie() {
if scp -q "$remote_user"@"$remote_ip":.config/pulse/cookie ~/.config/pulse/cookie ; then if scp -q "$remote_user"@"$remote_ip":.config/pulse/cookie ~/.config/pulse/cookie ; then
echo "INFO: Synced PulseAudio cookie from remote_ip=$remote_ip." >&2 echo "INFO: Synced PulseAudio cookie from remote_ip=$remote_ip." >&2
return 0 return 0
else else
echo "ERROR: Unable to sync PulseAudio cookie from remote_ip=$remote_ip." >&2 echo "ERROR: Unable to sync PulseAudio cookie from remote_ip=$remote_ip." >&2
return 1 return 1
fi fi
} }
# Establish SSH port forwarding to PulseAudio TCP server on remote host # Establish SSH port forwarding to PulseAudio TCP server on remote host
establish_ssh_portforward() { establish_ssh_portforward() {
_ssh -fNT -L 127.0.0.1:4713:127.0.0.1:4713 _ssh -fNT -L 127.0.0.1:4713:127.0.0.1:4713
} }
# Enable PulseAudio TCP tunnel server on remote host # Enable PulseAudio TCP tunnel server on remote host
enable_remote_pa_tunnel_server() { enable_remote_pa_tunnel_server() {
if _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then if _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then
echo "INFO: PulseAudio module \"module-native-protocol-tcp\" already loaded on remote_ip=$remote_ip." >&2 echo "INFO: PulseAudio module \"module-native-protocol-tcp\" already loaded on remote_ip=$remote_ip." >&2
return 0 return 0
elif _ssh pactl load-module module-native-protocol-tcp listen=127.0.0.1 auth-ip-acl=127.0.0.1 ; then elif _ssh pactl load-module module-native-protocol-tcp listen=127.0.0.1 auth-ip-acl=127.0.0.1 ; then
echo "INFO: Loaded PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2 echo "INFO: Loaded PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2
return 0 return 0
else else
echo "ERROR: Unable to load PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2 echo "ERROR: Unable to load PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2
return 1 return 1
fi fi
} }
# Enable tunnel sink on local host # Enable tunnel sink on local host
enable_local_pa_tunnel_sink() { enable_local_pa_tunnel_sink() {
if pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then if pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then
echo "INFO: PulseAudio module \"module-tunnel-sink\" already loaded." >&2 echo "INFO: PulseAudio module \"module-tunnel-sink\" already loaded." >&2
return 0 return 0
elif pactl load-module module-tunnel-sink server=tcp:127.0.0.1 ; then elif pactl load-module module-tunnel-sink server=tcp:127.0.0.1 ; then
echo "INFO: Loaded PulseAudio module \"module-tunnel-sink\"." >&2 echo "INFO: Loaded PulseAudio module \"module-tunnel-sink\"." >&2
return 0 return 0
else else
echo "ERROR: Unable to load PulseAudio module \"module-tunnel-sink\"." >&2 echo "ERROR: Unable to load PulseAudio module \"module-tunnel-sink\"." >&2
return 1 return 1
fi fi
} }
# Enable tunnel source on local host # Enable tunnel source on local host
enable_local_pa_tunnel_source() { enable_local_pa_tunnel_source() {
if pactl list modules | grep -Fq "Name: module-tunnel-source" ; then if pactl list modules | grep -Fq "Name: module-tunnel-source" ; then
echo "INFO: PulseAudio module \"module-tunnel-source\" already loaded." >&2 echo "INFO: PulseAudio module \"module-tunnel-source\" already loaded." >&2
return 0 return 0
elif pactl load-module module-tunnel-source server=tcp:127.0.0.1 ; then elif pactl load-module module-tunnel-source server=tcp:127.0.0.1 ; then
echo "INFO: Loaded PulseAudio module \"module-tunnel-source\"." >&2 echo "INFO: Loaded PulseAudio module \"module-tunnel-source\"." >&2
return 0 return 0
else else
echo "ERROR: Unable to load PulseAudio module \"module-tunnel-source\"." >&2 echo "ERROR: Unable to load PulseAudio module \"module-tunnel-source\"." >&2
return 1 return 1
fi fi
} }
# Set tunnel sink as default sink on local host # Set tunnel sink as default sink on local host
set_local_pa_tunnel_sink_as_default() { set_local_pa_tunnel_sink_as_default() {
if pactl set-default-sink tunnel-sink.tcp:127.0.0.1 ; then if pactl set-default-sink tunnel-sink.tcp:127.0.0.1 ; then
echo "INFO: Set \"tunnel-sink.tcp:127.0.0.1\" as default PulseAudio sink." >&2 echo "INFO: Set \"tunnel-sink.tcp:127.0.0.1\" as default PulseAudio sink." >&2
return 0 return 0
else else
echo "ERROR: Failed to set \"tunnel-sink.tcp:127.0.0.1\" as default PulseAudio sink." >&2 echo "ERROR: Failed to set \"tunnel-sink.tcp:127.0.0.1\" as default PulseAudio sink." >&2
return 1 return 1
fi fi
} }
# Perform start operation # Perform start operation
do_start() { do_start() {
sync_pa_cookie || return 1 sync_pa_cookie || return 1
establish_ssh_portforward || return 1 establish_ssh_portforward || return 1
enable_remote_pa_tunnel_server || return 1 enable_remote_pa_tunnel_server || return 1
if "$outbound" ; then if "$outbound" ; then
enable_local_pa_tunnel_sink || return 1 enable_local_pa_tunnel_sink || return 1
sleep 1 sleep 1
set_local_pa_tunnel_sink_as_default || return 1 set_local_pa_tunnel_sink_as_default || return 1
fi fi
if "$inbound" ; then if "$inbound" ; then
enable_local_pa_tunnel_source || return 1 enable_local_pa_tunnel_source || return 1
fi fi
return 0 return 0
} }
# Remove PulseAudio TCP tunnel sink on local host # Remove PulseAudio TCP tunnel sink on local host
remove_local_pa_tunnel_sink() { remove_local_pa_tunnel_sink() {
if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then
echo "INFO: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2 echo "INFO: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2
return 0 return 0
elif ! pactl list sinks | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then elif ! pactl list sinks | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then
echo "INFO: No PulseAudio tunnel sink to 127.0.0.1 exists." >&2 echo "INFO: No PulseAudio tunnel sink to 127.0.0.1 exists." >&2
return 0 return 0
else else
owner_module=$( owner_module=$(
pactl --format json list sinks 2>/dev/null | \ pactl --format json list sinks 2>/dev/null | \
jq '.[] | select(.name=="tunnel-sink.tcp:127.0.0.1") | .owner_module' -r jq '.[] | select(.name=="tunnel-sink.tcp:127.0.0.1") | .owner_module' -r
) )
if ! pactl unload-module "$owner_module" ; then if ! pactl unload-module "$owner_module" ; then
echo "ERROR: Could not unload owner module $owner_module of PulseAudio sink \"tunnel-sink.tcp:127.0.0.1\"." >&2 echo "ERROR: Could not unload owner module $owner_module of PulseAudio sink \"tunnel-sink.tcp:127.0.0.1\"." >&2
return 1 return 1
else else
echo "INFO: Unloaded owner module $owner_module of PulseAudio sink \"tunnel-sink.tcp:127.0.0.1\"." >&2 echo "INFO: Unloaded owner module $owner_module of PulseAudio sink \"tunnel-sink.tcp:127.0.0.1\"." >&2
return 0 return 0
fi fi
fi fi
} }
# Remove PulseAudio TCP tunnel source on local host # Remove PulseAudio TCP tunnel source on local host
remove_local_pa_tunnel_source() { remove_local_pa_tunnel_source() {
if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then
echo "INFO: PulseAudio module \"module-tunnel-source\" is not loaded." >&2 echo "INFO: PulseAudio module \"module-tunnel-source\" is not loaded." >&2
return 0 return 0
elif ! pactl list sources | grep -Fq "tunnel-source.tcp:127.0.0.1" ; then elif ! pactl list sources | grep -Fq "tunnel-source.tcp:127.0.0.1" ; then
echo "INFO: No PulseAudio tunnel source from 127.0.0.1 exists." >&2 echo "INFO: No PulseAudio tunnel source from 127.0.0.1 exists." >&2
return 0 return 0
else else
owner_module=$( owner_module=$(
pactl --format json list sources 2>/dev/null | \ pactl --format json list sources 2>/dev/null | \
jq '.[] | select(.name=="tunnel-source.tcp:127.0.0.1") | .owner_module' -r jq '.[] | select(.name=="tunnel-source.tcp:127.0.0.1") | .owner_module' -r
) )
if ! pactl unload-module "$owner_module" ; then if ! pactl unload-module "$owner_module" ; then
echo "ERROR: Could not unload owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2 echo "ERROR: Could not unload owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2
return 1 return 1
else else
echo "INFO: Unloaded owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2 echo "INFO: Unloaded owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2
return 0 return 0
fi fi
fi fi
} }
# Stop PulseAudio TCP tunnel server on remote host. # Stop PulseAudio TCP tunnel server on remote host.
disable_remote_pa_tunnel_server() { disable_remote_pa_tunnel_server() {
if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then
echo "INFO: PulseAudio module \"module-native-protocol-tcp\" not loaded on remote_ip=$remote_ip." >&2 echo "INFO: PulseAudio module \"module-native-protocol-tcp\" not loaded on remote_ip=$remote_ip." >&2
return 0 return 0
elif ! _ssh pactl unload-module module-native-protocol-tcp ; then elif ! _ssh pactl unload-module module-native-protocol-tcp ; then
echo "ERROR: Could not unload PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2 echo "ERROR: Could not unload PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2
return 1 return 1
else else
echo "INFO: Unloaded PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2 echo "INFO: Unloaded PulseAudio module \"module-native-protocol-tcp\" on remote_ip=$remote_ip." >&2
return 0 return 0
fi fi
} }
# Terminate SSH portforwarding session # Terminate SSH portforwarding session
terminate_ssh_portforward() { terminate_ssh_portforward() {
for pid in $(pidof ssh) ; do for pid in $(pidof ssh) ; do
if grep -Fq "$USER"-pulseaudio /proc/"$pid"/cmdline ; then if grep -Fq "$USER"-pulseaudio /proc/"$pid"/cmdline ; then
kill -TERM "$pid" kill -TERM "$pid"
fi fi
done done
} }
# Perform stop operation # Perform stop operation
do_stop() { do_stop() {
if "$outbound" ; then if "$outbound" ; then
remove_local_pa_tunnel_sink || return 1 remove_local_pa_tunnel_sink || return 1
fi fi
if "$inbound" ; then if "$inbound" ; then
remove_local_pa_tunnel_source || return 1 remove_local_pa_tunnel_source || return 1
fi fi
disable_remote_pa_tunnel_server || return 1 disable_remote_pa_tunnel_server || return 1
terminate_ssh_portforward || return 1 terminate_ssh_portforward || return 1
return 0 return 0
} }
## ##
@ -413,78 +409,78 @@ do_stop() {
rv=0 rv=0
if test "$operation" = setup ; then if test "$operation" = setup ; then
echo "Entering setup mode ..." echo "Entering setup mode ..."
else else
if ! test -e "$config" ; then if ! test -e "$config" ; then
echo "ERROR: Configfile $config does not exist (use \"$0 setup\" first)." >&2 echo "ERROR: Configfile $config does not exist (use \"$0 setup\" first)." >&2
rv=1 rv=1
elif ! test -r "$config" ; then elif ! test -r "$config" ; then
echo "ERROR: Configfile $config is not readable." >&2 echo "ERROR: Configfile $config is not readable." >&2
rv=1 rv=1
elif ! test -f "$config" ; then elif ! test -f "$config" ; then
echo "ERROR: Configfile $config is not a regular file." >&2 echo "ERROR: Configfile $config is not a regular file." >&2
rv=1 rv=1
else else
. "$config" . "$config"
if test -z "$remote_ip" ; then if test -z "$remote_ip" ; then
echo "ERROR: \"remote_ip=<IP address>\" not set in configfile $config." >&2 echo "ERROR: \"remote_ip=<IP address>\" not set in configfile $config." >&2
rv=1 rv=1
elif test -z "$remote_user" ; then elif test -z "$remote_user" ; then
echo "ERROR: \"remote_user=<username>\" not set in configfile $config." >&2 echo "ERROR: \"remote_user=<username>\" not set in configfile $config." >&2
rv=1 rv=1
fi fi
fi fi
if test -z "$(which jq)" ; then if test -z "$(which jq)" ; then
echo "ERROR: Required executable \"jq\" not found." >&2 echo "ERROR: Required executable \"jq\" not found." >&2
rv=1 rv=1
elif test -z "$(which pactl)" ; then elif test -z "$(which pactl)" ; then
echo "ERROR: Required executable \"pactl\" not found." >&2 echo "ERROR: Required executable \"pactl\" not found." >&2
rv=1 rv=1
elif test -z "$(which ssh)" ; then elif test -z "$(which ssh)" ; then
echo "ERROR: Required executable \"ssh\" not found." >&2 echo "ERROR: Required executable \"ssh\" not found." >&2
rv=1 rv=1
fi fi
fi fi
if test "$rv" -ne 0 ; then if test "$rv" -ne 0 ; then
echo "ERROR: Preliminary checks failed, skipping operation." >&2 echo "ERROR: Preliminary checks failed, skipping operation." >&2
else else
case "$operation" in case "$operation" in
""|-h|--help) ""|-h|--help)
cat << EOF cat << EOF
Setup and run encrypted connection to remote PulseAudio/Pipewire server Setup and run encrypted connection to remote PulseAudio/Pipewire server
Usage: $0 restart|setup|start|status|stop Usage: $0 restart|setup|start|status|stop
EOF EOF
rv=0 rv=0
;; ;;
setup) setup)
do_setup do_setup
rv=$? rv=$?
;; ;;
start) start)
do_start do_start
rv=$? rv=$?
;; ;;
stop) stop)
do_stop do_stop
rv=$? rv=$?
;; ;;
restart) restart)
do_stop do_stop
do_start do_start
rv=$? rv=$?
;; ;;
status) status)
do_status do_status
rv=$? rv=$?
;; ;;
*) *)
echo "ERROR: Usage: $0 restart|setup|start|status|stop" >&2 echo "ERROR: Usage: $0 restart|setup|start|status|stop" >&2
rv=1 rv=1
;; ;;
esac esac
fi fi
exit "$rv" exit "$rv"