views:

75

answers:

2

NOTE: I thought I was using bash, but /bin/sh is linked to /bin/dash, which has this weird exec problem.

I have a simple bash shell script on Linux which is used to launch a server process (which I did not write or control) and would like to have the bash shell script output the launched process's PID to a pidfile.

The problem is that bash-exec command does not replace its own process with the launched server process!

So:

echo $$ | cat > /var/run/launched-server.pid

This does not work because the pid in the file will be that of bash not the server process. And if the server process exits bash may not exit leaving the stupid launch script hanging out in the process list.

Does anyone know a way to use bash (or dash maybe?) so that:

  1. Is it possible?
  2. The launched-server server process's PID will be in my pidfile?
  3. Ensure that the bash script will die when the launched-server exists and not leave defunct shell processes hanging out in the process list?

Edit: This snippet from the bash reference manual be of use...

exec
           exec [-cl] [-a name] [command [arguments]]

If command is supplied, it replaces the shell without creating a new process. If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is what the login program does. The -c option causes command to be executed with an empty environment. If -a is supplied, the shell passes name as the zeroth argument to command. If no command is specified, redirections may be used to affect the current shell environment. If there are no redirection errors, the return status is zero; otherwise the return status is non-zero.


Edit 2: This is the script (sanitized):

#!/bin/sh

# this is where TMS expects to run its services for Daemontools
SERVICE_DIR='/var/service';

# kill stdout, stderr, stdin
exec </dev/null
exec >/dev/null
exec 2>/dev/null

logger -ip daemon.debug -- stdout, stderr, stdin redirected to /dev/null

if [ -d $SERVICE_DIR ]; then
    # sanitized...
    logger -ip daemon.debug -- services and supervisors exited
else
    logger -ip daemon.err -- $SERVICE_DIR does not exist, exiting
    exit 1;
fi

if [ -d /var/run/pid ]; then
    echo $$ | cat > /var/run/pid/launched-server.pid
    logger -ip daemon.debug -- creating launched-server pidfile
fi

# start the server process
logger -ip daemon.info -- launching server on $SERVICE_DIR
exec /usr/local/bin/launched-server

And some ps output to maybe be more clear?

me@chainsaw: ~/dev $ ps ax | grep launched-server
13896 pts/1    S+     0:00 /bin/sh ./server_boot
13905 pts/1    S+     0:00 launched-server /var/service
13938 pts/2    R+     0:00 grep --color=auto launched-server
A: 

Does your distribution include start-stop-daemon(8)? Wonderfully useful little tool, it was built specifically for starting daemons from shell scripts. (Of course, the daemons outlive the shell scripts, so it may not be a perfect match -- it depends on why you want the shell to outlive your daemon.)

Or, for something simpler:

Could your problem be solved with bash's exec command? It replaces the shell process with whatever program you ask to execute:

#!/bin/bash

echo $$ > /tmp/pidfile
exec /bin/sleep 60

$ ./show_exec.sh 
[nothing happens]

And, in another shell:

$ cat pidfile
24686
$ ps auxw | grep 24686
sarnold  24686  0.0  0.0   9728   816 pts/1    S+   04:53   0:00 /bin/sleep 60
sarnold
@sarnold One of the problems is that the script outlives the daemon, not the other way around :-) Its probably a simple problem that I'm just muddling up..
Petriborg
While your answer doesn't directly give me a solution in bash-per-say, I have to say the start-stop-daemon was spot on and is a great little piece of software. I've "solved" my problem with bash's exec by using it.
Petriborg
A: 

I now realize what the real problem was:

By using #!/bin/sh I was not invoking bash, but dash.

Dash's exec is the shell with the exec problem. If I had used #!/bin/bash from the start, it would have worked as expected.

Petriborg