]> granicus.if.org Git - ejabberd/commitdiff
Refactor ejabberdctl
authorChristophe Romain <christophe.romain@process-one.net>
Wed, 31 May 2017 16:11:45 +0000 (18:11 +0200)
committerChristophe Romain <christophe.romain@process-one.net>
Wed, 31 May 2017 16:11:45 +0000 (18:11 +0200)
ejabberdctl.template

index 64fed558b9757715d048837eded7277129713386..8053ea2dfd96feb48abd4e88ed01de3a6509881f 100755 (executable)
@@ -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()
-{
-    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()
+# run command either directly or via su $INSTALLUSER
+exec_cmd()
 {
-    livewarning
-    exec_cmd $ERL $NAME $ERLANG_NODE \
-             $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
 }
-
-# start interactive server with Elixir
-iexlive()
+exec_erl()
 {
-    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 "$@"
+    NODE=$1; shift
+    exec_cmd $ERL $NAME $NODE $ERLANG_OPTS "$@"
 }
-
-# start server in the foreground
-foreground()
+exec_iex()
 {
-    check_start
-    exec_cmd $ERL $NAME $ERLANG_NODE \
-         -noinput \
-         $MNESIA_OPTS \
-         $KERNEL_OPTS \
-         $EJABBERD_OPTS \
-         -s ejabberd \
-         $ERLANG_OPTS \
-         "$@"
+    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