#!/bin/bash
#
# stap-server script for managing the systemtap compile server
#
# Copyright (C) 2008, 2009 Red Hat Inc.
#
# This file is part of systemtap, and is free software.  You can
# redistribute it and/or modify it under the terms of the GNU General
# Public License (GPL); either version 2, or (at your option) any
# later version.
#
# This script provides management of systemtap compile servers as a service.
# See stap-server(8) for more information.

. /etc/rc.d/init.d/functions

# Systemtap function library
. ${PKGLIBEXECDIR}stap-env

prog=stap-server

# Commands
STAP_START_SERVER=${stap_pkglibexecdir}stap-start-server
STAP_STOP_SERVER=${stap_pkglibexecdir}stap-stop-server
UNAME=/bin/uname

# Default Global Configuration
CONFIG_FILE=$stap_sysconfdir/sysconfig/stap-server
CONFIG_PATH=$stap_sysconfdir/stap-server/conf.d
STAT_PATH=$stap_localstatedir/run/stap-server
LOG_FILE=$stap_localstatedir/log/stap-server/log

# Default option settings
# Optional global config file
OPT_CONFIG_FILE=

echo_usage () {
  echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|status} [options]"
  echo $"Options:"
  echo $"	-c configfile	: specify additional global configuration file."
  echo $"	-a arch		: specify the target architecture."
  echo $"	-r release	: specify the kernel release."
  echo $"	-I path		: augment the search path for tapsets."
  echo $"	-R path		: specify the location of the systemtap runtime."
  echo $"	-B options	: specify 'make' options for building systemtap modules."
  echo $"	-u username	: specify the user who will run the server(s)."
  echo $"	-i		: specify a server for each installed kernel release."
  echo $"	-n nickname	: specify a server configuration by nickname."
  echo $"	-p pid		: specify a server or server configuration by process id."
  echo $""
  echo $"All options, may be specified more than once."
  echo $""
  echo $"If -a is not specified, the default architecture is that of the host"
  echo $"platform."
  echo $""
  echo $"If -r is not specified, the default kernel release is that currently"
  echo $"running on the host platform."
  echo $""
  echo $"If -u is not specified, the default user is 'stap-server'"
  echo $""
  echo $"Each -I and -B option specifies an additional path or option"
  echo $"respectively. For other options, each new instance overrides the"
  echo $"previous setting."
  echo $""
  echo $"The -i option is a shortcut which specifies one server for each kernel"
  echo $"release installed in /lib/modules/. Previous -I, -R, -B and -u"
  echo $"options will be applied to each server, however previous -a options"
  echo $"are ignored and the default architecture is used." 
  echo $""
  echo $"The -n option allows the specification of a server configuration by"
  echo $"nickname. When -n is specified, a currently running server with the"
  echo $"given nickname will be searched for. If no currently running server"
  echo $"with the given nickname is found, a server configuration with the"
  echo $"given nickname will be searched for in $stap_sysconfdir/stap-server/conf.d/*.conf."
  echo $"If a server configuration for the given nickname is found, the -a, -r,"
  echo $"-I, -R, -B and -u options for that server will be used as if they were"
  echo $"specified on the command line. If no configuration with the given"
  echo $"nickname is found, and the action is 'start' (or an action behaving"
  echo $"like 'start' (see below), the server will be started with the given"
  echo $"nickname. If no configuration with the given nickname is found, and"
  echo $"the action is not 'start' (or an action behaving" "like 'start',"
  echo $"it is an error. If a nickname is not specified for a server, its"
  echo $"nickname will be its process id."
  echo $""
  echo $"The -p option allows the specification of a server configuration by"
  echo $"process id. When -p is specified, a currently running server with the"
  echo $"given process id will be searched for. If no such server is found,"
  echo $"it is an error. If a server with the given pid is found, the -a, -r,"
  echo $"-I, -R, -B and -u options for that server will be used as if they were"
  echo $"specified on the command line."
  echo $""
  echo $"The specified action is performed for the server(s) specified on the"
  echo $"command line. If no servers are specified on the command line, the"
  echo $"behavior is as follows:"
  echo $""
  echo $"  start:        Start the servers configured in $stap_sysconfdir/stap-server/conf.d/*.conf."
  echo $"                If none are configured, start a server for the kernel release"
  echo $"                and architecture of the host platform."
  echo $""
  echo $"  stop:         Stop all currently running servers."
  echo $""
  echo $"  restart:      Restart all currently running servers. If no servers are running,"
  echo $"                behave as if 'start' was specified."
  echo $""
  echo $"  condrestart:  Restart all currently running servers. If no servers are running,"
  echo $"                do nothing."
  echo $""
  echo $"  try-restart:  Same as condrestart."
  echo $""
  echo $"  force-reload: Stop all currently running servers and behave as if 'start'"
  echo $"                was specified."
  echo $""
  echo $"  status:       Report the status of all current running servers."
  echo $""
}

