Skip to content

Instantly share code, notes, and snippets.

@kimw
Last active February 25, 2017 10:31
Show Gist options
  • Save kimw/6f30aeddea3e45ad7a282885c8ea5d3f to your computer and use it in GitHub Desktop.
Save kimw/6f30aeddea3e45ad7a282885c8ea5d3f to your computer and use it in GitHub Desktop.
dash script: shadowsocks controller
# file: ~/.ss-ctl.conf
# vim: ts=4 sw=4 noet ft=sh
#
# Config file of ss-ctl
# See: https://gist.github.com/kimw/6f30aeddea3e45ad7a282885c8ea5d3f
# Multi config files can be seprated by space
CONF_FILES="/a/path/to/config/file.json"
SS_SERVER_ENABLED=true
SS_SERVER_BIN="/a/path/to/ss-server"
SS_SERVER_ARGS=""
SS_LOCAL_ENABLED=false
SS_LOCAL_BIN="/a/path/to/ss-local"
SS_LOCAL_ARGS=""
SS_REDIR_ENABLED=false
SS_REDIR_BIN="/a/path/to/ss-redir"
SS_REDIR_ARGS=""
#!/bin/sh
# vim: ts=4 sw=4 noet fdm=indent
#
# ss-ctl - Start/Stop shadowsocks from command line easier.
# More informations at
# https://gist.github.com/kimw/6f30aeddea3e45ad7a282885c8ea5d3f
#
# Copyright (C) 2017 Kim Wong <kim.max@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
DEFAULT_CONF_FILES=""
DEFAULT_SS_SERVER_BIN=$(which ss-server)
DEFAULT_SS_SERVER_ARGS=""
DEFAULT_SS_LOCAL_BIN=$(which ss-local)
DEFAULT_SS_LOCAL_ARGS=""
DEFAULT_SS_REDIR_BIN=$(which ss-redir)
DEFAULT_SS_REDIR_ARGS=""
print_help() {
echo "Usage: $(basename $0) [start | restart] [-v]"
echo " or $(basename $0) [stop | status]"
echo " or $(basename $0) -h"
echo "Options:"
echo " -v verbose in log file"
echo " -h print help messages"
}
die() {
echo "Bad command."
echo ""
print_help
exit 1
}
start_server() {
local pid pids conf_file log_file args=$*
echo -n "START ss-server... "
pids="$(pgrep ss-server)"
if [ -n "$pids" ]; then
echo -n "SKIP (already run as PID:"
for pid in $pids; do echo -n " $pid,"; done
echo "\b)"
else
for conf_file in $CONF_FILES; do
log_file=$(echo "$conf_file" | sed -e "s/config/ss-server/g" -e "s/\.json$/.log/g")
nohup $SS_SERVER_BIN -c "$conf_file" $SS_SERVER_ARGS $args >>"$log_file" 2>&1 &
while ! pgrep "ss-server" >/dev/null; do sleep 0.5; done # wait
done
echo -n "OK (run as PID:"
for pid in $(pgrep ss-server); do echo -n " $pid,"; done
echo "\b)"
fi
}
stop_server() {
local pids etime etimes
echo -n " STOP ss-server... "
pids=$(pgrep ss-server)
if [ -n "$pids" ]; then
etimes="$(ps -ho etime $pids)"
_killall ss-server
echo -n "OK (served you:"
for etime in $etimes; do echo -n " $etime,"; done
echo "\b)"
else
echo "SKIP (no instance)"
fi
}
restart_server() {
stop_server
start_server $*
}
start_local() {
local pid pids conf_file log_file args=$*
echo -n "START ss-local... "
pids="$(pgrep ss-local)"
if [ -n "$pids" ]; then
echo -n "SKIP (already run as PID:"
for pid in $pids; do echo -n " $pid,"; done
echo "\b)"
else
for conf_file in $CONF_FILES; do
log_file=$(echo "$conf_file" | sed -e "s/config/ss-local/g" -e "s/\.json$/.log/g")
nohup $SS_LOCAL_BIN -c "$conf_file" $SS_LOCAL_ARGS $args >>"$log_file" 2>&1 &
while ! pgrep "ss-local" >/dev/null; do sleep 0.5; done # wait
done
echo -n "OK (run as PID:"
for pid in $(pgrep ss-local); do echo -n " $pid,"; done
echo "\b)"
fi
}
stop_local() {
local pids etime etimes
echo -n " STOP ss-local... "
pids=$(pgrep ss-local)
if [ -n "$pids" ]; then
etimes="$(ps -ho etime $pids)"
_killall ss-local
echo -n "OK (served you:"
for etime in $etimes; do echo -n " $etime,"; done
echo "\b)"
else
echo "SKIP (no instance)"
fi
}
restart_local() {
stop_local
start_local $*
}
start_redir() {
local pid pids conf_file log_file args=$*
echo -n "START ss-redir... "
pids="$(pgrep ss-redir)"
if [ -n "$pids" ]; then
echo -n "SKIP (already run as PID:"
for pid in $pids; do echo -n " $pid,"; done
echo "\b)"
else
for conf_file in $CONF_FILES; do
log_file=$(echo "$conf_file" | sed -e "s/config/ss-redir/g" -e "s/\.json$/.log/g")
nohup $SS_REDIR_BIN -c "$conf_file" $SS_REDIR_ARGS $args >>"$log_file" 2>&1 &
while ! pgrep "ss-redir" >/dev/null; do sleep 0.5; done # wait
done
echo -n "OK (run as PID:"
for pid in $(pgrep ss-redir); do echo -n " $pid,"; done
echo "\b)"
fi
}
stop_redir() {
local pids etime etimes
echo -n " STOP ss-redir... "
pids=$(pgrep ss-redir)
if [ -n "$pids" ]; then
etimes="$(ps -ho etime $pids)"
_killall ss-redir
echo -n "OK (served you:"
for etime in $etimes; do echo -n " $etime,"; done
echo "\b)"
else
echo "SKIP (no instance)"
fi
}
restart_redir() {
stop_redir
start_redir $*
}
_killall() {
local pid
for pid in $(pgrep $1); do
# try to kill, until it was killed
while ps "$pid" >/dev/null; do kill "$pid"; sleep 0.5; done
done
}
load_vars() {
local conf_files
local ss_server_enabled ss_server_bin ss_server_args
local ss_local_enabled ss_local_bin ss_local_args
local ss_redir_enabled ss_redir_bin ss_redir_args
# load command line variables
[ -n "$CONF_FILES" ] && conf_files=$CONF_FILES
[ -n "$SS_SERVER_ENABLED" ] && ss_server_enabled=$SS_SERVER_ENABLED
[ -n "$SS_SERVER_BIN" ] && ss_server_bin=$SS_SERVER_BIN
[ -n "$SS_SERVER_ARGS" ] && ss_server_args=$SS_SERVER_ARGS
[ -n "$SS_LOCAL_ENABLED" ] && ss_local_enabled=$SS_LOCAL_ENABLED
[ -n "$SS_LOCAL_BIN" ] && ss_local_bin=$SS_LOCAL_BIN
[ -n "$SS_LOCAL_ARGS" ] && ss_local_args=$SS_LOCAL_ARGS
[ -n "$SS_REDIR_ENABLED" ] && ss_redir_enabled=$SS_REDIR_ENABLED
[ -n "$SS_REDIR_BIN" ] && ss_redir_bin=$SS_REDIR_BIN
[ -n "$SS_REDIR_ARGS" ] && ss_redir_args=$SS_REDIR_ARGS
# overwrite variables by file '$HOME/.ss-ctl.conf' if it's not assigned in command line
[ -f $HOME/.ss-ctl.conf ] && . $HOME/.ss-ctl.conf
[ -z "$conf_files" ] && conf_files=$CONF_FILES
[ -z "$ss_server_enabled" ] && ss_server_enabled=$SS_SERVER_ENABLED
[ -z "$ss_server_bin" ] && ss_server_bin=$SS_SERVER_BIN
[ -z "$ss_server_args" ] && ss_server_args=$SS_SERVER_ARGS
[ -z "$ss_local_enabled" ] && ss_local_enabled=$SS_LOCAL_ENABLED
[ -z "$ss_local_bin" ] && ss_local_bin=$SS_LOCAL_BIN
[ -z "$ss_local_args" ] && ss_local_args=$SS_LOCAL_ARGS
[ -z "$ss_redir_enabled" ] && ss_redir_enabled=$SS_REDIR_ENABLED
[ -z "$ss_redir_bin" ] && ss_redir_bin=$SS_REDIR_BIN
[ -z "$ss_redir_args" ] && ss_redir_args=$SS_REDIR_ARGS
# overwrite variables by default value if it's not assigned in command line nor '$HOME/.ss-ctl.conf'
[ -z "$conf_files" ] && conf_files=$DEFAULT_CONF_FILES
[ -z "$ss_server_enabled" ] && ss_server_enabled=$DEFAULT_SS_SERVER_ENABLED
[ -z "$ss_server_bin" ] && ss_server_bin=$DEFAULT_SS_SERVER_BIN
[ -z "$ss_server_args" ] && ss_server_args=$DEFAULT_SS_SERVER_ARGS
[ -z "$ss_local_enabled" ] && ss_local_enabled=$DEFAULT_SS_LOCAL_ENABLED
[ -z "$ss_local_bin" ] && ss_local_bin=$DEFAULT_SS_LOCAL_BIN
[ -z "$ss_local_args" ] && ss_local_args=$DEFAULT_SS_LOCAL_ARGS
[ -z "$ss_redir_enabled" ] && ss_redir_enabled=$DEFAULT_SS_REDIR_ENABLED
[ -z "$ss_redir_bin" ] && ss_redir_bin=$DEFAULT_SS_REDIR_BIN
[ -z "$ss_redir_args" ] && ss_redir_args=$DEFAULT_SS_REDIR_ARGS
CONF_FILES=$conf_files
SS_SERVER_ENABLED=$ss_server_enabled
SS_SERVER_BIN=$ss_server_bin
SS_SERVER_ARGS=$ss_server_args
SS_LOCAL_ENABLED=$ss_local_enabled
SS_LOCAL_BIN=$ss_local_bin
SS_LOCAL_ARGS=$ss_local_args
SS_REDIR_ENABLED=$ss_redir_enabled
SS_REDIR_BIN=$ss_redir_bin
SS_REDIR_ARGS=$ss_redir_args
}
check_vars() {
[ -z "$CONF_FILES" ] && die;
[ -z "$SS_SERVER_BIN" ] && die;
[ -z "$SS_LOCAL_BIN" ] && die;
[ -z "$SS_REDIR_BIN" ] && die;
}
check_envs() {
# each config file must exists
for conf in $CONF_FILES; do
if [ ! -f $conf ]; then
echo "ERROR: Config file not found: $conf"
exit 1
fi
done
# `ss-server` must executable if it's enabled
if [ "$SS_SERVER_ENABLED" = true -a ! -x "$SS_SERVER_BIN" ]; then
echo "ERROR: ss-server is not exists or executable: $SS_SERVER_BIN"
exit 1
fi
# `ss-local` must executable if it's enabled
if [ "$SS_LOCAL_ENABLED" = true -a ! -x "$SS_LOCAL_BIN" ]; then
echo "ERROR: ss-local is not exists or executable: $SS_LOCAL_BIN"
exit 1
fi
# `ss-redir` must executable if it's enabled
if [ "$SS_REDIR_ENABLED" = true -a ! -x "$SS_REDIR_BIN" ]; then
echo "ERROR: ss-redir is not exists or executable: $SS_REDIR_BIN"
exit 1
fi
}
main() {
local args cmd="${1:-status}"
[ $# -gt 0 ] && shift; args=$*
case "$cmd" in
start) [ -n "$args" -a "$args" != "-v" ] && die
[ "$SS_SERVER_ENABLED" = true ] && start_server $args
[ "$SS_LOCAL_ENABLED" = true ] && start_local $args
[ "$SS_REDIR_ENABLED" = true ] && start_redir $args
;;
stop) [ -n "$args" ] && die
[ $SS_SERVER_ENABLED = true ] && stop_server
[ "$SS_LOCAL_ENABLED" = true ] && stop_local
[ "$SS_REDIR_ENABLED" = true ] && stop_redir
;;
restart) [ -n "$args" -a "$args" != "-v" ] && die
[ "$SS_SERVER_ENABLED" = true ] && restart_server $args
[ "$SS_LOCAL_ENABLED" = true ] && restart_local $args
[ "$SS_REDIR_ENABLED" = true ] && restart_redir $args
;;
status) pid=$(pgrep "ss-(server|local|redir)")
[ -n "$pid" ] && ps -o pid,etime,cmd $pid
;;
-h) print_help ;;
*) die ;;
esac
}
load_vars
check_vars
check_envs
main $*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment