mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-26 16:26:24 +01:00
478 lines
14 KiB
Bash
Executable File
478 lines
14 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# define default configuration
|
|
POLL=true
|
|
SMP=auto
|
|
ERL_MAX_PORTS=32000
|
|
ERL_PROCESSES=250000
|
|
ERL_MAX_ETS_TABLES=1400
|
|
FIREWALL_WINDOW=""
|
|
ERLANG_NODE=ejabberd@localhost
|
|
|
|
# define default environment variables
|
|
SCRIPT_DIR=`cd ${0%/*} && pwd`
|
|
ERL={{erl}}
|
|
IEX={{bindir}}/iex
|
|
EPMD={{bindir}}/epmd
|
|
INSTALLUSER={{installuser}}
|
|
|
|
# Compatibility in ZSH
|
|
#setopt shwordsplit 2>/dev/null
|
|
|
|
# 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="su $INSTALLUSER -c"
|
|
fi
|
|
done
|
|
if [ `id -g` -eq `id -g $INSTALLUSER` ] ; then
|
|
EXEC_CMD="sh -c"
|
|
fi
|
|
if [ "$EXEC_CMD" = "false" ] ; then
|
|
echo "This command can only be run by root or the user $INSTALLUSER" >&2
|
|
exit 4
|
|
fi
|
|
else
|
|
EXEC_CMD="sh -c"
|
|
fi
|
|
|
|
# parse command line parameters
|
|
ARGS=""
|
|
while [ $# -ne 0 ] ; do
|
|
PARAM=$1
|
|
shift
|
|
case $PARAM in
|
|
--) break ;;
|
|
--node) ERLANG_NODE_ARG=$1 ; shift ;;
|
|
--config-dir) ETC_DIR="$1" ; shift ;;
|
|
--config) EJABBERD_CONFIG_PATH="$1" ; shift ;;
|
|
--ctl-config) EJABBERDCTL_CONFIG_PATH="$1" ; shift ;;
|
|
--logs) LOGS_DIR="$1" ; shift ;;
|
|
--spool) SPOOL_DIR="$1" ; shift ;;
|
|
*) ARGS="$ARGS $PARAM" ;;
|
|
esac
|
|
done
|
|
|
|
# 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
|
|
NODE=${ERLANG_NODE%@*}
|
|
fi
|
|
if [ "{{release}}" != "true" ] ; then
|
|
if [ "$EJABBERDDIR" = "" ] ; then
|
|
EJABBERDDIR={{libdir}}/ejabberd
|
|
fi
|
|
if [ "$EJABBERD_EBIN_PATH" = "" ] ; then
|
|
EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin
|
|
fi
|
|
if [ "$EJABBERD_PRIV_PATH" = "" ] ; then
|
|
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
|
|
fi
|
|
if [ "$EJABBERD_BIN_PATH" = "" ] ; then
|
|
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
|
|
fi
|
|
if [ "$EJABBERD_SO_PATH" = "" ] ; then
|
|
EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib
|
|
fi
|
|
if [ "$EJABBERD_MSGS_PATH" = "" ] ; then
|
|
EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs
|
|
fi
|
|
fi
|
|
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
|
|
SASL_LOG_PATH=$LOGS_DIR/erlang.log
|
|
DATETIME=`date "+%Y%m%d-%H%M%S"`
|
|
ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump
|
|
ERL_INETRC=$ETC_DIR/inetrc
|
|
|
|
# define erl parameters
|
|
ERL_OPTIONS=$(echo $ERL_OPTIONS | sed 's/ /\\ /g')
|
|
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#*-}"
|
|
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}"
|
|
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"
|
|
|
|
# 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
|
|
[ -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
|
|
|
|
# export global variables
|
|
export EJABBERD_CONFIG_PATH
|
|
export EJABBERD_MSGS_PATH
|
|
export EJABBERD_LOG_PATH
|
|
export EJABBERD_SO_PATH
|
|
export EJABBERD_BIN_PATH
|
|
export EJABBERD_DOC_PATH
|
|
export EJABBERD_PID_PATH
|
|
export ERL_CRASH_DUMP
|
|
export ERL_EPMD_ADDRESS
|
|
export ERL_INETRC
|
|
export ERL_MAX_PORTS
|
|
export ERL_MAX_ETS_TABLES
|
|
export CONTRIB_MODULES_PATH
|
|
|
|
# start server
|
|
start()
|
|
{
|
|
check_start
|
|
$EXEC_CMD "$ERL \
|
|
$NAME $ERLANG_NODE \
|
|
-noinput -detached \
|
|
-pa $EJABBERD_EBIN_PATH \
|
|
-mnesia dir \"\\\"$SPOOL_DIR\\\"\" \
|
|
$KERNEL_OPTS \
|
|
$EJABBERD_OPTS \
|
|
-s ejabberd \
|
|
-sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \
|
|
$ERLANG_OPTS $ARGS \"$@\""
|
|
}
|
|
|
|
# attach to server
|
|
debug()
|
|
{
|
|
debugwarning
|
|
TTY=`tty | sed -e 's/.*\///g'`
|
|
$EXEC_CMD "$ERL \
|
|
$NAME debug-${TTY}-${ERLANG_NODE} \
|
|
-remsh $ERLANG_NODE \
|
|
-hidden \
|
|
$KERNEL_OPTS \
|
|
$ERLANG_OPTS $ARGS \"$@\""
|
|
}
|
|
|
|
# attach to server using Elixir
|
|
iexdebug()
|
|
{
|
|
debugwarning
|
|
TTY=`tty | sed -e 's/.*\///g'`
|
|
# Elixir shell is hidden as default
|
|
$EXEC_CMD "$IEX \
|
|
$IEXNAME debug-${TTY}-${ERLANG_NODE} \
|
|
--remsh $ERLANG_NODE \
|
|
--erl \"$KERNEL_OPTS\" \
|
|
--erl \"$ERLANG_OPTS\" --erl \"$ARGS\" --erl \"$@\""
|
|
}
|
|
|
|
# start interactive server
|
|
live()
|
|
{
|
|
livewarning
|
|
$EXEC_CMD "$ERL \
|
|
$NAME $ERLANG_NODE \
|
|
-pa $EJABBERD_EBIN_PATH \
|
|
-mnesia dir \"\\\"$SPOOL_DIR\\\"\" \
|
|
$KERNEL_OPTS \
|
|
$EJABBERD_OPTS \
|
|
-s ejabberd \
|
|
$ERLANG_OPTS $ARGS \"$@\""
|
|
}
|
|
|
|
# start interactive server with Elixir
|
|
iexlive()
|
|
{
|
|
livewarning
|
|
$EXEC_CMD "$IEX \
|
|
$IEXNAME $ERLANG_NODE \
|
|
-pa $EJABBERD_EBIN_PATH \
|
|
--erl \"-mnesia dir \\\"$SPOOL_DIR\\\"\" \
|
|
--erl \"$KERNEL_OPTS\" \
|
|
--erl \"$EJABBERD_OPTS\" \
|
|
--app ejabberd \
|
|
--erl \"$ERLANG_OPTS\" --erl $ARGS --erl \"$@\""
|
|
}
|
|
|
|
etop()
|
|
{
|
|
$EXEC_CMD "$ERL \
|
|
$NAME debug-${TTY}-${ERLANG_NODE} \
|
|
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
|
|
}
|
|
|
|
# TODO: refactor debug warning and livewarning
|
|
debugwarning()
|
|
{
|
|
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
|
echo "--------------------------------------------------------------------"
|
|
echo ""
|
|
echo "IMPORTANT: we will attempt to attach an INTERACTIVE shell"
|
|
echo "to an already running ejabberd node."
|
|
echo "If an ERROR is printed, it means the connection was not successful."
|
|
echo "You can interact with the ejabberd node if you know how to use it."
|
|
echo "Please be extremely cautious with your actions,"
|
|
echo "and exit immediately if you are not completely sure."
|
|
echo ""
|
|
echo "To detach this shell from ejabberd, press:"
|
|
echo " control+c, control+c"
|
|
echo ""
|
|
echo "--------------------------------------------------------------------"
|
|
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
|
echo " EJABBERD_BYPASS_WARNINGS=true"
|
|
echo "Press return to continue"
|
|
read foo
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
livewarning()
|
|
{
|
|
check_start
|
|
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
|
echo "--------------------------------------------------------------------"
|
|
echo ""
|
|
echo "IMPORTANT: ejabberd is going to start in LIVE (interactive) mode."
|
|
echo "All log messages will be shown in the command shell."
|
|
echo "You can interact with the ejabberd node if you know how to use it."
|
|
echo "Please be extremely cautious with your actions,"
|
|
echo "and exit immediately if you are not completely sure."
|
|
echo ""
|
|
echo "To exit this LIVE mode and stop ejabberd, press:"
|
|
echo " q(). and press the Enter key"
|
|
echo ""
|
|
echo "--------------------------------------------------------------------"
|
|
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
|
echo " EJABBERD_BYPASS_WARNINGS=true"
|
|
echo "Press return to continue"
|
|
read foo
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
# TODO: Make iex command display only if ejabberd Elixir support has been enabled
|
|
help()
|
|
{
|
|
echo ""
|
|
echo "Commands to start an ejabberd node:"
|
|
echo " start Start an ejabberd node in server mode"
|
|
echo " debug Attach an interactive Erlang shell to a running ejabberd node"
|
|
echo " iexdebug Attach an interactive Elixir shell to a running ejabberd node"
|
|
echo " live Start an ejabberd node in live (interactive) mode"
|
|
echo " iexlive Start an ejabberd node in live (interactive) mode, within an Elixir shell"
|
|
echo ""
|
|
echo "Optional parameters when starting an ejabberd node:"
|
|
echo " --config-dir dir Config ejabberd: $ETC_DIR"
|
|
echo " --config file Config ejabberd: $EJABBERD_CONFIG_PATH"
|
|
echo " --ctl-config file Config ejabberdctl: $EJABBERDCTL_CONFIG_PATH"
|
|
echo " --logs dir Directory for logs: $LOGS_DIR"
|
|
echo " --spool dir Database spool dir: $SPOOL_DIR"
|
|
echo " --node nodename ejabberd node name: $ERLANG_NODE"
|
|
echo ""
|
|
}
|
|
|
|
# common control function
|
|
ctl()
|
|
{
|
|
COMMAND=$@
|
|
|
|
# Control number of connections identifiers
|
|
# using flock if available. Expects a linux-style
|
|
# flock that can lock a file descriptor.
|
|
MAXCONNID=100
|
|
CONNLOCKDIR={{localstatedir}}/lock/ejabberdctl
|
|
FLOCK='/usr/bin/flock'
|
|
if [ ! -x "$FLOCK" ] || [ ! -d "$CONNLOCKDIR" ] ; then
|
|
JOT='/usr/bin/jot'
|
|
if [ ! -x "$JOT" ] ; then
|
|
# no flock or jot, simply invoke ctlexec()
|
|
CTL_CONN="ctl-${ERLANG_NODE}"
|
|
ctlexec $CTL_CONN $COMMAND
|
|
result=$?
|
|
else
|
|
# no flock, but at least there is jot
|
|
RAND=`jot -r 1 0 $MAXCONNID`
|
|
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
|
|
ctlexec $CTL_CONN $COMMAND
|
|
result=$?
|
|
fi
|
|
else
|
|
# we have flock so we get a lock
|
|
# on one of a limited number of
|
|
# conn names -- this allows
|
|
# concurrent invocations using a bound
|
|
# number of atoms
|
|
for N in `seq 1 $MAXCONNID`; do
|
|
CTL_CONN="ejabberdctl-$N"
|
|
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
|
|
(
|
|
exec 8>"$CTL_LOCKFILE"
|
|
if flock --nb 8; then
|
|
ctlexec $CTL_CONN $COMMAND
|
|
ssresult=$?
|
|
# segregate from possible flock exit(1)
|
|
ssresult=`expr $ssresult \* 10`
|
|
exit $ssresult
|
|
else
|
|
exit 1
|
|
fi
|
|
)
|
|
result=$?
|
|
if [ $result -eq 1 ] ; then
|
|
# means we errored out in flock
|
|
# rather than in the exec - stay in the loop
|
|
# trying other conn names...
|
|
badlock=1
|
|
else
|
|
badlock=""
|
|
break;
|
|
fi
|
|
done
|
|
result=`expr $result / 10`
|
|
fi
|
|
|
|
if [ "$badlock" ] ;then
|
|
echo "Ran out of connections to try. Your ejabberd processes" >&2
|
|
echo "may be stuck or this is a very busy server. For very" >&2
|
|
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
|
|
exit 1;
|
|
fi
|
|
|
|
case $result in
|
|
0) :;;
|
|
1) :;;
|
|
2) help;;
|
|
3) help;;
|
|
esac
|
|
return $result
|
|
}
|
|
|
|
ctlexec()
|
|
{
|
|
CONN_NAME=$1; shift
|
|
COMMAND=$@
|
|
$EXEC_CMD "$ERL \
|
|
$NAME ${CONN_NAME} \
|
|
-noinput \
|
|
-hidden \
|
|
-pa $EJABBERD_EBIN_PATH \
|
|
$KERNEL_OPTS \
|
|
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
|
|
}
|
|
|
|
# stop epmd if there is no other running node
|
|
stop_epmd()
|
|
{
|
|
$EPMD -names 2>/dev/null | grep -q name || epmd -kill >/dev/null
|
|
}
|
|
|
|
# make sure node not already running and node name unregistered
|
|
check_start()
|
|
{
|
|
$EPMD -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
|
|
ps ux | grep -v grep | grep -q " $ERLANG_NODE " && {
|
|
echo "ERROR: The ejabberd node '$ERLANG_NODE' is already running."
|
|
exit 4
|
|
} || {
|
|
ps ux | grep -v grep | grep -q beam && {
|
|
echo "ERROR: The ejabberd node '$ERLANG_NODE' is registered,"
|
|
echo " but no related beam process has been found."
|
|
echo "Shutdown all other erlang nodes, and call 'epmd -kill'."
|
|
exit 5
|
|
} || {
|
|
$EPMD -kill >/dev/null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# cluster setup
|
|
join_cluster()
|
|
{
|
|
$EJABBERD_BIN_PATH/joincluster $*
|
|
}
|
|
leave_cluster()
|
|
{
|
|
$EJABBERD_BIN_PATH/leavecluster $*
|
|
}
|
|
|
|
# allow sync calls
|
|
wait_for_status()
|
|
{
|
|
# args: status try delay
|
|
# return: 0 OK, 1 KO
|
|
timeout=$2
|
|
status=4
|
|
while [ $status -ne $1 ] ; do
|
|
sleep $3
|
|
timeout=`expr $timeout - 1`
|
|
[ $timeout -eq 0 ] && {
|
|
status=$1
|
|
} || {
|
|
ctl status > /dev/null
|
|
status=$?
|
|
}
|
|
done
|
|
[ $timeout -eq 0 ] && return 1 || return 0
|
|
}
|
|
|
|
# main handler
|
|
case $ARGS in
|
|
' start') start;;
|
|
' debug') debug;;
|
|
' iexdebug') iexdebug;;
|
|
' live') live;;
|
|
' iexlive') iexlive;;
|
|
' etop') etop;;
|
|
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
|
|
' stopped') wait_for_status 3 15 2 && stop_epmd;; # wait 15x2s before timeout
|
|
' join_cluster'*) join_cluster ${ARGS# join_cluster};;
|
|
' leave_cluster'*) leave_cluster ${ARGS# leave_cluster};;
|
|
*) ctl $ARGS;;
|
|
esac
|