0

On Red Hat 7.4, in init.d, I have file sapabi, which is installed by calling

  • chkconfig --add sapabi

This result in entries like /etc/rc3.d/

  • S10network
  • S90sapinit
  • S91sapabi

Example entry in /etc/rc6.d/

  • K90network
  • K09sapabi
  • K10sapinit

When I execute the file as user root with command

  • ./sapabi start
  • service sapabi start
  • service sapabi stop

everything works fine and the remote SAP Diagnostics Agent is started or stopped by sapcontrol as intended.

However, when I enter the 'reboot' command :

  • during shutdown nothing is executed at all, not even the 'stop' argument
  • during startup, start is passed as an argument and the start() functions are called. Unfortunately, the 'eval' sapcontrol command isn't executed like when I call the ./sapabi start command. Instead, the log file returns the 'help' of sapcontrol :

NAME sapcontrol (Version: 753, patch 200, changelist 1844229)

SYNOPSIS sapcontrol [-prot ] [-trace ] [-debug] ...

  • Why isn't eval executed properly during startup in the same manner like when the script is launched directly?
  • Why isn't the service stopped during shutdown?
  • Am I missing something in Required-Start or Required-Stop?
  • I'm not too sure about the correct use of ' or " in the eval statement

Many thanks for the help

#!/bin/sh
#
# /etc/init.d/sapabi
#
# chkconfig: 345 91 09
# description: Start / stop SAP
#
### BEGIN INIT INFO
# Provides: sapabi
# Required-Start: $network $syslog $local_fs $named $remote_fs $time
# X-UnitedLinux-Should-Start:
# Required-Stop: $network $syslog $local_fs $named $remote_fs $time
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Start the sap system
# Description: Start the sap system
### END INIT INFO
PGM_PATH=$0
ARG1=$1
ARG2=$2

# Remote Diagnostics Agent configuration
#
# DA_R : If set to 1, remote diagnostics services will be started.
#
DA_R=1
DA_R_OS_USER="daaadm"
DA_R_OS_USER_PASSWORD="xxxxxx"
DA_R_INSTANCE_NR="98"
DA_R_START_CMD="StartSystem"
DA_R_STOP_CMD="StopSystem"
DA_R_HOST="xxx.xxx.xxx"

log=/var/log/sapabi.log

function ping_server()
{
    target=$1
    ping -c1 -w3 ${target} &>/dev/null && return 1 || return 0
}

function start_service()
{
    serviceName=$1
    localSidAdm=$2
    serviceHost=$3
    serviceUser=$4
    servicePassword=$5
    serviceInstance=$6
    serviceStartCmd=$7
    processName=$8
    waitTime=$9

    ping_server $serviceHost;
    if [ $? -eq 1 ];
    then
echo "in ping start_service $serviceName" >> $log
        eval ' su -s /bin/csh -l "$localSidAdm" -c "sapcontrol -nr "$serviceInstance" -host "$serviceHost"  -user "$serviceUser" "$servicePassword" -function "$serviceStartCmd""' >> $log
        test=""
        startTime=$(date +%s)
        currentTime=$(date +%s)
        while [[ "${test}" != *"GREEN"*  && ($((currentTime - startTime)) -lt $waitTime) ]];
            do
            test=`su -s /bin/csh -l "$localSidAdm" -c 'sapcontrol -nr '"$serviceInstance"' -host '"$serviceHost"' -user '"$serviceUser"' '"$servicePassword"' -function GetProcessList | grep '"$processName"''`
            # Do not print the trailing newline character
            echo -n "."
            sleep 1
            currentTime=$(date +%s)
        done
        echo ""
        echo "$serviceName - time $((currentTime - startTime)) seconds - ${test}" >> $log
    else
        echo "Error : ${serviceName} host ${serviceHost} not available"
        do_exit ${ERR_unknown_host}
    fi

    unset serviceName
    unset localSidAdm
    unset serviceHost
    unset serviceUser
    unset servicePassword
    unset serviceInstance
    unset serviceStartCmd
    unset processName
    unset waitTime
}

