LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Help needed to understand a bit of shell script (http://www.linuxquestions.org/questions/programming-9/help-needed-to-understand-a-bit-of-shell-script-618294/)

yogeshm02 02-03-2008 01:41 AM

Help needed to understand a bit of shell script
 
Hi

Can someone explain the following piece of code from a small shell script (in particular, the one after $): -
Code:

start_daemon() { return /sbin/start_daemon ${1+"$@"}; }
Regards

gnashley 02-03-2008 02:32 AM

The variable $@ contains all the command line arguments passed to the program or function.

yogeshm02 02-03-2008 02:36 AM

Quote:

Originally Posted by gnashley (Post 3044272)
The variable $@ contains all the command line arguments passed to the program or function.

Thanks, but what does ${1+"$@"} as a whole do?

colucix 02-03-2008 03:29 AM

I have not truly clear the meaning of this particular line of code, but the syntax is
Code:

${parameter+alternative_value}
which means: if parameter is set, use alternative value, else use null string. In this case if argument number 1 is set, use all the argument list. But - I repeat - I cannot figure out what it means in this context.

/bin/bash 02-03-2008 05:00 AM

Code:

start_daemon() { return /sbin/start_daemon ${1+"$@"}; }
This function is common in /etc/init.d/functions script.
The start_daemon function sometimes called daemon or startproc is responsible for starting the daemons, in this case it uses the program /sbin/start_daemon. It is passing the command line arguements ${1+"$@"} to /sbin/start_daemon. So you would pass the name of the daemon to the function, this becomes $1 and as was mentioned by gnashley $@ is the command line arguements passed to the script or function.

Example:So if you call the function like this
start_daemon
it will not work, but if you call it like this:
start_daemon cupsd --nice=0 --log=on
then this should work, you need to have at least 1 argv for it to work.

Normally return is used to pass error no's back from a function.

colucix 02-03-2008 06:20 AM

Thanks, but I still cannot figure out why simply "$@" couldn't be used in place of ${1+"$@"}.

gnashley 02-03-2008 07:43 AM

It seems to simply run /sbin/start_daemon with whatever arguments are passed. If at least one argument is given then all the arguments are passed. If no argument is given then none are passed. This would have done the same thing:
return /sbin/start_daemon "$@"

yogeshm02 02-03-2008 09:44 AM

Thanks.

Actually I'm trying to write an init script (derived from skeleton script provided by openSUSE 10.3). I'm also attaching the script.
This is the error I get while starting the service: -
Code:

Starting eSpyD /etc/init.d/eSpyD-service: line 70: return: /sbin/start_daemon: numeric argument required
failed

...and this is line 70:
Code:

start_daemon() { return /sbin/start_daemon ${1+"$@"}; }
...which is probably invoked from here:
Code:

        start_daemon $ESPYD_BIN
Oops, attaching a file seems not possible, so here is complete script (I'm not removing comments): -
Code:

#!/bin/bash
#
#    Implemented from template LSB system startup script for example
#    service/daemon FOO
#    Copyright (C) 1995--2005  Kurt Garloff, SUSE / Novell Inc.
#         
#    This library is free software; you can redistribute it and/or modify it
#    under the terms of the GNU Lesser General Public License as published by
#    the Free Software Foundation; either version 2.1 of the License, or (at
#    your option) any later version.
#                             
#    This library 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
#    Lesser General Public License for more details.
#     
#    You should have received a copy of the GNU Lesser General Public
#    License along with this library; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
#    USA.
#
# /etc/init.d/eSpyD
#
# Note: This template uses functions rc_XXX defined in /etc/rc.status on
# UnitedLinux/SUSE/Novell based Linux distributions. However, it will work
# on other distributions as well, by using the LSB (Linux Standard Base)
# or RH functions or by open coding the needed functions.
# Read http://www.tldp.org/HOWTO/HighQuality-Apps-HOWTO/ if you prefer not
# to use this template.
#
# chkconfig: 345 99 00
# description: eSpyD daemon which logs network usage for eSpy
#
### BEGIN INIT INFO
# Provides:          eSpyD
# Required-Start:   
# Should-Start:
# Required-Stop:   
# Should-Stop:
# Default-Start:    3 4 5
# Default-Stop:      0 1 2 6
# Short-Description: eSpyD daemon which logs network usage for eSpy
# Description:      Start eSpyD to allow logging of network usage which
#        can be monitored with eSpy.
### END INIT INFO
#

ESPYD_BIN=/usr/local/sbin/eSpyD
test -x $ESPYD_BIN || { echo "$ESPYD_BIN not installed";
        if [ "$1" = "stop" ]; then exit 0;
        else exit 5; fi; }

# Shell functions sourced from /etc/rc.status:
#      rc_check        check and set local and overall rc status
#      rc_status        check and set local and overall rc status
#      rc_status -v    be verbose in local rc status and clear it afterwards
#      rc_status -v -r  ditto and clear both the local and overall rc status
#      rc_status -s    display "skipped" and exit with status 3
#      rc_status -u    display "unused" and exit with status 3
#      rc_failed        set local and overall rc status to failed
#      rc_failed <num>  set local and overall rc status to <num>
#      rc_reset        clear both the local and overall rc status
#      rc_exit          exit appropriate to overall rc status
#      rc_active        checks whether a service is activated by symlinks

# Use the SUSE rc_ init script functions;
# emulate them on LSB, RH and other systems

# Default: Assume sysvinit binaries exist
start_daemon() { return /sbin/start_daemon ${1+"$@"}; }
killproc()    { return /sbin/killproc    ${1+"$@"}; }
pidofproc()    { return /sbin/pidofproc    ${1+"$@"}; }
checkproc()    { return /sbin/checkproc    ${1+"$@"}; }
if test -e /etc/rc.status; then
    # SUSE rc script library
    . /etc/rc.status
else
    export LC_ALL=POSIX
    _cmd=$1
    declare -a _SMSG
    if test "${_cmd}" = "status"; then
        _SMSG=(running dead dead unused unknown reserved)
        _RC_UNUSED=3
    else
        _SMSG=(done failed failed missed failed skipped unused failed failed reserved)
        _RC_UNUSED=6
    fi
    if test -e /lib/lsb/init-functions; then
        # LSB   
            . /lib/lsb/init-functions
        echo_rc()
        {
            if test ${_RC_RV} = 0; then
                log_success_msg "  [${_SMSG[${_RC_RV}]}] "
            else
                log_failure_msg "  [${_SMSG[${_RC_RV}]}] "
            fi
        }
        # TODO: Add checking for lockfiles
        checkproc() { return pidofproc ${1+"$@"} >/dev/null 2>&1; }
    elif test -e /etc/init.d/functions; then
        # RHAT
        . /etc/init.d/functions
        echo_rc()
        {
            #echo -n "  [${_SMSG[${_RC_RV}]}] "
            if test ${_RC_RV} = 0; then
                success "  [${_SMSG[${_RC_RV}]}] "
            else
                failure "  [${_SMSG[${_RC_RV}]}] "
            fi
        }
        checkproc() { return status ${1+"$@"}; }
        start_daemon() { return daemon ${1+"$@"}; }
    else
        # emulate it
        echo_rc() { echo "  [${_SMSG[${_RC_RV}]}] "; }
    fi
    rc_reset() { _RC_RV=0; }
    rc_failed()
    {
        if test -z "$1"; then
            _RC_RV=1;
        elif test "$1" != "0"; then
            _RC_RV=$1;
            fi
        return ${_RC_RV}
    }
    rc_check()
    {
        return rc_failed $?
    }       
    rc_status()
    {
        rc_failed $?
        if test "$1" = "-r"; then _RC_RV=0; shift; fi
        if test "$1" = "-s"; then rc_failed 5; echo_rc; rc_failed 3; shift; fi
        if test "$1" = "-u"; then rc_failed ${_RC_UNUSED}; echo_rc; rc_failed 3; shift; fi
        if test "$1" = "-v"; then echo_rc; shift; fi
        if test "$1" = "-r"; then _RC_RV=0; shift; fi
        return ${_RC_RV}
    }
    rc_exit() { exit ${_RC_RV}; }
    rc_active()
    {
        if test -z "$RUNLEVEL"; then read RUNLEVEL REST < <(/sbin/runlevel); fi
        if test -e /etc/init.d/S[0-9][0-9]${1}; then return 0; fi
        return 1
    }
fi

# Reset status of this service
rc_reset

# Return values acc. to LSB for all commands but status:
# 0          - success
# 1      - generic or unspecified error
# 2      - invalid or excess argument(s)
# 3      - unimplemented feature (e.g. "reload")
# 4      - user had insufficient privileges
# 5      - program is not installed
# 6      - program is not configured
# 7      - program is not running
# 8--199  - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
#
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signaling is not supported) are
# considered a success.

case "$1" in
    start)
        echo -n "Starting eSpyD "
        ## Start daemon with startproc(8). If this fails
        ## the return value is set appropriately by startproc.
        start_daemon $ESPYD_BIN

        # Remember status and be verbose
        rc_status -v
        ;;
    stop)
        echo -n "Shutting down eSpyD "
        ## Stop daemon with killproc(8) and if this fails
        ## killproc sets the return value according to LSB.

        killproc -TERM $ESPYD_BIN

        # Remember status and be verbose
        rc_status -v
        ;;
    try-restart|condrestart)
        ## Do a restart only if the service was active before.
        ## Note: try-restart is now part of LSB (as of 1.9).
        ## RH has a similar command named condrestart.
        if test "$1" = "condrestart"; then
                echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
        fi
        $0 status
        if test $? = 0; then
                $0 restart
        else
                rc_reset        # Not running is not a failure.
        fi
        # Remember status and be quiet
        rc_status
        ;;
    restart)
        ## Stop the service and regardless of whether it was
        ## running or not, start it again.
        $0 stop
        $0 start

        # Remember status and be quiet
        rc_status
        ;;
    force-reload)
        ## Signal the daemon to reload its config. Most daemons
        ## do this on signal 1 (SIGHUP).
        ## If it does not support it, restart the service if it
        ## is running.

        echo -n "Reload service eSpyD "
        $0 try-restart
        rc_status -v
        ;;
    reload)
        ## Like force-reload, but if daemon does not support
        ## signaling, do nothing (!)

        echo -n "Reload service eSpyD "
        rc_failed 3
        rc_status -v
        ;;
    status)
        echo -n "Checking for service eSpyD "
        ## Check status with checkproc(8), if process is running
        ## checkproc will return with exit status 0.

        # Return value is slightly different for the status command:
        # 0 - service up and running
        # 1 - service dead, but /var/run/  pid  file exists
        # 2 - service dead, but /var/lock/ lock file exists
        # 3 - service not running (unused)
        # 4 - service status unknown :-(
        # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
       
        # NOTE: checkproc returns LSB compliant status values.
        checkproc $FOO_BIN
        # NOTE: rc_status knows that we called this init script with
        # "status" option and adapts its messages accordingly.
        rc_status -v
        ;;
    probe)
        # Don't do anything

        ;;
    *)
        echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
        exit 1
        ;;
esac
rc_exit

Do you have any idea about the reason for this error?

Thanks again,

colucix 02-03-2008 01:05 PM

Code:

# Default: Assume sysvinit binaries exist
start_daemon() { return /sbin/start_daemon ${1+"$@"}; }
killproc()    { return /sbin/killproc    ${1+"$@"}; }
pidofproc()    { return /sbin/pidofproc    ${1+"$@"}; }
checkproc()    { return /sbin/checkproc    ${1+"$@"}; }

This sounds like a bug to me. The return statement accepts a numeric argument not a command. You can try to simply remove return from the statements above: in this case the exit status of the last (and unique) command executed inside the function is returned.

Anyway, there is another skeleton in OpenSuSE 10.3 without this sysV init compatibility part: it is /etc/init.d/skeleton, instead of /etc/init.d/skeleton.compat. Have you tried that?


All times are GMT -5. The time now is 11:04 PM.