Children of scripts don't stop

Asked by Quentin Stafford-Fraser on 2007-04-02

I may well be doing something foolish here. Apologies if so. Here's an example 'foo' script:

  start on rc2/stop
  stop on shutdown

  script
    /tmp/foo
  end script
  respawn

Here, /tmp/foo is a shell script just writes some output once a second. If I kill it, it restarts nicely.

If I use 'stop' on the script, however, it kills the shell that is running /tmp/foo, but not /tmp/foo itself. That keeps running. ie, upstart is creating two processes:

  6958 /bin/sh -e -c /tmp/fooer
  6959 /bin/sh /tmp/fooer

And only the first is killed by 'stop'. I would have expected the child to die at the same time, in the absence of nohups etc, but I may know less about shells than I thought I did.

I can get around it here by using

  script
    exec /tmp/foo
  end script

so the parent shell is replaced. Is that the intended behaviour?

Question information

Language:
English Edit question
Status:
Solved
For:
upstart Edit question
Assignee:
No assignee Edit question
Solved by:
Quentin Stafford-Fraser
Solved:
2007-04-02
Last query:
2007-04-02
Last reply:
2007-04-02

This is ordinary shell behaviour, since upstart spawns an ordinary shell to handle the process if you use "script"..."end process", and upstart only supervises the actual script or binary being executed directly, and not any children that they might spawn.

Since you're only running a single binary, just use exec directly, e.g.

  start on stopped rc2
  stop on shutdown

  exec /tmp/foo
  respawn

Thanks Scott -

Actually, this was just a simple example. In my case I'm sourcing a couple of configuration files and setting a couple of variables before the actual python program is launched - hence the use of the script.

The thing that makes my situation somewhat more complicated is that I want to run the program as a different user, which I do with

  su - $USER -c <command>

So upstart spawns a shell, which spawns su, which spawns a shell to run the -c command, which runs the command itself, and in our case this command runs sub-commands.
I was hoping for a tidy way to kill everything off with a 'stop' ! Each layer will tidily kill the layer below it, except for the top one if started by 'script'.

I guess there are various ways to solve this:
* do something to kill lower-layers off in a post-stop script, or
* modify the program itself to be able to setuid so I can exec it, or
* modify it to record its PID in a file so I can kill it in the old init.d way
* exec a script which does the configuration setup and then exec's the program

I'll use one of these unless you have any better suggestions, or any plans to allow things to be started as different uids.

Many thanks!

For this, just make the last thing in your script be called with "exec"; that way it has the process id that upstart is supervising, and thus will be stopped properly