Search code examples
linuxbashunixxterm

Why is forked child killed by (former) parent process exiting


I am trying to write a very minimalist version of the idea of "window swallowing" that can work with Xterm, or any terminal emulator that provides the -e option to run a specified program as the shell of the terminal.

I have written the following script and saved it into run.sh and I am passing that to Xterm with -e ./run.sh

run.sh:

#!/bin/sh

PROG=''
read PROG
($PROG &) && exit

The intention is that an Xterm window will open, get the program name as input from the user, launch the program and fork it, and then close itself. The issue is that Xterm closes itself immediately and the specified program never opens. My assumption is that the parent process is being killed before the child can fork itself but I'm not sure? The && exit should ensure that the parent process doesn't exit until it receives a success code from the child.

I modified the script like so and it behaves as intented:

PROG=''
read PROG
($PROG & sleep 1) && exit

Which strengthens my hypothesis. I would like to be able to remove this sleep because it makes the program very ugly leaving the original Xterm open for an extra second.

Please note that the programs I am using this with are graphical (I am actually testing it by launching another Xterm window), so they should be opening their own window when they launch. I do not expect CLI programs to take over the Xterm window as I intend for it to close obviously


Solution

  • When the controlling terminal of a process disappears, the process will receive a SIGHUP.

    If the sleep makes a difference, you're likely seeing a race between the process receiving SIGHUP and the process installing its signal handlers.

    The traditional way to make a process ignore SIGHUP is to use nohup, but it works by installing a signal handler too, so it doesn't solve the race.

    Instead, you can ignore SIGHUP synchronously in the shell, and then start your process in the background:

    #!/bin/sh
    
    PROG=''
    read PROG
    ( trap '' HUP; $PROG < /dev/null > /dev/null 2>&1 &) && exit