You were very close to the solution. Anaconda (the installer) is written in Python, so I went digging into the code.
Ultimately, it executes the script like this:
rc = iutil.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)],
stdin = messages, stdout = messages, stderr = messages,
root = scriptRoot)
A bit more digging and you can find iutil.execWithRedirect defined in 'iutil.py'. This function ultimately uses subprocess.Popen (a Python built in) to execute the command. It also tries very hard to get the contents of STDOUT and STDERR from the %pre script.
The code looks like this:
#prepare tee proceses
proc_std = tee(pstdout, stdout, program_log.info, command)
proc_err = tee(perrout, stderr, program_log.error, command)
#start monitoring the outputs
proc_std.start()
proc_err.start()
proc = subprocess.Popen([command] + argv, stdin=stdin,
stdout=pstdin,
stderr=perrin,
preexec_fn=chroot, cwd=root,
env=env)
proc.wait()
ret = proc.returncode
#close the input ends of pipes so we get EOF in the tee processes
os.close(pstdin)
os.close(perrin)
#wait for the output to be written and destroy them
proc_std.join()
del proc_std
proc_err.join()
del proc_err
So, with what you have, you get past the proc.wait() and os.close calls by forking into the background.
proc_std and proc_err are threads that repeatedly call readline on STDOUT and STDERR. They keep reading until EOF is encountered. Since your script inherits the STDOUT and STDERR socket from the %pre script, they will never encounter EOF. Ananconda then hangs waiting for the thread reading STDOUT to exit (on the 'proc_std.join()') line, which never happens.
It's a very confusing issue, but ultimately a very simple fix. Instead of:
/bin/sh /tmp/rpm_watcher.sh &
use
/bin/sh /tmp/rpm_watcher.sh > /dev/null 2>&1 < /dev/null &
This ensures your script doesn't inherit STDOUT and STDERR, so Anaconda doesn't hang and the install can continue.
It's a little hard to diagnose, as you don't give source for myproc
, but I suspect that your problem has something to do with "controlling TTY". I wrote a small shell script that just calls sleep 100
. I ran it under nohup
:
$ nohup ./sleeper > sleeper.out &
[1] 25305
-bash-3.2$ jobs
[1]+ Running nohup ./sleeper > sleeper.out &
-bash-3.2$ ps -l -p 25305
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 429624 25305 18252 0 77 0 - 15961 wait pts/0 00:00:00 sleeper
If you look at the ps
output, you see a column named "TTY". At least some versions of nohup
(the one I used above is from GNU coreutils, version 5.97, so relatively old). When I exited the bash shell from which I started sleeper
, the TTY column changed to '?', meaning that sleeper
didn't have one.
If myproc
doesn't deliberately detach itself from it's controlling TTY, it's still possible to get things like a SIGPIPE signal if it tries to write to stdout. It seems to me other things are possible, but I can't recall or google anything up.
If you can find or compile "daemonize", you might want to try it. If myproc
is compiled, you could modify the source to call the daemon(3)
library function.
Best Answer
This is not possible.
Well, it is if you are prepared to muck around with a debugger, and poke the internals of the process running your shell program. So more specifically: this is not possible in a simple straightforward manner at the level of shell programming.
This is because
disown
affects a list of "jobs" that the shell program maintains in the memory space of each individual shell process.Shells (job control ones, that is) remember the child processes that they forked in their internal "job tables", until they are instructed to forget about them by
disown
or the child processes terminate and the shell haswait()
ed for them and reported the termination of the "job".disown
does not affect the child process state in any way. It affects what the shell does.Because it forgets about the
disown
ed process …wait()
informs it about the termination of the child;exit
/logout
; andShells do not share these lists, and they are not easily accessible (sans, as mentioned, firing up a debugger and attaching it) from other processes. There is no IPC mechanism or command-line tool for accessing them except for the built-in
disown
command run within the relevant shell process itself. (This is why it is a built-in command.)This is why you cannot even
disown
jobs from a second shell even within the same login session.disown
is entirely a per-shell per-shell-process thing.Furthermore …
Actually, that is not what you've been doing.
The notion of foreground and background are relative to the controlling terminal of the session. Specifically, there is one process group, known to the controlling terminal, that is the foreground process group. Stopping and continuing processes does not by itself switch processes between foreground and background. One needs to update the controlling terminal's foreground process group as well. A foreground process is only in the foreground by dint of being a member of that foreground process group. All other process groups in that session, and thus processes in those process groups, are in the background.
Ironically, you haven't been doing this from another shell. What you've been doing is triggering the original shell process to take action. It sees the main process of the foreground process group stop, and it adjusts the terminal's foreground process group (back to its own process group) in response.
The right signal is
SIGTSTP
, by the way.Further reading