How to Reattach a Disowned Process and Restore STDIN/STDOUT/STDERR Handles in Linux


2 views

When you disown a process in Linux, you're essentially detaching it from your current shell session while allowing it to continue running. This is useful when you need to disconnect from a remote server but want to keep a long-running job alive. However, this leaves the process orphaned without its original STDIN/STDOUT/STDERR handles.

The most straightforward method is using reptyr, a tool specifically designed for this purpose:

# First install reptyr
sudo apt-get install reptyr  # Debian/Ubuntu
sudo yum install reptyr      # CentOS/RHEL

# Find your process ID
ps aux | grep your_process_name

# Reattach the process
reptyr PID

For systems where reptyr isn't available or doesn't work, you can use GDB:

# Attach GDB to the process
gdb -p PID

# In GDB:
(gdb) call dup2(open("/dev/pts/X", 0), 0)
(gdb) call dup2(open("/dev/pts/X", 1), 1)
(gdb) call dup2(open("/dev/pts/X", 2), 2)
(gdb) detach
(gdb) quit

Replace X with your actual terminal number (find it with tty command).

If you originally ran the process in screen or tmux, you can try these approaches:

# For screen:
screen -r

# For tmux:
tmux attach

For daemonized processes or those that have closed their file descriptors:

  1. Check if the process supports signal-based reopening of logs (like nginx -USR1)
  2. Consider using strace to monitor file operations
  3. For critical processes, set up proper logging from the start

To avoid this situation in the future:

# Always use screen/tmux for long-running processes
screen -S session_name
./long_running_script.sh
# Then detach with Ctrl-A D

# Or use nohup with proper redirection
nohup ./script.sh > output.log 2>&1 &

We've all been there - you start a long-running process in a terminal, realize you need to disconnect, and hastily use disown to keep it running. Now you're reconnected and want to monitor the process's output or provide input, but find the standard I/O streams are lost.

When a process is disowned, it loses its connection to the original terminal's file descriptors (stdin=0, stdout=1, stderr=2). These become orphaned and can't be simply reattached with tools like screen or tmux.

The most reliable method is using gdb to redirect the file descriptors:

# First find your process ID
$ pgrep -f "your_process_name"

# Attach with gdb
$ gdb -p PID

# In gdb:
(gdb) call close(0)
(gdb) call close(1)
(gdb) call close(2)
(gdb) call open("/dev/pts/X", 0)  # Replace X with your current terminal (see 'tty')
(gdb) call dup(0)
(gdb) call dup(0)
(gdb) detach
(gdb) quit

For a simpler solution, install and use reptyr:

$ sudo apt install reptyr  # Debian/Ubuntu
$ reptyr PID

To avoid this situation in the future:

  • Always use screen or tmux for long-running processes
  • Consider nohup with proper redirection: nohup command > output.log 2>&1 &
  • For critical processes, use proper init systems like systemd

If reattachment isn't possible, ensure your process logs to files:

$ strace -ewrite -p PID  # View writes to stdout/stderr
$ lsof -p PID            # Check open files