#-----------------------------------------------------------------
# Helper functions
#-----------------------------------------------------------------
log () { # message
  echo `LC_ALL=en date +"%b %e %T"`": $1" >> "$LOG_FILE"
}
clog () { # message [-n]
  echo $2 "$1"
  log "$1"
}
slog () { # message
  logger "$1" # if syslogd is running, this message will be sent to syslog.
  log "$1"
}
logex () { # command
  eval log \"Exec: $@\"
  "$@" >> "$LOG_FILE" 2>&1
  return $?
}
do_failure () { # message
  slog "Error: $1"
  failure "$1"
}
do_success () { # message
  log "Pass: $1"
  success "$1"
}

#------------------------------------------------------------------
# Parameter parsing and setup options
#------------------------------------------------------------------
parse_args () { # arguments
  local rc=0
  while [ -n "$1" ]; do
    case "$1" in
      -a)
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS ARCH='$2'"
        shift 1
	;;
      -B)
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS BUILD='$2'"
        shift 1
	;;
      -c)
        OPT_CONFIG_FILE=$2
        shift 1
        ;;
      -i)
	process_i
	;;
      -I)
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS INCLUDE='$2'"
        shift 1
	;;
      -n)
	process_n $2
        shift 1
	;;
      -p)
	process_p $2
	test $? = 0 || rc=1
        shift 1
	;;
      -r)
	process_r $2
	test $? = 0 || rc=1
        shift 1
	;;
      -R)
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS RUNTIME='$2'"
        shift 1
	;;
      -u)
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS USER='$2'"
        shift 1
	;;
      --)
        ;;
      *)
	rc=1
        ;;
    esac
    shift 1
  done

  # Add an EXEC command to the end if any server options were specified
  test -n "$OPT_SERVER_CMDS" && OPT_SERVER_CMDS="$OPT_SERVER_CMDS EXEC"

  test $rc != 0 && echo_usage
  return $rc
}

# Process the -i flag.
process_i () {
  cd /lib/modules
  local release
  for release in `ls`; do
      test -n "$OPT_SERVER_CMDS" && OPT_SERVER_CMDS="$OPT_SERVER_CMDS EXEC"
      process_r $release
  done

  return 0
}