start() {
    #start the remote Diagnostics Agent
    if [ "$DA_R" == 1 ];
        then
            echo "Starting the remote Diagnostics Agent"
            start_service "Remote Diagnostics Agent" $LOCAL_SIDADM $DA_R_HOST $DA_R_OS_USER $DA_R_OS_USER_PASSWORD $DA_R_INSTANCE_NR $DA_R_START_CMD "jstart" "2700"
    fi
}
... similar stop functions ...

case "${ARG1}" in
    start )
        start 
    ;;
    stop )
        stop 
    ;;
    status )
        status 
    ;;
    restart )
        stop  
        start  
    ;;
    * )
        echo "Usage: ${PGM_PATH} {start|stop|status|restart}" 
        do_exit
    ;;
esac;
  • Can you narrow it down a bit and include a `set -x` debug log? – that other guy Jul 04 '18 at 21:52
  • Why are you even using `eval` here? Also, the quoting on that line looks weird; depending on what you intended, you're either trying to nest double-quotes (which doesn't work) or leave variable references outside double-quotes (almost always a bad idea, and probably what's causing your trouble). – Gordon Davisson Jul 04 '18 at 23:05
  • 1
    I'm voting to close this question as off-topic because your question is better suited to [Server Fault](https://serverfault.com/tour). This site is for programming related questions. – Cyrus Jul 05 '18 at 04:48
  • @Cyrus : looks clearly like programming related, hence the code. – user2215655 Jul 05 '18 at 05:55
  • @Gordon Davisson, I'm using eval to execute a command built dynamically from a string. Better alternatives welcome. I'm fairly new to writing bash scripts. And the script does work when executed directly. – user2215655 Jul 05 '18 at 05:56
  • 1
    @user2215655 `eval` is almost always the wrong way to do this -- it makes shell quoting even more confusing than it normally is, blurs the line between code and data, and is generally a good way to get really weird bugs. And if you're using `csh -c`, it's already going through what amounts to one level of `eval`, so adding a second is pretty much suicidal. I'd ask another question about how to construct the command in a reliable way. – Gordon Davisson Jul 05 '18 at 06:12
  • See [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050) for an in-depth discussion of the preferable alternatives to storing commands in strings. ([BashFAQ #48](http://mywiki.wooledge.org/BashFAQ/048) discusses why `eval` is so thoroughly frowned on). – Charles Duffy Jul 06 '18 at 03:07
  • BTW, consider running your script through http://shellcheck.net/ and fixing what it finds -- and maybe declaring your variables `local` so they're function-scoped without any need for manual `unset` operations. (And as an aside, see http://wiki.bash-hackers.org/scripting/obsolete re: function-declaration syntax; `function foo() {` combines the POSIX sh syntax `foo() {` and the ksh syntax `function foo {` in a manner that eliminates compatibility with either of those predecessors). – Charles Duffy Jul 06 '18 at 03:08
  • BTW, with respect to asking questions that include code -- see the [mcve] definition in our help center. Code segments should be the *shortest possible thing* that someone else can run to reproduce a problem or test their proposed fix, with all unessential parts removed. – Charles Duffy Jul 06 '18 at 03:14

2 Answers2

0

If I read your code correctly, you use eval to create a log entry. In that case replace eval witch echo “...” and remove all but the opening and closing quotes.

  • Using `echo` to log commands loses essential details -- you can't tell the difference between `echo ./myprogram "one argument"` and `echo ./myprogram "one" "argument"`, despite these being entirely different commands. If one wants to do manual logging, much more reliable to do something like `logcmd() { (( $# )) || return 0; printf '%q ' "$@"; echo; }`, and then `logcmd ./myprogram "one argument"`, which will properly reflect the quotes. Or, even better, use `set -x`. – Charles Duffy Jul 06 '18 at 03:11
0

Issue was related due to the password containing a '#' sign. It needs to be escaped by putting a '\' in front of the '#' sign.