mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-20 17:27:00 +01:00
46f01b962a
If the $INSTALLUSER is not root, he will usually not have the necessary permissions to create his home directory.
425 lines
13 KiB
Bash
Executable File
425 lines
13 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}}
|
|
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 [ -z "$INSTALLUSER_HOME" ] ; then
|
|
echo "Cannot determine home directory of $INSTALLUSER" >&2
|
|
exit 1
|
|
fi
|
|
if [ ! -d "$INSTALLUSER_HOME" ] ; then
|
|
mkdir -p "$INSTALLUSER_HOME"
|
|
chown "$INSTALLUSER" "$INSTALLUSER_HOME"
|
|
fi
|
|
EXEC_CMD="env HOME=$INSTALLUSER_HOME su $INSTALLUSER -p -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
|
|
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
|
|
|
|
# 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"
|
|
# then set SPOOL_DIR as ejabberd home directory by changing
|
|
# to that directory readable by INSTALLUSER to prevent
|
|
# "File operation error: eacces." messages
|
|
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
|
|
|
|
# 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()
|
|
{
|
|
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 any key to continue"
|
|
read foo
|
|
echo ""
|
|
fi
|
|
TTY=`tty | sed -e 's/.*\///g'`
|
|
$EXEC_CMD "$ERL \
|
|
$NAME debug-${TTY}-${ERLANG_NODE} \
|
|
-remsh $ERLANG_NODE \
|
|
-hidden \
|
|
$KERNEL_OPTS \
|
|
$ERLANG_OPTS $ARGS \"$@\""
|
|
}
|
|
|
|
# start interactive server
|
|
live()
|
|
{
|
|
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 any key to continue"
|
|
read foo
|
|
echo ""
|
|
fi
|
|
$EXEC_CMD "$ERL \
|
|
$NAME $ERLANG_NODE \
|
|
-pa $EJABBERD_EBIN_PATH \
|
|
-mnesia dir \"\\\"$SPOOL_DIR\\\"\" \
|
|
$KERNEL_OPTS \
|
|
$EJABBERD_OPTS \
|
|
-s ejabberd \
|
|
$ERLANG_OPTS $ARGS \"$@\""
|
|
}
|
|
|
|
etop()
|
|
{
|
|
$EXEC_CMD "$ERL \
|
|
$NAME debug-${TTY}-${ERLANG_NODE} \
|
|
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
|
|
}
|
|
|
|
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 " live Start an ejabberd node in live (interactive) mode"
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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;;
|
|
' live') live;;
|
|
' 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
|
|
*) ctl $ARGS;;
|
|
esac
|