# Process the -n flag.
process_n () {
  local target_NICKNAME="$1"

  # Is there a running server with this nickname?
  local pid=`get_server_pid_by_nickname "$target_NICKNAME"`
  if [ -n "$pid" ]; then
      # Read the configuration and add it to the configuration commands.
      . $STAT_PATH/$pid
      OPT_SERVER_CMDS="$OPT_SERVER_CMDS `echo_server_commands`"
      return
  fi

  # Is there a server configuration with this nickname?
  for f in "$CONFIG_PATH"/*.conf; do
    if [ -f "$f" ]; then
      . "$f"
      test "X$NICKNAME" = "X$target_NICKNAME" || continue
      OPT_SERVER_CMDS="$OPT_SERVER_CMDS `echo_server_commands`"
      return
    fi
  done

  # No server configuration could be found for this nickname. Add a
  # NICKNAME_NOT_FOUND=... command to the configuration commands.
  OPT_SERVER_CMDS="$OPT_SERVER_CMDS NICKNAME_NOT_FOUND='$target_NICKNAME'"
}

# Process the -p flag.
process_p () {
  local pid="$1"

  # Are we managing a server with the given pid?
  test ! -f $STAT_PATH/$pid && echo "No stap-server running as pid $pid" && \
      exit 1

  # Add the configuration of the server running as $pid to OPT_SERVER_CMDS
  . $STAT_PATH/$pid
  OPT_SERVER_CMDS="$CONFIG_SERVER_CMDS `echo_server_commands`"

  return 0
}

# Process the -r flag.
process_r () {
    local first_char=`expr "$1" : '\(.\).*'`

    if test "$first_char" = "/"; then # fully specified path
        local kernel_build_tree=$1
        local version_file_name="$kernel_build_tree/include/config/kernel.release"
        # The file include/config/kernel.release within the kernel
        # build tree is used to pull out the version information
	local kernel_release=`cat $version_file_name 2>/dev/null`
	if test "X$kernel_release" = "X"; then
	    echo "Missing $version_file_name"
	    return 1
	fi
	OPT_SERVER_CMDS="$OPT_SERVER_CMDS RELEASE='$kernel_release'"
	return 0
    fi

    # kernel release specified directly
    OPT_SERVER_CMDS="$OPT_SERVER_CMDS RELEASE='$1'"
    return 0
}

load_config () {
  # Include configs
  if [ -f "$CONFIG_FILE" ]; then
    . "$CONFIG_FILE"
  fi
  if [ -f "$OPT_CONFIG_FILE" ]; then
    . "$OPT_CONFIG_FILE"
  fi
}

# Default to the currently running kernel release
get_release () {
    $UNAME -r
}

# Default to the currently running kernel release
get_arch () {
    stap_get_arch
}

echo_server_commands () {
    # Echo the configuration command string.
    echo -n "ARCH='$ARCH'"
    echo -n " RELEASE='$RELEASE'"
    echo -n " RUNTIME='$RUNTIME'"
    for i in $INCLUDE; do
	echo -n " INCLUDE='$i'"
    done
    for b in $BUILD; do
	echo -n " BUILD='$b'"
    done
    echo -n " USER='$USER'"
    echo -n " NICKNAME='$NICKNAME'"
    echo
}

echo_server_options () {
    # Echo the configuration options.
    echo -n "-a '$ARCH'"
    echo -n " -r '$RELEASE'"
    test -n "$RUNTIME" && echo -n " -R '$RUNTIME'"
    for i in $INCLUDE; do
	echo -n " -I '$i'"
    done
    for b in $BUILD; do
	echo -n " -B '$b'"
    done
    test -n "$USER" && echo -n " -u '$USER'"
    echo -n " -n '$NICKNAME'"
    echo
}

load_server_config () {
  CONFIG_SERVER_CMDS=
  for f in "$CONFIG_PATH"/*.conf; do
    if [ -f "$f" ]; then
      # Obtain a configuration from each config file.
      # Ensure that we get the correct defaults for items not specified.
      local ARCH=
      local BUILD=
      local INCLUDE=
      local RUNTIME=
      local USER=
      local RELEASE=
      . "$f"
      # Other options default to empty. These ones don't.
      [ -z "$ARCH" ]     && ARCH=`get_arch`
      [ -z "$RELEASE" ]  && RELEASE=`get_release`
      [ -z "$USER" ]     && USER=$STAP_USER
      CONFIG_SERVER_CMDS="$CONFIG_SERVER_CMDS `echo_server_commands` EXEC"
    fi
  done
}

prepare_stat_dir () {
  if [ ! -d "$STAT_PATH" ]; then
    logex mkdir -p "$STAT_PATH"
    [ $? -ne 0 ] && return 1
  fi
  return 0
}

prepare_log_dir () {
  local log_path=`dirname "$LOG_FILE"`
  if [ ! -d "$log_path" ]; then
      mkdir -p "$log_path"
      [ $? -ne 0 ] && return 1
  fi
  return 0
}

stat_file () { # server-spec
    echo $STAT_PATH/$1
}

default_server_cmds () {
  echo "EXEC"
}

init_server_opts () {
  ARCH=`get_arch`
  RELEASE=`get_release`
  BUILD=
  INCLUDE=
  NICKNAME=
  NICKNAME_NOT_FOUND=
  RUNTIME=
  USER=$STAP_USER
}

server_still_running () { # PID
    (ps -e | grep stap-serverd | grep -q $1) && return 0 # Still running

    rm -f $STAT_PATH/$1
    return 1 # Not running
}

get_server_pid_by_config () {
    # Need to save the config, since the process of checking the running
    # servers alters it.
    local target_ARCH="$ARCH"
    local target_RELEASE="$RELEASE"
    local target_INCLUDE="$INCLUDE"
    local target_RUNTIME="$RUNTIME"
    local target_BUILD="$BUILD"
    local target_USER="$USER"
    local target_NICKNAME="$NICKNAME"

    # Check the status file for each running server to see if it matches
    # the one currently configured. We're checking for a given configuration,
    # so don't compare the nickname.
    for f in $STAT_PATH/*; do
	test ! -e $f && continue
	. $f
	test "X$ARCH"     = "X$target_ARCH"     || continue
	test "X$RELEASE"  = "X$target_RELEASE"  || continue
	test "X$INCLUDE"  = "X$target_INCLUDE"  || continue
	test "X$RUNTIME"  = "X$target_RUNTIME"  || continue
	test "X$BUILD"    = "X$target_BUILD"    || continue
	test "X$USER"     = "X$target_USER"     || continue
	echo `basename $f` # Server has a pid
	return
    done

    ARCH="$target_ARCH"
    RELEASE="$target_RELEASE"
    INCLUDE="$target_INCLUDE"
    RUNTIME="$target_RUNTIME"
    BUILD="$target_BUILD"
    USER="$target_USER"
    NICKNAME="$target_NICKNAME"
}

get_server_pid_by_nickname () {
    # No need to save the current configuration. This function is not called
    # in a context requiring it.
    local target_NICKNAME="$1"

    # Check the status file for each running server to see if the nickname
    # matches the one we want.
    for f in $STAT_PATH/*; do
	test ! -e $f && continue
	. $f
	test "X$NICKNAME" = "X$target_NICKNAME" || continue
	echo `basename $f` # Server with nickname was found
	return
    done
}

managed_servers () {
  if [ ! -d $STAT_PATH ]; then
      echo ""
      return 1
  fi
  cd $STAT_PATH
  local list=`ls`
  if [ -z "$list" ]; then
      echo ""
      return 1
  fi

  echo "$list"
}

eval_server_command () {
    local cmd="$1"

    # Accumulate the results of BUILD and INCLUDE commands.
    if echo $cmd | grep -q ^BUILD; then
	local prevBUILD="$BUILD"
	eval $cmd
	BUILD="$prevBUILD $BUILD"
	BUILD=`echo $BUILD | sed 's/^ //'`
    elif echo $cmd | grep -q ^INCLUDE; then
	local prevINCLUDE="$INCLUDE"
	eval $cmd
	INCLUDE="$prevINCLUDE $INCLUDE"
	INCLUDE=`echo $INCLUDE | sed 's/^ //'`
    else
	eval $cmd
    fi
}

start_server () {
    clog $"Starting $prog for $RELEASE $ARCH: " -n

    # Is there already a server running for the requested kernel release
    # and arch?
    local server_pid=`get_server_pid_by_config`
    if test -n "$server_pid"; then
	if server_still_running $server_pid; then
	    do_success $"$prog start `echo_server_options`"
	    return 0 # Success
	fi
    fi

    # Construct the server start command.
    local server_cmd="$STAP_START_SERVER -r '$RELEASE' -a '$ARCH'"
    for b in $BUILD; do
	server_cmd="$server_cmd -B '$b'"
    done
    for i in $INCLUDE; do
	server_cmd="$server_cmd -I '$i'"
    done
    test -n "$RUNTIME" && server_cmd="$server_cmd -R '$RUNTIME'"
    server_cmd="$server_cmd --log=$LOG_FILE"

    # Start the server here.
    local pid
    if [ -n "$USER" ]; then
	pid=`runuser -s /bin/bash - $USER -c "$server_cmd"`
    else
	pid=`eval $server_cmd`
    fi
    if [ $? != 0 -o -z "$pid" ]; then
	if [ -n "$pid" ]; then
	    rm -f $STAT_PATH/$pid
	fi
	do_failure $"$prog start `echo_server_options`"
	return 1 # Failure
    fi

    # Nickname defaults to the pid.
    test -z "$NICKNAME" && NICKNAME="$pid"

    # Write the configuration to the status file.
    local server_status_file=$STAT_PATH/$pid
    echo "ARCH='$ARCH'" > $server_status_file
    echo "USER='$USER'" >> $server_status_file
    echo "BUILD='$BUILD'" >> $server_status_file
    echo "INCLUDE='$INCLUDE'" >> $server_status_file
    echo "NICKNAME='$NICKNAME'" >> $server_status_file
    echo "RUNTIME='$RUNTIME'" >> $server_status_file
    echo "RELEASE='$RELEASE'" >> $server_status_file

    do_success $"$prog start `echo_server_options`"
}

start () { # server-cmds
  prepare_stat_dir
  if [ $? -ne 0 ]; then
    do_failure $"Failed to make stat directory ($STAT_PATH)"
    return 1
  fi

  # Start the specified servers
  server_cmds="$1"
  # If none specified, start the configured servers
  if [ -z "$server_cmds" ]; then
    load_server_config
    server_cmds="$CONFIG_SERVER_CMDS"

    # If none configured, start the default servers
    [ -z "$server_cmds" ] && server_cmds=`default_server_cmds`
  fi

  # Start each requested server in turn
  local rc=0
  local first=1
  init_server_opts
  local cmd
  local prevCmd
  for cmd in $server_cmds; do
      prevCmd=$cmd
      # Evaluate commands until the EXEC command is found.
      if test "$cmd" != "EXEC"; then
	  eval_server_command $cmd
	  # A specified nickname only sticks if it is the final command.
	  # Otherwise, we have a configuration based on a nicknamed
	  # configuration.
	  echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME=""
	  continue
      fi
      # If a nickname was specified, but the corresponding config was not found,
      # then it is the nickname for this new configuration.
      if test -n "$NICKNAME_NOT_FOUND"; then
	  NICKNAME="$NICKNAME_NOT_FOUND"
	  NICKNAME_NOT_FOUND=
      fi

      # Start the configured server
      test $first = 0 && echo
      first=0
      start_server || rc=1

      # Don't use the same nickname for the next server.
      NICKNAME=
  done

  return $rc
}

stop () { # server-cmds
  local first=1
  local server_list=
  server_cmds="$1"
  if [ -n "$server_cmds" ]; then
      # Get the pids of all the requested servers.
      init_server_opts
      local cmd
      local prevCmd
      for cmd in $server_cmds; do
	  prevCmd=$cmd
          # Evaluate commands until the EXEC command is found.
	  if test "$cmd" != "EXEC"; then
	      eval_server_command $cmd
	      # A specified nickname only sticks if it is the final command.
	      # Otherwise, we have a configuration based on a nicknamed
	      # configuration.
	      echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME=""
	      continue
	  fi
          # If a nickname was specified, but the corresponding config was not
	  # found, it is an error.
	  if test -n "$NICKNAME_NOT_FOUND"; then
	      clog "No configuration found for the nickname '$NICKNAME_NOT_FOUND'" -n
	      NICKNAME="$NICKNAME_NOT_FOUND"
	      do_failure $"$prog stop `echo_server_options`"
	      NICKNAME_NOT_FOUND=
	      rc=1
	      continue
	  fi

          # Get the pid for this server, if it's running
	  local server_pid=`get_server_pid_by_config`
	  if test -n "$server_pid"; then
	      server_list="$server_list $server_pid"
	      continue
	  fi

	  # This server is not running, but give a success stop status anyway.
	  test $first = 0 && echo
	  first=0
	  clog $"Stopping $prog for $RELEASE $ARCH: " -n
	  do_success $"$prog stop `echo_server_options`"
      done
  else
      server_list=`managed_servers`
      if [ -z "$server_list" ]; then
	  clog $"Stopping $prog: " -n
	  do_success $"$prog: No managed servers to stop"
	  return 0
      fi
  fi

  # Stop each server in turn
  local rc=0
  local pid
  for pid in $server_list; do
      . $STAT_PATH/$pid

      test $first = 0 && echo
      first=0
      clog $"Stopping $prog for $RELEASE $ARCH: " -n

      local this_rc=0
      if server_still_running $pid; then
	  if [ -n "$USER" ]; then
	      runuser -s /bin/bash - $USER -c "$STAP_STOP_SERVER $pid"
	  else
	      eval $STAP_STOP_SERVER $pid
	  fi
	  if [ $? != 0 ]; then
	      do_failure $"$prog stop `echo_server_options`"
	      this_rc=1
	      rc=1
	  fi
      fi
      if [ $this_rc = 0 ]; then
	  rm -f $STAT_PATH/$pid
	  do_success $"$prog stop `echo_server_options`"
      fi
  done

  return $rc
}

status () { # server-list
  local rc=0

  # Report status for the specified servers or all running servers, if none
  # specified.
  local server_list=
  server_cmds="$1"
  if [ -n "$server_cmds" ]; then
      # Get the pids of all the requested servers.
      init_server_opts
      local cmd
      local prevCmd
      for cmd in $server_cmds; do
	  prevCmd=$cmd
          # Evaluate commands until the EXEC command is found.
	  if test "$cmd" != "EXEC"; then
	      eval_server_command $cmd
	      # A specified nickname only sticks if it is the final command.
	      # Otherwise, we have a configuration based on a nicknamed
	      # configuration.
	      echo "$cmd" | grep -q "^NICKNAME=" || NICKNAME=""
	      continue
	  fi
          # If a nickname was specified, but the corresponding config was not
	  # found, say so.
	  if test -n "$NICKNAME_NOT_FOUND"; then
	      echo "No configuration found for the nickname '$NICKNAME_NOT_FOUND'"
	      NICKNAME_NOT_FOUND=
	      rc=3
	      continue
	  fi

          # Get the pid for this server, if it's running
	  local server_pid=`get_server_pid_by_config`
	  if test -n "$server_pid"; then
	      server_list="$server_list $server_pid"
	      continue
	  fi
	  # This server is not running
	  echo "stap-server `echo_server_options`"
	  rc=3
      done
  else
      server_list=`managed_servers`
      if [ -z "$server_list" ]; then
	  echo "No managed stap-server is running"
	  return 3
      fi
  fi

  # Get status of each server in turn
  local pid
  for pid in $server_list; do
      . $STAT_PATH/$pid
      if ! server_still_running $pid; then
	  echo "stap-server `echo_server_options` started as PID $pid is no longer running"
	  rc=1
	  continue
      fi
      echo "stap-server `echo_server_options` running as PID $pid"
  done

  return $rc
}

# Restart or start if not running
function restart () { # server-cmds
  # Restart the specified servers or all servers, if none specified.
  local server_cmds="$1"
  if [ -z "$server_cmds" ]; then
      local server_list=`managed_servers`
      local pid
      for pid in $server_list; do
	  . $STAT_PATH/$pid
	  server_cmds="$server_cmds `echo_server_commands` EXEC"
      done
  fi

  # Stop the specified servers, or all if none specified
  stop "$server_cmds"
  local rc=$?
  echo

  # Restart the same servers. If none were specified then
  # start the configured or default server(s)).
  start "$server_cmds"
  local this_rc=$?
  [ $this_rc != 0 ] && rc=$this_rc

  return $rc
}

# Restart only if running
function condrestart () { # server-list
  # Restart the specified servers or all servers, if none specified,
  # but only if they are already running.
  local server_cmds="$1"
  if [ -z "$server_cmds" ]; then
      local server_list=`managed_servers`
      local pid
      for pid in $server_list; do
	  . $STAT_PATH/$pid
	  server_cmds="$server_cmds `echo_server_commands` EXEC"
      done
      # No server specified or running?
      if [ -z "$server_cmds" ]; then
	  clog "No managed stap-server is running" -n
	  do_success "No managed stap-server is running"
	  return 0
      fi
  fi

  # For each server in the list, stop it if it is running
  local start_cmds=
  local first=1
  local server_cmd=
  local cmd
  for cmd in $server_cmds; do
      # Execute and collect commands until the EXEC command is found.
      server_cmd="$server_cmd $cmd"
      if test "$cmd" != "EXEC"; then
	  eval_server_command $cmd
	  continue
      fi

      test $first = 0 && echo
      first=0

      # Now see if this server is running
      if ! status "$server_cmd" >/dev/null 2>&1; then
	clog $"$prog for $RELEASE $ARCH is not running" -n
	do_success "$prog `echo_server_options` is not running"
	server_cmd=
	continue
      fi

      start_cmds="$start_cmds $server_cmd"

      stop "$server_cmd"
      this_rc=$?
      [ $this_rc != 0 ] && rc=$this_rc

      server_cmd=
  done

  # Now restart the servers that were running
  if [ "X$start_cmds" != "X" ]; then
      echo
      start "$start_cmds"
      local this_rc=$?
      [ $this_rc != 0 ] && rc=$this_rc
  fi

  return $rc
}

#------------------------------------------------------------------
# Mainline script
#------------------------------------------------------------------
CMD=$1
shift 1

prepare_log_dir
if [ $? -ne 0 ]; then
    echo $"Failed to make log directory (`dirname $LOG_FILE`)" >&2
    exit 1
fi

OPTS=`getopt -s bash -u -o 'a:B:c:iI:n:p:r:R:u:' -- $@`
if [ $? -ne 0 ]; then
  echo "Error: Argument parse error: $@" >&2
  echo_usage
  exit 2
fi

# Initialize server specs
OPT_SERVER_CMDS=
parse_args $OPTS || exit 2
load_config

RETVAL=0

case $CMD in
  start)
  # Start specified servers. If none specified, start configured servers
  start "$OPT_SERVER_CMDS"
  RETVAL=$?
  ;;
  stop)
  # Stop specified servers
  stop "$OPT_SERVER_CMDS"
  RETVAL=$?
  ;;
  # Restart specified servers
  restart)
  restart "$OPT_SERVER_CMDS"
  RETVAL=$?
  ;;
  # Restart specified servers if they are running
  condrestart|try-restart)
  condrestart "$OPT_SERVER_CMDS"
  RETVAL=$?
  ;;
  # Give status on specified servers
  status)
  status "$OPT_SERVER_CMDS"
  exit $?
  ;;
  # Reloading config without stop/restart is not supported
  reload)
  RETVAL=3
  ;;
  # Reload config with stop/start
  force-reload)
  # stop all running servers
  stop
  echo
  # Restart specified servers
  # If none specified, restart configured servers
  start "$OPT_SERVER_CMDS"
  RETVAL=$?
  ;;
  usage|*)
  echo_usage
  RETVAL=0
  ;;
esac

echo
exit $RETVAL
