diff --git a/ejabberdctl.cfg.example b/ejabberdctl.cfg.example index b72058a1a..a90ff9aa2 100644 --- a/ejabberdctl.cfg.example +++ b/ejabberdctl.cfg.example @@ -55,11 +55,10 @@ # # This communication is used by ejabberdctl command line tool, # and in a cluster of several ejabberd nodes. -# Notice that the IP address must be specified in the Erlang syntax. # -# Default: {127,0,0,1} +# Default: 127.0.0.1 # -INET_DIST_INTERFACE={127,0,0,1} +#INET_DIST_INTERFACE=127.0.0.1 #. #' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections diff --git a/ejabberdctl.template b/ejabberdctl.template index a98e73ef2..252373c32 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -6,24 +6,45 @@ SMP=auto ERL_MAX_PORTS=32000 ERL_PROCESSES=250000 ERL_MAX_ETS_TABLES=1400 - -SCRIPT_DIR=$(cd ${0%/*} && pwd) +FIREWALL_WINDOW="" +INET_DIST_INTERFACE="127.0.0.1" +ERLANG_NODE=ejabberd@localhost # define default environment variables -NODE=ejabberd -HOST=localhost -ERLANG_NODE=$NODE@$HOST +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 + EXEC_CMD="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= +ARGS="" while [ $# -ne 0 ] ; do PARAM=$1 shift case $PARAM in --) break ;; - --node) ERLANG_NODE_ARG=$1; shift ;; + --node) ERLANG_NODE_ARG=$1 ; shift ;; --config-dir) ETCDIR=$1 ; shift ;; --config) EJABBERD_CONFIG_PATH=$1 ; shift ;; --ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;; @@ -37,13 +58,15 @@ done if [ "$ETCDIR" = "" ] ; then ETCDIR={{sysconfdir}}/ejabberd fi -if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then - EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg -fi if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg fi -[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH" +if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then + . "$EJABBERDCTL_CONFIG_PATH" +fi +if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then + EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg +fi if [ "$LOGS_DIR" = "" ] ; then LOGS_DIR={{localstatedir}}/log/ejabberd fi @@ -57,60 +80,26 @@ if [ "$ERLANG_NODE_ARG" != "" ] ; then ERLANG_NODE=$ERLANG_NODE_ARG NODE=${ERLANG_NODE%@*} fi - -# check the proper system user is used -ID=`id -g` -GIDS=`id -G` -EJID=`id -g $INSTALLUSER` -EXEC_CMD="false" -for GID in $GIDS; do - if [ $GID -eq 0 ] ; then - EXEC_CMD="su ${INSTALLUSER} -p -c" - fi -done -if [ "$ID" -eq "$EJID" ] ; 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 - -NAME=-name -[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname - -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 - KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE}\"" -fi - -ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS" - -# define additional environment variables if [ "{{release}}" != "true" ] ; then if [ "$EJABBERDDIR" = "" ] ; then - EJABBERDDIR={{libdir}}/ejabberd + EJABBERDDIR={{libdir}}/ejabberd fi if [ "$EJABBERD_EBIN_PATH" = "" ] ; then - EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin + EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin fi if [ "$EJABBERD_PRIV_PATH" = "" ] ; then - EJABBERD_PRIV_PATH=$EJABBERDDIR/priv + EJABBERD_PRIV_PATH=$EJABBERDDIR/priv fi if [ "$EJABBERD_BIN_PATH" = "" ] ; then - EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin + EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin fi if [ "$EJABBERD_SO_PATH" = "" ] ; then - EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib + EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib fi if [ "$EJABBERD_MSGS_PATH" = "" ] ; then - EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs + 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"` @@ -118,11 +107,29 @@ ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump ERL_INETRC=$ETCDIR/inetrc HOME=$SPOOLDIR -# create the home dir with the proper user if doesn't exist, because it stores cookie file -[ -d $HOME ] || $EXEC_CMD "mkdir -p $HOME" +# 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 -# Change to a directory readable by INSTALLUSER to +# create the ejabberd home dir with the proper user if doesn't exist +# then change to that directory readable by INSTALLUSER to # prevent "File operation error: eacces." messages +[ -d $HOME ] || $EXEC_CMD "mkdir -p $HOME" cd $HOME # export global variables @@ -141,16 +148,10 @@ export ERL_MAX_ETS_TABLES export HOME export EXEC_CMD - -# Compatibility in ZSH -#setopt shwordsplit 2>/dev/null - # start server -start () +start() { - checknodenameusage - [ "$?" -eq 0 ] && echo "\nERROR: The node '$ERLANG_NODE' is already running." && return 1 - + check_start $EXEC_CMD "$ERL \ $NAME $ERLANG_NODE \ -noinput -detached \ @@ -163,7 +164,7 @@ start () } # attach to server -debug () +debug() { echo "--------------------------------------------------------------------" echo "" @@ -182,7 +183,7 @@ debug () echo " EJABBERD_BYPASS_WARNINGS=true" echo "Press any key to continue" if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then - read foo + read foo fi echo "" TTY=`tty | sed -e 's/.*\///g'` @@ -195,11 +196,9 @@ debug () } # start interactive server -live () +live() { - checknodenameusage - [ "$?" -eq 0 ] && echo "\nERROR: The node '$ERLANG_NODE' is already running." && return 1 - + check_start echo "--------------------------------------------------------------------" echo "" echo "IMPORTANT: ejabberd is going to start in LIVE (interactive) mode." @@ -216,7 +215,7 @@ live () echo " EJABBERD_BYPASS_WARNINGS=true" echo "Press any key to continue" if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then - read foo + read foo fi echo "" $EXEC_CMD "$ERL \ @@ -228,7 +227,14 @@ live () $ERLANG_OPTS $ARGS \"$@\"" } -help () +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:" @@ -247,7 +253,7 @@ help () } # common control function -ctl () +ctl() { COMMAND=$@ @@ -258,71 +264,71 @@ ctl () 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 + 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 + # 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 + ssresult=`expr $ssresult \* 10` + exit $ssresult + else + exit 1 + fi ) - result=$? - if [ $result -eq 1 ]; then + 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) + 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; + 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;; + 0) :;; + 1) :;; + 2) help;; + 3) help;; esac return $result } -ctlexec () +ctlexec() { CONN_NAME=$1; shift COMMAND=$@ @@ -335,17 +341,30 @@ ctlexec () -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" } -# display ctl usage -usage () -{ - ctl - exit -} - # stop epmd if there is no other running node stop_epmd() { - epmd -names | grep -q name || epmd -kill + 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 @@ -355,9 +374,9 @@ wait_for_status() # return: 0 OK, 1 KO timeout=$2 status=4 - while [ $status -ne $1 ]; do + while [ $status -ne $1 ] ; do sleep $3 - timeout=$(($timeout - 1)) + timeout=`expr $timeout - 1` [ $timeout -eq 0 ] && { status=$1 } || { @@ -365,28 +384,16 @@ wait_for_status() status=$? } done - [ $timeout -eq 0 ] && { - status=1 - } || { - status=0 - } - return $status -} - -# check node name is used or not -# $? --> 0=alreadyused 1=available -checknodenameusage () -{ - $EXEC_CMD "$ERL \ - $NAME $ERLANG_NODE \ - -s erlang halt | grep -c duplicate_name > /dev/null " + [ $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 + ' stopped') wait_for_status 3 15 2 && stop_epmd;; # wait 15x2s before timeout *) ctl $ARGS;; esac diff --git a/src/ejabberd_logger.erl b/src/ejabberd_logger.erl index afb1f3f3d..5d29c99e1 100644 --- a/src/ejabberd_logger.erl +++ b/src/ejabberd_logger.erl @@ -5,6 +5,24 @@ %%% %%% @end %%% Created : 12 May 2013 by Evgeniy Khramtsov +%%% +%%% ejabberd, Copyright (C) 2013 ProcessOne +%%% +%%% 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 2 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, write to the Free Software +%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA + %%%------------------------------------------------------------------- -module(ejabberd_logger). diff --git a/src/p1_mnesia.erl b/src/p1_mnesia.erl index 97acfc352..fa308176c 100644 --- a/src/p1_mnesia.erl +++ b/src/p1_mnesia.erl @@ -1,19 +1,22 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% -%% The Initial Developer of the Original Code is ProcessOne. -%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne -%% All Rights Reserved.'' +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne +%%% All Rights Reserved.'' +%%% +%%% This software is copyright 2006-2013, ProcessOne. -module(p1_mnesia).