Bash Signals – Control Which Process Gets Cancelled by Ctrl+C

bashsignals

I have a live CD that boots into Linux and runs a small Bash script. The script searches for and runs a second program (which is usually a compiled C++ binary).

You're supposed to be able to abort the second program by pressing Ctrl+C. What should happen is that the second program halts, and the Bash script continues running cleanup. What actually happens is that both the main application and the Bash script terminate. Which is a problem.

So I used the trap builtin to tell Bash to ignore SIGINT. And now Ctrl+C terminates the C++ application, but Bash continues its run. Great.

Oh yeah… Sometimes the "second application" is another Bash script. And in that case, Ctrl+C now does nothing whatsoever.

Clearly my understanding of how this stuff works is wrong… How do I control which process gets SIGINT when the user presses Ctrl+C? I want to direct this signal to just one specific process.

Best Answer

After many, many hours of searching the face of the Internet, I have found the answer.

  1. Linux has the notion of a process group.

  2. The TTY driver has a notion of Foreground Process Group.

  3. When you press Ctrl+C, the TTY sends SIGINT to every process in the Foreground Process Group. (See also this blog entry.)

This is why both the compiled binary and the script that launches it both get clobbered. In fact I only want the main application to receive this signal, not the startup scripts.

The solution is now obvious: We need to put the application in a new process group, and make it the Foreground Process Group for this TTY. Apparently the command to do that is

setsid -c <applcation>

And that is all. Now when the user presses Ctrl+C, SIGINT will be sent to the application (and any children it may have) and nobody else. Which is what I wanted.

  • setsid by itself puts the application in a new process group (indeed, an entire new "session", which is apparently a group of process groups).

  • Adding the -c flag makes this new process group become the "foreground" process group for the current TTY. (I.e., it gets SIGINT when you press Ctrl+C)

I've seen a lot of conflicting information about when Bash does or does not run processes in a new process group. (In particular, it appears to be different for "interactive" and "non-interactive" shells.) I've seen suggestions that you can maybe get this to work with clever pipe trickery... I don't know. But the approach above seems to work for me.

Related Question