Closing Terminal window does not kill script run with sudo

bashsudoterminal

X-posting from unix.SE on recommendation.

I have a bash script called testing saved within /usr/local/bin.

In one Terminal window in macOS I run sudo testing. In a second terminal window, I generate a list of processes:

ps -axo tty,pid,ppid,args | { head -1; grep "bash\|testing" | grep -v grep; }

Which returns as expected:

TTY        PID  PPID ARGS
ttys000  73674 73673 -bash                              # login shell used to run sudo
ttys000  73701 73674 sudo testing                       # sudo process
ttys000  73702 73701 /bin/bash /usr/local/bin/testing   # "testing" bash script being run by sudo
ttys001   3714  3713 -bash                              # second login shell used to generate this process list

However, after quitting the first Terminal window (while testing is still running within it), the process list looks like this:

TTY        PID  PPID ARGS
??       73701     1 sudo testing
??       73702 73701 /bin/bash /usr/local/bin/testing
ttys001   3714  3713 -bash

As expected, the first login shell has been terminated and the second login shell is still running. But the sudo process and its forked (now-orphaned) child, the testing script, are still running!

I suspect this is because the user, not root, is the one closing the Terminal window, and as such does not have the necessary permissions to affect root processes. Is this correct? I feel like I'm missing something basic here. Is there some way to allow the root processes to be terminated by closing the Terminal window?

Best Answer

You are talking about orphan processes. As you will see, your question has little to do with sudo. Orphans are assigned to process 1. This process 1 is called init and is a daemon process that continues running until the system is shut down. Here are two simple examples where orphans are created. The macOS is High Sierra which uses bash as the default shell.

If you choose to repeat the examples, you will have to replace the process ids with the ones you get.

When the parent windows terminates, a hang up signal (SIGHUP) is sent to the child processes. Normally, this causes each child processes to terminate. However, if a child chooses not to terminate or is never sent a hangup signal (SIGHUP), then the child can become an orphan.

Example 1

Open a new Terminal window and enter the command shopt -s huponexit. This command is necessary because bash is a login shell. Output shown below.

Last login: Thu Mar 12 17:02:31 on ttys008
Marlin:~ davidanderson$ shopt -s huponexit
Marlin:~ davidanderson$

Enter the command { trap '' hup; sleep 60000; } &, as shown below.

Marlin:~ davidanderson$ { trap '' hup; sleep 60000; } &
[1] 8993
Marlin:~ davidanderson$

Here a new process 8993 is created as job 1. The trap '' hup command causes the hang up signal (SIGHUP) to be ignored. Next, open a another Terminal window and enter the command ps -axo tty,pid,ppid,args 8993, as shown below.

Last login: Thu Mar 12 17:09:12 on ttys008
Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 8993
TTY        PID  PPID ARGS
ttys008   8993  8972 -bash
Marlin:~ davidanderson$ 

This shows the first window was assigned ttys008 and has a process id of 8972. Next, the first window is closed. In the popup window, Terminate is selected. A hang up signal (SIGHUP) is sent to process 8972, which is ignored. Process 8972 is now orphaned and will be assigned to process 1. Repeating the ps -axo tty,pid,ppid,args 8993 command in the second window will show this. See below.

Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 8993
TTY        PID  PPID ARGS
??        8993     1 -bash
Marlin:~ davidanderson$

Finally, the commands shown below are entered to send a terminal signal (SIGTERM) to process 8993 and show that the process has terminated.

Marlin:~ davidanderson$ kill 8993
Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 8993
TTY        PID  PPID ARGS
Marlin:~ davidanderson$

Example 2

This is basically the same as example 1, except instead of having the process ignore the hangup signal (SIGHUP), the disown %1 command is used to prevent a hangup signal (SIGHUP) from being sent to the process. Open a new Terminal window and enter the command shopt -s huponexit. This command is necessary because bash is a login shell. Output shown below.

Last login: Thu Mar 12 17:02:31 on ttys008
Marlin:~ davidanderson$ shopt -s huponexit
Marlin:~ davidanderson$

Next, enter sleep 60000 & followed by disown %1. The %1 parameter represents job 1. The results are shown below.

Last login: Thu Mar 12 17:14:54 on ttys010
Marlin:~ davidanderson$ sleep 60000 &
[1] 9139
Marlin:~ davidanderson$ disown %1
Marlin:~ davidanderson$

In the second window, enter ps -axo tty,pid,ppid,args 9139. The results are shown below.

Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 9139
TTY        PID  PPID ARGS
ttys008   9139  9130 sleep 60000
Marlin:~ davidanderson$

After closing the third window, enter ps -axo tty,pid,ppid,args 9139 in the second window. The results are shown below. Another orphan has been created.

Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 9139
TTY        PID  PPID ARGS
??        9139     1 sleep 60000
Marlin:~ davidanderson$ 

Finally, enter kill 9139 and ps -axo tty,pid,ppid,args 9139, as shown below.

Marlin:~ davidanderson$ kill 9139
Marlin:~ davidanderson$ ps -axo tty,pid,ppid,args 9139
TTY        PID  PPID ARGS
Marlin:~ davidanderson$ 

References

Orphan process
Zombie process
init
Daemon