shell script working with --daemon

HI,
I have a shell script :
lockfile=/var/lock/subsys/$prog
start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    daemon --user=$user $exec $config &
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

Open in new window


This is basically a part of an init.d script.
I want to understand the basic construct in it like what does following do :
1)  [ -x $exec ]
2)  [ -f $config ]
3)     daemon --user=$user $exec $config &

Also in specific what is daemon command do.. looks like it just executes the given program.
Does the --user =$user means that the program is run as from user $user ?

Thanks
Rohit BajajAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Dan CraciunIT ConsultantCommented:
From http://libslack.org/daemon/manpages/daemon.1.html

daemon(1) turns other processes into daemons. There are many tasks that need to be performed to correctly set up a daemon process. This can be tedious. daemon performs these tasks for other processes.

usage: daemon [options] [--] [cmd arg...]
options:
-u, --user=user[:[group]] - Run the client as user[:group]

So daemon --user=$user $exec $config & will run $exec as a daemon under the $user user, with $config parameters.

HTH,
Dan
Rohit BajajAuthor Commented:
do i need to do something to make the daemon work.
because currently when i run this script. nothing happens.
whereas if i remove daemon and just use the plain exec command my server startsup

although i am including the functions file under init.d
but my system does not have the daemon command
Dan CraciunIT ConsultantCommented:
Wow, that's an echo. 17 identical posts...

If nothing happens, it's because you don't have daemon installed. It's not installed by default and I have not seen init scripts like that for some years.

Install the package with yum/apt-get/your distro's package manager and it will work.
Big Business Goals? Which KPIs Will Help You

The most successful MSPs rely on metrics – known as key performance indicators (KPIs) – for making informed decisions that help their businesses thrive, rather than just survive. This eBook provides an overview of the most important KPIs used by top MSPs.

simon3270Commented:
For questions 1 and 2, the "[ some_test ] || some command" structure is a shorthand for
    if [ some_test ]; then
        : do nothing
    else
        some command
    fi

The "[ some_test]" part runs the specified test (here "-x $exec" to test whether the command named in the $exec variable is executable, and "-f $config" to check that the file named in the $config variable exists), and sets the return code to 0 if the test was successful, and 1 if not.  The "||" bit then looks at that return code, and if it is 0, stops processing.  If it is 1, it then runs the command after the "||".

The intention is to run commands until one of them succeeds.  You can in fact have a chain of these, as
    [ -x $exec ] || [ -x $exec2 ] || [ -f /tmp/noexec ] || exit 5
This will exit with return code 5 if neither of the programs named $exec or $exec2 variables are executable, and the /tmp/noexec file does not exist.  If any of those test succeeds, processing stops at that point and no further tests, and in particular not the exit 5, take place.

There is a similar chain which runs until one of the tests fails:
    [ -x /bintest ] && [-x $exec2 ] && [ -f $HOME ] && echo all OK

This sort of sequence is often abused as in
    [ some_test ] && cmd1 || cmd2
so as to perform the test, and run cmd1 if the test succeeds, and cmd2 if it fails.  This only works if the cmd1 command returns a 0 exit code - if it returns non-zero, cmd2 will be executed too.  Unless you are absolutely sure that cmd1 will always return success, use
    if [ some_test ]; then
        cmd1
    else
        cmd2
    fi

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Rohit BajajAuthor Commented:
Hi,
Thanks a lot...
Also whats the lockfile for  in the lines :
lockfile=/var/lock/subsys/$prog
 and why we are performing touch $lockfile.
Is this lockfile automatically created ?
the retval=$? I guess its assigning the return value of the last command which in this case is a daemon.
Please correct me if i am wrong.
simon3270Commented:
The "prog" variable is presumably set higher up in the script to the name of the program, so the name of the file in /var/lock/subsys is specific to this program.  I don't believe that /var/lock/subsys part has any specific meaning - it's just a common place to put lock files (as /var/run is a common place to put process ID files).

