3

On a Linux system, the bash builtin command disown can be used to remove jobs from the current session. How does bash implement this feature? Is setsid() used here, and if so, how does bash trigger the child process to invoke setsid()? Does it use signal?

1
  • Did you already look at the source code but can't understand it? Commented Sep 19, 2019 at 13:18

1 Answer 1

6

No. disown does not remove a job from the current session [1], does not detach it from the terminal, and does not affect which signals the kernel will send it when the session leader exits or when the controlling terminal is torn down.

disown only works on bash's own job table, only changes bash's idea of which jobs it's in control of, and only affects bash's own behavior, namely which jobs it will resend a SIGHUP received by the bash process. That SIGHUP resending is an extra feature of bash [2], not required by the standard and not related to the job control provided by the OS.

You can see it with a simple example, where I'm using script(1) to create a pty and an interactive shell session running in it:

$ script /dev/null -qc bash $ sh -c 'sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666' & [1] 3837 $ disown -a $ jobs # no jobs known to bash $ pgrep -as0 # show all processes from the current session 3836 bash 3837 sh -c sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666 3838 sleep 555 3841 sleep 666 $ kill -HUP $$ # seppuku the session leader Hangup hupped! 

Here the kernel sends a SIGHUP signal to the background process group (= job) because one of its processes is stopped, and disowning it will not prevent that from happening.

All processes from the sh -c '...' are part of the same job, including the "background" sleep &; shell scripts don't do job control by default.

If no members of the background process group are stopped, no SIGHUP is sent:

$ script /dev/null -qc bash $ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' & [1] 3270 $ disown -a $ kill -HUP $$ # sleep 555, 666 and sh -c are still running 

Finally, bash will send a SIGHUP to all the jobs from its table (only those started by itself and not disowned), no matter if bash is the session leader or not, or if the jobs are running, stopped, etc:

$ bash $ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' & [1] 3413 $ kill -HUP $$ Hangup hupped! Hangup 

[1] which would be impossible to do anyway; setsid() is only able to make into a new session a process which is not a process group leader, there is no way to move a whole job into a new or existing session.

[2] which is documented in the bash's manpage:

The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the signal to a particular job, it should be removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to not receive SIGHUP using disown -h.

There's is also shopt -s huponexit which cause a login bash shell to send a HUP to its jobs upon exiting (whether because of a signal or not), which again overlaps in confusing ways with the standard job control features of the OS.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.