#!/bin/sh
#
# $Id: start,v 1.96 2000/02/17 05:26:13 per Exp $

pre="`echo \" $$             \" | sed -e 's/\(.........\)\(.*\)/\1/g'` :"

cd `dirname $0`

# Can be set with '--config-dir=DIR'
DIR=../configurations/
LOGDIR=../logs/
FILES="default"
program=base_server/roxenloader.pike
extra_args=""

pcdir="precompiled/`uname -m`.`uname -r`"
old_roxen_defines="$pcdir/old_roxen_defines"
./mkdir -p $pcdir

# Default verbosity level.
verbose=1

# Do not default to using a relative path.
roxendir="`pwd`"

# Set up environment
if test -f etc/environment; then
  . etc/environment
fi

# Make sure $CLASSPATH contains the servlet stuff
CLASSPATH=java/classes/roxen_module.jar:java/classes/roxen_servlet.jar:java/classes/servlet.jar:java/classes${CLASSPATH:+:}$CLASSPATH
export CLASSPATH


pike=`type pike|head -1|sed -e 's,.*is ,,'`
if [ -x bin/pike ] ; then pike=$roxendir/bin/pike; fi
if [ -x bin/roxen ] ; then  pike=$roxendir/bin/roxen; fi
if [ "x$PIKE" = "x" ]; then :; else
  if [ -x "$PIKE" ]; then pike="$PIKE"; fi
fi


if [ x"$pike" = "x" ] ; then
  echo "No pike binary found. Aborting."
  exit 1
fi

if [ ! -f "$pike" ] ; then
  echo "No pike binary found. Aborting."
  exit 1
fi

####### BEGIN ARGUMENT PARSING


DEFINES="$DEFINES -DKEEP_ALIVE"

# Enable threads (if available) on Solaris.
# Most other OS's have thread bugs that cause them or Roxen to crash.
if uname | grep 'SunOS' >/dev/null 2>&1; then
  if uname -r | grep '5\.[5-9]' >/dev/null 2>&1; then
    if [ $verbose -gt 0 ] ; then
      echo "$pre Solaris 2.5 or later detected. Enabling threads (if available)."
    fi
    DEFINES="$DEFINES -DENABLE_THREADS -DTHREADS"
  fi
fi

gdb=no

remove_old_dot_o_files () {
  echo "$pre Removing old .o files ($1)"
  find $pcdir -name '*.o' | xargs rm -f
}


## Parse all arguments.
## GNU-style, long options only, except for -D, simply passed on.
ARGS=""

parse_args() {
 while [ ! c"$1" = "c" ] ; do
  case $1 in
  -D*)
   DEFINES="$DEFINES $1"
  ;;
  -l*)
   ARGS="$ARGS $1"
  ;;
# Used by the 'install' script
  --truss)
     pike="truss $pike"
   ;;
  --truss-c)
     pike="truss -c $pike"
   ;;
  --log-dir=*)
   LOGDIR=`echo $1 | sed -e 's/--log-dir=//'`
  ;;
  --config-dir=*)
   DIR=`echo $1 | sed -e 's/--config-dir=//'`
   FILES=`echo $1 | sed -e's/--config-dir=//' -e's/\.//g' -e's./..g' -e 's.-..g'`
  ;;
  --pid-file=*)
   extra_args="$extra_args $1"
  ;;
  '--debug'|'--with-debug'|'--enable-debug')
    debug=1
  ;;
  '--without-debug')
    debug=-1
  ;;
  '--fd-debug'|'--with-fd-debug'|'--enable-fd-debug')
    DEFINES="-DFD_DEBUG $DEFINES"
  ;;
  '--dump-debug'|'--with-dump-debug'|'--enable-dump-debug')
    DEFINES="-DDUMP_DEBUG $DEFINES"
  ;;
  '--threads'|'--with-threads'|'--enable-threads')
    DEFINES="-DENABLE_THREADS $DEFINES"
  ;;
  '--no-threads'|'--without-threads'|'--disable-threads')
    DEFINES="`echo $DEFINES | sed -e 's/-DENABLE_THREADS//'`"
  ;;
  '--no-keep-alive'|'--without-keep-alive'|'--disable-keep-alive')
    DEFINES="`echo $DEFINES | sed -e 's/-DKEEP_ALIVE//'`"
  ;;
  '--with-profile'|'--profile')
    DEFINES="-DPROFILE $DEFINES"
  ;;
  '--with-file-profile'|'--file-profile')
    DEFINES="-DPROFILE -DFILE_PROFILE $DEFINES"
  ;;
  '--keep-alive'|'--with-keep-alive'|'--enable-keep-alive')
    DEFINES="-DKEEP_ALIVE $DEFINES"
  ;;
  '--quiet'|'-q')
    verbose=0
  ;;
  '--verbose'|'-v')
    verbose=2
    debug=1
  ;;
  '--remove-dumped')
     remove_old_dot_o_files "user request"
  ;;
  '--once')
    once=1
  ;;