"retval=$?" does set the retval variable to the return code of the last command.  It then tests that value, and if the value was 0, it creates the lock file (the "touch $lockfile", which creates an empty file if it doesn't exist, and updates the "last modified" time of the file if it does exist).

One thing about retval here - because the daemon program is run in the background (the "&" at the end of the command), $? is the return code from trying to execute the "daemon" program itself, and not anything which the daemon program does.  Even if the daemon program itself doesn't exist, the return code may well be 0.

Is $lockfile used in another part of this script?  In this sort of script, a lock file is often used to avoid the program running twice, so you might see:
  if [ -f $lockfile ]; then
    echo Program is already running
    exit 1
  else
    daemon -user ......
  fi

So, the first time you start the daemon, the lock file is created.  if you try to start it again, the lock file will already be there, so the script will report that it is already started.

 I would guess that the lock file  is not automatically created and deleted, so you would have "touch $lockfile" in the start code, and "rm $lockfile" in the stop code.  This, combined with the fact that the lockfile will be created whether or not the daemon actually runs, makes $lockfile a fairly poor control - my check code above will fail if the daemon crashes - it won't have removed the lock file, so the code will think that the daemon is still running and won't start it.  Also, someone could have manually deleted the lock file while the daemon is running, so if you ran "start" again, the above check code would start a second copy of the daemon.
Rohit BajajAuthor Commented:
HI,
Thanks that was really helpful explanation.
The lockfile is not used anywhere else apart from when we execute the stop() . It removes the lockfile.
So i guess in the script it is pretty much useless currently to create a lockfile and not do anything with it.

As you said even using lockfile is a poor way to guarantee that the process doesnot start twice.
If i remove the & from daemon then the retval will be of exec or daemon still ?
what other way i can use for instead of lockfile to guarantee that script not executing twice ?
simon3270Commented:
Removing the "&" is not really an option, as far as I can tell.  The "daemon" program runs the specified command in the backgroup, but "daemon" itself continues to run so that it can monitor the program it has started, and restart it if it fails.  If you remove the "&", the script will just stop at the daemon line and never return to the user.

There is a better way - provide a "--name xxx" option to "daemon" - this will force daemon to create a Process ID file, containing the PID of the command it has started.  If you then call "daemon" again to start the same named process, it will note that the name.pid file exists and that the process is still running, so will stop you running it twice.
simon3270Commented:
By the way, how does  "stop" find the process to stop?  If you supply a "--name" option as above, you can stop the process by running this, where xxxx is the name you used when you started the process
    daemon --stop --name xxxx
Rohit BajajAuthor Commented:
HI,
Here is the complete init script which i am referring to build my own init script. The part of which i posted above :

#!/bin/sh
#
# uecho Bring uecho up or down
#
# chkconfig:   2345 20 80
# description: uecho is a UDP echo service

### BEGIN INIT INFO
# Default-Start:       2 3 4 5
# Default-Stop:        0 1 6
# Short-Description:   Bring uecho up or down
# Description:         uecho is a UDP echo service
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

exec="@bindir@/uecho"
prog="uecho"
config="/etc/uecho.conf"
user="uecho"

lockfile=/var/lock/subsys/$prog

start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    daemon --user=$user $exec $config &
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    # run checks to determine if the service is running or use generic status
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

Open in new window



I used the same code to start and stop my process. But i found that the process didnt get killed although the retval was having 0 value. dont know what killproc command does.
As an alternative i just cd /opt/flock-snippets and ran mvn jetty:stop command and that did stop the process
But i am wondering if thats correct way of stopping it because i am starting my process using daemon but not using any daemon to stop it.
Rohit BajajAuthor Commented:
HI,
I tried putting the following line adding the name attribute
daemon --user=$user  --name=$prog $exec &
tried with --name $prog
But the process doesnt start
It shows : Usage: daemon [+/-nicelevel] {program}
simon3270Commented:
I assume that the "killproc" call fails because it's not actually starting a process called "uecho".  "killproc mvn" woudl do it, but that woudl kill all "mvn" processes, not just the one you are starting.

Does "man daemon" show the --start, --stop and --name options?
Rohit BajajAuthor Commented:
Hi,
No man daemon is not having --start etc... things i guess in the script its using daemon from functions file which we are sourcing
simon3270Commented:
Ah, that makes a difference.

If your "mvn jetty:stop" works, then that is as good a way of stopping as any.  I assume that if the mvn call hasn't actually started, that just returns an error, which is good.
Rohit BajajAuthor Commented:
Hi,
As you mentioned The "daemon" program runs the specified command in the backgroup, but "daemon" itself continues to run so that it can monitor the program it has started, and restart it if it fails.  If you remove the "&", the script will just stop at the daemon line and never return to the user.
I understand this but just want to know the real purpose of daemon command. If it was just to make a background process then i could have just type & behind the process.
Or is it just a useful utility so that i can specify --user etc other parameters ?
simon3270Commented:
The "daemon" program I have used does some essential work before starting the background program it makes it easy to set the user, define a file to hold the new process's PID, set the root directory, and then does work to protect the started program from the calling program. For example, if you just add an & to the end of the command, when the calling script ends, a HUP signal may be sent to that program. Depending on the program,  this may cause the program to stop.

I've recently been through the same process (adding a start/stop script to a new system). My approach was like yoirs - to look through the system's own scripts to find one which matched the requirements of my code, understand what all of the steps in that script did, then modify the script to run code. I assumed that the system writers had worked out the best way to use the abilities of the rest of the system, so I didn't change any more of the code than I had to.!
Duncan RoeSoftware DeveloperCommented:
I can only find daemonize as a package, not daemon. daemonize does what you want.
simon3270Commented:
One things occurred to me - does the "mvn jetty:run" stop soon after you run it, leavnig the jetty process running in the background?

If so, you don't need the "daemon" or "&" at all.  The start script could be (assuming that $exec and $config run the "mvn jetty:run" command):
su - $user -c "$exec $config"
retval=$?

Open in new window


The for the stop, you use
su - $user -c "mvn jetty:stop"
retval=$?

Open in new window

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Linux

From novice to tech pro — start learning today.