diff --git a/ejabberdctl.template b/ejabberdctl.template index 64fed558b..8053ea2df 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -10,159 +10,95 @@ FIREWALL_WINDOW="" ERLANG_NODE=ejabberd@localhost # define default environment variables -SCRIPT_DIR=`cd ${0%/*} && pwd` ERL={{erl}} IEX={{bindir}}/iex EPMD={{epmd}} INSTALLUSER={{installuser}} -ERL_LIBS={{libdir}} # check the proper system user is used if defined -if [ "$INSTALLUSER" != "" ] ; then - EXEC_CMD="false" - for GID in `id -G`; do - if [ $GID -eq 0 ] ; then - INSTALLUSER_HOME=$(getent passwd "$INSTALLUSER" | cut -d: -f6) - if [ -n "$INSTALLUSER_HOME" ] && [ ! -d "$INSTALLUSER_HOME" ] ; then - mkdir -p "$INSTALLUSER_HOME" - chown "$INSTALLUSER" "$INSTALLUSER_HOME" - fi - EXEC_CMD="as_install_user" - fi - done - if [ `id -g` -eq `id -g $INSTALLUSER` ] ; then +EXEC_CMD="false" +if [ -n "$INSTALLUSER" ] ; then + if [ $(id -g) -eq $(id -g $INSTALLUSER || echo -1) ] ; then EXEC_CMD="as_current_user" - fi - if [ "$EXEC_CMD" = "false" ] ; then - echo "This command can only be run by root or the user $INSTALLUSER" >&2 - exit 4 + else + id -Gn | grep -q wheel && EXEC_CMD="as_install_user" fi else EXEC_CMD="as_current_user" fi +if [ "$EXEC_CMD" = "false" ] ; then + echo "ERROR: This command can only be run by root or the user $INSTALLUSER" >&2 + exit 7 +fi -# run command either directly or via su $INSTALLUSER -exec_cmd() -{ - if [ "EXEC_CMD" = as_install_user ]; then - su -c '"$0" $@"' "INSTALLUSER" -- "$@" - else - "$@" - fi -} - +# set backward compatibility on command line parameters +set -- $(echo "$*" | sed -e \ + "s/--node/-n/;s/--spool/-s/;s/--logs/-l/;\ + s/--config/-f/;s/--ctl-config/-c/;s/--config-dir/-d/;\ + s/--no-timeout/-t/") # parse command line parameters -next=init -for arg; do - # Empty argument list as it is already saved in the for buffer - if [ "$next" = init ]; then - next= - set -- - fi - case $next in - node) ERLANG_NODE_ARG=$arg; next=;; - config-dir) ETC_DIR=$arg; next=;; - config) EJABBERD_CONFIG_PATH=$arg; next=;; - ctl-config) EJABBERDCTL_CONFIG_PATH=$arg; next=;; - logs) LOGS_DIR=$arg; next=;; - spool) SPOOL_DIR=$arg; next=;; - "") - case $arg in - --) next=raw;; - --no-timeout) EJABBERD_NO_TIMEOUT="--no-timeout" ;; - --node) next=node;; - --config-dir) next=config-dir;; - --config) next=config;; - --ctl-config) next=ctl-config;; - --logs) next=logs;; - --spool) next=spool;; - *) set -- "$@" "$arg";; # unknown option, keep it. - esac;; - raw) # we are after --, keep options as it is. - set -- "$@" "$arg";; +while getopts n:s:l:f:c:d:tx opt; do + case $opt in + n) ERLANG_NODE_ARG=$OPTARG;; + s) SPOOL_DIR=$OPTARG;; + l) LOGS_DIR=$OPTARG;; + f) EJABBERD_CONFIG_PATH=$OPTARG;; + c) EJABBERDCTL_CONFIG_PATH=$OPTARG;; + d) ETC_DIR=$OPTARG;; + t) NO_TIMEOUT="--no-timeout";; esac done +# keep extra command line parameters for ejabberd +shift $((OPTIND-1)) -# Define ejabberd variable if they have not been defined from the command line -if [ "$ETC_DIR" = "" ] ; then - ETC_DIR={{sysconfdir}}/ejabberd -fi -if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then - EJABBERDCTL_CONFIG_PATH=$ETC_DIR/ejabberdctl.cfg -fi -if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then - . "$EJABBERDCTL_CONFIG_PATH" -fi -if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then - EJABBERD_CONFIG_PATH=$ETC_DIR/ejabberd.yml -fi -if [ "$LOGS_DIR" = "" ] ; then - LOGS_DIR={{localstatedir}}/log/ejabberd -fi -if [ "$SPOOL_DIR" = "" ] ; then - SPOOL_DIR={{localstatedir}}/lib/ejabberd -fi -if [ "$EJABBERD_DOC_PATH" = "" ] ; then - EJABBERD_DOC_PATH={{docdir}} -fi -if [ "$ERLANG_NODE_ARG" != "" ] ; then - ERLANG_NODE=$ERLANG_NODE_ARG -fi -if [ "{{release}}" != "true" -a "$EJABBERD_BIN_PATH" = "" ] ; then - EJABBERD_BIN_PATH={{libdir}}/ejabberd/priv/bin -fi -EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log -DATETIME=`date "+%Y%m%d-%H%M%S"` -ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump -ERL_INETRC=$ETC_DIR/inetrc +# define ejabberd variables if not already defined from the command line +: ${ETC_DIR:={{sysconfdir}}/ejabberd} +: ${LOGS_DIR:={{localstatedir}}/log/ejabberd} +: ${SPOOL_DIR:={{localstatedir}}/lib/ejabberd} +: ${EJABBERD_CONFIG_PATH:="$ETC_DIR"/ejabberd.yml} +: ${EJABBERDCTL_CONFIG_PATH:="$ETC_DIR"/ejabberdctl.cfg} +[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH" +[ "$ERLANG_NODE_ARG" != "" ] && ERLANG_NODE=$ERLANG_NODE_ARG +: ${EJABBERD_DOC_PATH:={{docdir}}} +: ${EJABBERD_LOG_PATH:="$LOGS_DIR"/ejabberd.log} -# define mnesia options -MNESIA_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS" # define erl parameters ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS" -KERNEL_OPTS="" if [ "$FIREWALL_WINDOW" != "" ] ; then - KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}" + ERLANG_OPTS="$ERLANG_OPTS -kernel " \ + "inet_dist_listen_min ${FIREWALL_WINDOW%-*} " \ + "inet_dist_listen_max ${FIREWALL_WINDOW#*-}" fi if [ "$INET_DIST_INTERFACE" != "" ] ; then - INET_DIST_INTERFACE2="$(echo $INET_DIST_INTERFACE | sed 's/\./,/g')" - if [ "$INET_DIST_INTERFACE" != "$INET_DIST_INTERFACE2" ] ; then - INET_DIST_INTERFACE2="{$INET_DIST_INTERFACE2}" + INET_DIST_INTERFACE2=$("$ERL" -noshell -eval 'case inet:parse_address("'$INET_DIST_INTERFACE'") of {ok,IP} -> io:format("~p",[IP]); _ -> ok end.' -s erlang halt) + if [ "$INET_DIST_INTERFACE2" != "" ] ; then + ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface \"$INET_DIST_INTERFACE2\"" fi - KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE2}\"" fi if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then NAME="-sname" else NAME="-name" fi -IEXNAME="-$NAME" +ERL_LIBS={{libdir}} +ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump +ERL_INETRC="$ETC_DIR"/inetrc -# define ejabberd environment parameters -if [ "$EJABBERD_CONFIG_PATH" != "${EJABBERD_CONFIG_PATH%.yml}" ] ; then - rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) - rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) - count=$(sed '/^[ ]*log_rotate_count/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) - date=$(sed '/^[ ]*log_rotate_date/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) -else - rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH) - rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH) - count=$(sed '/^[ ]*log_rotate_count/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH) - date=$(sed '/^[ ]*log_rotate_date/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH) -fi +# define ejabberd parameters +rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH") +rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH") +count=$(sed '/^[ ]*log_rotate_count/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH") +date=$(sed '/^[ ]*log_rotate_date/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH") [ -z "$rate" ] || EJABBERD_OPTS="log_rate_limit $rate" -[ -z "$rotate" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_size $rotate" -[ -z "$count" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_count $count" -[ -z "$date" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_date '$date'" -[ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd ${EJABBERD_OPTS}" - -[ -d "$SPOOL_DIR" ] || $EXEC_CMD "mkdir -p $SPOOL_DIR" -cd "$SPOOL_DIR" +[ -z "$rotate" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_size $rotate" +[ -z "$count" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_count $count" +[ -z "$date" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_date '$date'" +[ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS" +EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd" # export global variables export EJABBERD_CONFIG_PATH export EJABBERD_LOG_PATH -export EJABBERD_BIN_PATH export EJABBERD_DOC_PATH export EJABBERD_PID_PATH export ERL_CRASH_DUMP @@ -174,89 +110,26 @@ export CONTRIB_MODULES_PATH export CONTRIB_MODULES_CONF_DIR export ERL_LIBS -# TODO: Too much copy-and-paste below, factorize! -# start server -start() +# run command either directly or via su $INSTALLUSER +exec_cmd() { - check_start - exec_cmd $ERL \ - $NAME $ERLANG_NODE \ - -noinput -detached \ - $MNESIA_OPTS \ - $KERNEL_OPTS \ - $EJABBERD_OPTS \ - -s ejabberd \ - $ERLANG_OPTS \ - "$@" -} - -# attach to server -debug() -{ - debugwarning - NID=$(uid debug) - exec_cmd $ERL $NAME $NID \ - -remsh $ERLANG_NODE \ - -hidden \ - $KERNEL_OPTS \ - $ERLANG_OPTS \ - "$@" -} - -# attach to server using Elixir -iexdebug() -{ - debugwarning - # Elixir shell is hidden as default - NID=$(uid debug) - exec_cmd $IEX $IEXNAME $NID \ - -remsh "$ERLANG_NODE" \ - --erl "$KERNEL_OPTS" \ - --erl "$ERLANG_OPTS" \ - --erl "$@" -} - -# start interactive server -live() -{ - livewarning - exec_cmd $ERL $NAME $ERLANG_NODE \ - $MNESIA_OPTS \ - $KERNEL_OPTS \ - $EJABBERD_OPTS \ - -s ejabberd \ - $ERLANG_OPTS \ - "$@" -} - -# start interactive server with Elixir -iexlive() -{ - livewarning - echo $@ - exec_cmd $IEX $IEXNAME $ERLANG_NODE \ - --erl "-mnesia dir \"$SPOOL_DIR\"" \ - --erl "$KERNEL_OPTS" \ - --erl "$EJABBERD_OPTS" \ - --app ejabberd \ - --erl "$ERLANG_OPTS" \ - --erl "$@" -} - -# start server in the foreground -foreground() -{ - check_start - exec_cmd $ERL $NAME $ERLANG_NODE \ - -noinput \ - $MNESIA_OPTS \ - $KERNEL_OPTS \ - $EJABBERD_OPTS \ - -s ejabberd \ - $ERLANG_OPTS \ - "$@" + case $EXEC_CMD in + as_install_user) su -c '"$0" $@"' "$INSTALLUSER" -- "$@" ;; + as_current_user) "$@" ;; + esac +} +exec_erl() +{ + NODE=$1; shift + exec_cmd $ERL $NAME $NODE $ERLANG_OPTS "$@" +} +exec_iex() +{ + NODE=$1; shift + exec_cmd $IEX -$NAME $NODE --erl "$ERLANG_OPTS" "$@" } +# usage debugwarning() { if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then @@ -283,7 +156,6 @@ debugwarning() livewarning() { - check_start if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then echo "--------------------------------------------------------------------" echo "" @@ -305,32 +177,6 @@ livewarning() fi } -etop() -{ - NID=$(uid top) - exec_cmd $ERL \ - $NAME $NID \ - -hidden -s etop -s erlang halt -output text -node $ERLANG_NODE -} - -ping() -{ - [ -z "$1" ] && PEER=${ERLANG_NODE} || PEER=$1 - if [ "$PEER" = "${PEER%.*}" ] ; then - PING_NAME="-sname" - PING_NODE=$(hostname -s) - else - PING_NAME="-name" - PING_NODE=$(hostname) - fi - NID=$(uid ping ${PING_NODE}) - exec_cmd $ERL \ - $PING_NAME $NID \ - -hidden $KERNEL_OPTS $ERLANG_OPTS \ - -eval 'io:format("~p~n",[net_adm:ping('"$PEER"')])' \ - -s erlang halt -output text -noinput -} - help() { echo "" @@ -352,28 +198,27 @@ help() echo "" } -# common control function -ctl() +# generic erlang node ping feature +ping() { - NID=$(uid ctl) - exec_cmd $ERL $NAME $NID \ - -noinput -hidden $KERNEL_OPTS -s ejabberd_ctl \ - -extra $ERLANG_NODE $EJABBERD_NO_TIMEOUT \ - "$@" - result=$? - case $result in - 2) help;; - 3) help;; - *) :;; - esac - return $result + PEER=${1:-$ERLANG_NODE} + if [ "$PEER" = "${PEER%.*}" ] ; then + PING_NAME="-sname" + PING_NODE=$(hostname -s) + else + PING_NAME="-name" + PING_NODE=$(hostname) + fi + exec_cmd $ERL $PING_NAME $(uid ping $PING_NODE) $ERLANG_OPTS \ + -noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"$PEER"')])' \ + -s erlang halt -output text } +# dynamic node name helper uid() { uuid=$(uuidgen 2>/dev/null) - [ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && \ - uuid=$(cat /proc/sys/kernel/random/uuid) + [ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid) [ -z "$uuid" ] && uuid=$(printf "%X" $RANDOM$(date +%M%S)$$) uuid=${uuid%%-*} [ $# -eq 0 ] && echo ${uuid}-${ERLANG_NODE} @@ -388,6 +233,7 @@ stop_epmd() } # make sure node not already running and node name unregistered +# if all ok, ensure runtime directory exists and make it current directory check_start() { "$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && { @@ -404,11 +250,16 @@ check_start() "$EPMD" -kill >/dev/null } } + } || { + cd "$SPOOL_DIR" || { + echo "ERROR: ejabberd can not access directory $SPOOL_DIR" + exit 6 + } } } # allow sync calls -wait_for_status() +wait_status() { # args: status try delay # return: 0 OK, 1 KO @@ -417,27 +268,64 @@ wait_for_status() while [ $status -ne $1 ] ; do sleep $3 timeout=`expr $timeout - 1` - [ $timeout -eq 0 ] && { + if [ $timeout -eq 0 ] ; then status=$1 - } || { + else ctl status > /dev/null status=$? - } + fi done - [ $timeout -eq 0 ] && return 1 || return 0 + [ $timeout -gt 0 ] } -# main handler -case $@ in - 'start') start;; - 'debug') debug;; - 'iexdebug') iexdebug;; - 'live') live;; - 'iexlive') iexlive;; - 'foreground') foreground;; - 'ping'*) shift; ping "$@";; - 'etop') etop;; - 'started') wait_for_status 0 30 2;; # wait 30x2s before timeout - 'stopped') wait_for_status 3 30 2 && stop_epmd;; # wait 30x2s before timeout - *) ctl "$@";; +# main +case $1 in + start) + check_start + exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput -detached + ;; + foreground) + check_start + exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput + ;; + live) + livewarning + check_start + exec_erl $ERLANG_NODE $EJABBERD_OPTS + ;; + debug) + debugwarning + exec_erl $(uid debug) -hidden -remsh $ERLANG_NODE + ;; + etop) + exec_erl $(uid top) -hidden -node $ERLANG_NODE -s etop \ + -s erlang halt -output text + ;; + iexdebug) + debugwarning + exec_iex $(uid debug) --remsh "$ERLANG_NODE" + ;; + iexlive) + livewarning + exec_iex $ERLANG_NODE --erl "$EJABBERD_OPTS" --app ejabberd + ;; + ping) + ping $2 + ;; + started) + wait_status 0 30 2 # wait 30x2s before timeout + ;; + stopped) + wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout + ;; + *) + exec_erl $(uid ctl) -hidden -noinput -s ejabberd_ctl \ + -extra $ERLANG_NODE $NO_TIMEOUT "$@" + result=$? + case $result in + 2|3) help;; + *) :;; + esac + exit $result + ;; esac