# Misspelling --once might give undesirable results, so let's accept
# some "creative" spellings...  :-)
  '--onve'|'--onec'|'--onev')
    once=1
  ;;
  '--gdb')
    gdb=gdb
    once=1
  ;;
  '--program')
    program="$2"
    once=1
    shift
  ;;
  '--cd')
    cd_to="$2"
    # Use the absolute path...
    roxendir="`pwd`"
    once=1
    shift
  ;;
  -r*|-d*|-t*|-l*|-w*)
    # Argument passed along to Pike.
    ARGS="$ARGS $1"
  ;;
  -D*|-M*|-I*|-P*)
    # Argument passed along to Pike.
    DEFINES="$DEFINES $1"
  ;;
  '--version')
    if [ -f base_server/roxen.pike ]; then
      VERSION="`sed <base_server/roxen.pike -e'/__roxen_version__/s/[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\)[^0-9]*/\1/p' -ed | head -1`"
      BUILD="`sed <base_server/roxen.pike -e'/__roxen_build__/s/[^0-9]*\([0-9][0-9]*\)[^0-9]*/\1/p' -ed | head -1`"
      echo "Roxen $VERSION.$BUILD"
      exit 0
    else
      echo 'base_server/roxen.pike not found!'
      exit 1
    fi
  ;;
  '--help'|'-?')
  sed -e "s/\\.B/`tput 'bold' 2>/dev/null`/g" -e "s/B\\./`tput 'sgr0' 2>/dev/null`/g" << EOF
.BThis command will start the Roxen serverB..

The environment variable .BROXEN_ARGSB. can be used to specify
the default arguments.

   .BArguments:B.

      .B--versionB.:                  Output version information.

      .B--help -?B.:                  This information.

      .B--remove-dumpedB.:            Remove all dumped code, thus forcing
                                  a recompile.

      .B--verbose -vB.:               Enable more verbose messages.

      .B--quiet -qB.:                 Disable most of the messages.

      .B--log-dir=DIRB.:              Set the log directory. Defaults to .B../logsB..

      .B--config-dir=DIRB.:           Use an alternate configuration directory.
				  Defaults to .B../configurationB..

      .B--with-threadsB.:             If threads are available, use them.

      .B--without-threadsB.:          Even if threads are enabled by default,
                                  disable them.

      .B--with-profileB.:             Store runtime profiling information on
				  a directory basis. This information is
 				  not saved on permanent storage, it is only
				  available until the next server restart
				  This will enable a new 'action' in the
				  configuration interface

      .B--with-file-profileB.:        Like .B--with-profileB., but save information
                                  for each and every file.

      .B--with-keep-aliveB.:          Enable keep alive in the HTTP
			          protocol module. This is the default.
                                  Some clients might have problems
                                  with keep-alive.

      .B--without-keep-aliveB.:       Disable keep alive in the HTTP
			          protocol module. Some clients might have
				  problems with keep-alive.

      .B--onceB.:                     Run the server only once, in the foreground.
			   	  This is very useful when debugging.

      .B--gdbB.:                      Run the server in gdb. Implies .B--onceB..

      .B--programB.:                  Start a different program with the roxen
				  Pike. As an example,
                                  .B./start --program bin/install.pikeB. will
				  start the installation program normally
                                  started with .B./installB.

      .B--with-debugB.:               Enable debug

      .B--without-debugB.:            Disable all debug

      .B--with-fd-debugB.:            Enable FD debug.

      .B--with-dump-debugB.:          Enable dump debug.

      .B--trussB.:                    (Solaris only). Run the server under
				  truss, shows .BallB. system calls. This is
				  extremely noisy, and is not intented for
				  anything but debug.

      .B--truss-cB.:                  (Solaris only). Run the server under
				  truss -c, shows times for all system calls
                                  on exit. This is not intented for anything
                                  but debug. Slows the server down.

      .B--pid-file=<file>B.:          Store the roxen and startscript pids in this
				  file. Defaults to .B/tmp/roxen_$UIDB.

  .BArguments passed to pike:B.

       .B-DDEFINEB.:                  Define the symbol .BDEFINEB..

       .B-d<level>B.:                 Set the runtime Pike debug to level.
				  This only works if Pike is compiled
				  with debug.

       .B-rtB.:                       Enable runtime typechecking.
				  Things will run more slowly, but it is very
                                  useful while developing code.

				  Enabled when starting roxen with --debug

       .B-rTB.:                       Enable strict types.
				  Same as adding #pragma strict-types
				  to all files.

				  This enables more strict
				  type-checking, things that are
				  normally permitted (such as calling
				  a mixed value, or assigning a typed
				  object variable with an untyped
				  object) will generate warnings.

				  Useful for module and roxen core
				  developers, but not so useful for
				  the occasional pike-script-writer.

				  Enabled when starting roxen with --debug

       .B-s<size>B.:                  Set the stack size.

       .B-M<path>B.:                  Add the path to the Pike module path.

       .B-I<path>B.:                  Add the path to the Pike include path.

       .B-P<path>B.:                  Add the path to the Pike program path.

       .B-dtB.:                       Turn off tail recursion optimization.

       .B-tB.:                        Turn on Pike level tracing.

       .B-t<level>B.:                 Turn on more Pike tracing. This only
				  works if Pike is compiled with debug.

       .B-wB.:                        Turn on Pike warnings.

  .BEnvironment variables:B.

     .BLANGB.:                        Used to determine the default locale
                                  in the configuration interface and logs.
     .BROXEN_CONFIGDIRB.:             Same as .B--config-dir=... B.
     .BROXEN_PID_FILEB.:              Same as .B--pid-file=... B.
     .BROXEN_LANGB.:                  The default language for all language
		                  related tags. Defaults to 'en' for english.

EOF
    tput 'rmso' 2>/dev/null
    exit 0
   ;;
  *)
    pass="$pass $1"
   ;;
  esac
  shift
 done
}

parse_args $@

if [ ! "X$ROXEN_ARGS" = "X" ]; then
  if [ $verbose -gt 0 ]; then
    echo "$pre Using $ROXEN_ARGS from ROXEN_ARGS."
  else :; fi
  parse_args $ROXEN_ARGS
fi

if [ ! "X$pass" = "X" ] ; then set -- $pass ;fi


####### END ARGUMENT PARSING


####### BEGIN PIKE OPTIONS

# Roxen will create files as the initial user,
# which it expects to be able to read as the run-time user.
umask 022

if [ "x$PIKE_NO_DEFAULT_PATHS" = "x" ]; then
  # Pike default Master-program
  if [ "x$PIKE_MASTER" = "x" ]; then
    if [ -d share/pike ]; then
      # This is used with localinstall
      DEFINES="$DEFINES -I$roxendir/share/pike/include"
      PIKE_MODULE_PATH="$PIKE_MODULE_PATH:$roxendir/share/pike/modules"
    fi
    if [ -f lib/master.pike ]; then
      DEFINES="$DEFINES -m$roxendir/lib/master.pike -I$roxendir/lib/include"
      PIKE_MODULE_PATH="$PIKE_MODULE_PATH:$roxendir/lib/modules:$roxendir/share/modules"
    elif [ -f lib/pike/master.pike ]; then
      DEFINES="$DEFINES -m$roxendir/lib/pike/master.pike -I$roxendir/lib/pike/include"
      PIKE_MODULE_PATH="$PIKE_MODULE_PATH:$roxendir/lib/pike/modules:$roxendir/share/pike/modules"
    fi
    export PIKE_MODULE_PATH
  else
    # This is useful when using several different Pikes.
    # Specify include and module paths with
    # PIKE_INCLUDE_PATH and PIKE_MODULE_PATH
    # they are handled automatically by the master,
    # so no need to do it here.
    DEFINES="$DEFINES -m$PIKE_MASTER"
  fi
fi

# Extra module-path
if [ -d etc/modules ]; then
  DEFINES="$DEFINES -M$roxendir/etc/modules"
fi

# Extra include-path
if [ -d etc/include ]; then
  DEFINES="$DEFINES -I$roxendir/etc/include"
fi

# Extra include-path (2)
if [ -d base_server ]; then
  DEFINES="$DEFINES -I$roxendir/base_server"
fi

# Extra program-path
DEFINES="$DEFINES -P`pwd`"

# Support for adding local pike-modules
if [ -d ../local/etc/. ]; then
  # Extra module-path
  if [ -d ../local/etc/modules/. ]; then
    DEFINES="$DEFINES -M$roxendir/../local/etc/modules"
  fi

  # Extra include-path
  if [ -d ../local/etc/include ]; then
    DEFINES="$DEFINES -I$roxendir/../local/etc/include"
  fi

  # Extra program-path
  DEFINES="$DEFINES -P$roxendir/../local/etc"
fi

# Extra kludge for HPUX
# HPUX doesn't like group 60001(nobody)
if uname | grep 'HP-UX' >/dev/null 2>&1; then
  if [ $verbose -gt 0 ]; then
    echo "$pre WARNING: Applying kludge for HPUX. (see base_server/privs.pike)"
  else :; fi
  DEFINES="$DEFINES -DHPUX_KLUDGE"
fi


case "x$debug" in
  "x")
    DEBUG="-DMODULE_DEBUG "
    ARGS="$ARGS -w"
    ;;
  "x-1")
    DEBUG=""
    ;;
  "x1")
    DEBUG="-DDEBUG -DMODULE_DEBUG"
    ARGS="$ARGS -w"
    ;;
esac

DEFINES="$DEBUG $DEFINES"

####### END PIKE OPTIONS


#
# Some useful functions
#

rotate () {
  b=5;
  for a in 4 3 2 1 ; do mv -f $1.$a $1.$b 2> /dev/null;  b=$a; done
}

start_roxen() {
  if [ "x$DIR" != "x../configurations/" ] ; then
    args="$DEFINES $ARGS $program --config-dir=$DIR $pass"
  else
    args="$DEFINES $ARGS $program $pass"
  fi
  if [ x$cd_to != x ] ; then
    cd $cd_to
  fi
  if [ "x$gdb" = "xno" ]; then
    if [ $verbose -gt 0 ]; then
      if [ $verbose -gt 1 -o -z "$once" ] ; then
        echo "$pre" "Executing $pike $args $@"|sed -e "s!`pwd`!.!g"
      else
        echo "$pre" "Using '$pike'"|sed -e "s!`pwd`!.!g"
      fi
    fi
    args="-DSERIOUS $args"
    $pike $args $@
  else
    echo "$pre" Executing gdb $pike $args $@
    args="-DSERIOUS $args"
    echo >.gdbinit handle SIGPIPE nostop noprint pass
    echo >>.gdbinit handle SIGUSR1 nostop noprint pass
    echo >>.gdbinit handle SIGUSR2 nostop noprint pass
    echo >>.gdbinit run $args $@
    gdb $pike
    rm .gdbinit
  fi
}

#
# Now do the stuff
#
PIKEVERSION=`$pike --version 2>&1`


if [ "$program" = "base_server/roxenloader.pike" ] ; then
  if [ "`cat $old_roxen_defines 2>/dev/null`" != "$PIKEVERSION $DEFINES" ] ; then
    remove_old_dot_o_files "defines or pike version changed"
  fi
  echo "$PIKEVERSION $DEFINES" > $old_roxen_defines
fi

if [ -z "$once" ] ; then
  if [ $verbose -gt 0 ]; then
    echo "$pre" Starting the Roxen World Wide Web server.
  else :; fi
  ./mkdir -p $LOGDIR/debug/

  if [ $verbose -gt 0 ]; then
    cat << oo
Using configuration from $DIR, storing the debug log in $LOGDIR/debug/$FILES.1
You can use the configuration interface in the server to get debug info.
oo
  else :; fi

  # Try to get rid of some fd's.
  # Some /bin/sh's have problems detaching otherwise.

  exec >/dev/null
  exec </dev/null

  if ((while : ; do
      echo "$pre" "Server restart at `date`"
      echo "$pre" "Debug log in $LOGDIR/debug/$FILES.1"
      rotate $LOGDIR/debug/$FILES
      start_roxen $extra_args 2>>$LOGDIR/debug/$FILES.1 1>&2

      exitcode="$?"

      if [ "$exitcode" -eq "0" ] ; then
        # Clean shutdown.
        echo "$pre" "Roxen shutdown."
        exit 0
      fi
      if [ "$exitcode" -lt "0" ] ; then
        # Signal death.
        echo "$pre" "Roxen died of signal $exitcode. Restarting..."
      else
        echo "$pre" Roxen down. Restarting.
      fi
      done) & ) </dev/null >$LOGDIR/debug/start_$FILES.output 2>&1; then
    :;
  else
    echo 'Failed to spawn subshell. -- Permission problem?' 1>&2
    exit 1
  fi
else
  start_roxen $extra_args 2>&1
fi
