Redirect File Descriptor of Running Process

This note explains how to redirect stdin (or any other file descriptor) of a pre-existing process using the GNU debugger (gdb) and a FIFO. It was tested on FreeBSD 11.

An example of use would be saving the contents of remote vi sessions after they are detached due to a dropped connection.

First, make a FIFO:

$ mkfifo /tmp/vififo

Assuming there is a pre-existing vi session with PID 91266, connect with gdb, close file descriptor 0 and reopen it as a connection to the FIFO with the call close and call open commands.

$ gdb -p 91266
<snip>
Attaching to process 91266
<snip>
(gdb) call close (0)
$1 = 0
(gdb) call open ("/tmp/vififo", 0600)

At this point gdb will appear to hang. Leave it and open a new terminal. Use echo to send characters to the process through the FIFO.

Special characters may be escaped by pressing Ctrl-V followed by the character. For example, to send an Escape, press Ctrl-V followed by Escape which results in an Escape code, or ^[.

Continuing the example, tell vi to save the current buffer to a file.

$ echo "^[:w /tmp/vi_recover.txt" > /tmp/vififo

After this command the gdb session should start responding again, returning to a (gdb) prompt. Exit gdb.

$2 = 0
(gdb) quit
A debugging session is active.

    Inferior 1 [process 91266] will be detached.

Quit anyway? (y or n) Y
Detaching from program: /hh/bin/vi, process 91266
[Inferior 1 (process 91266) detached]

The characters have now been received by vi and a file should be waiting at /tmp/vi_recover.txt.

Expose Process STDIO on TCP Port

This note explains how to launch a process and connect its stdin/stdout/stderr directly to a TCP port. It was tested on FreeBSD 12.

As an example, we will launch a bash process running on a Debian 10 machine and connect it to TCP port 4242. Then, from a FreeBSD machine we will connect and utilize the bash session remotely.

First, on the Debian machine, we use socat, a program which establishes two bidirectional byte streams and transfers data between them. In our case, we tell socat to build a PTY at /tmp/pty_test and connect it to TCP port 4242.

socat PTY,link=/tmp/pty_test,raw TCP-LISTEN:4242,reuseaddr,fork

Note that the PTY argument to socat must precede the TCP-LISTEN argument. Despite the bidirectional nature, the endpoint definition order is not interchangeable.

Now we use setsid to start a new bash process and attach it to the PTY at /tmp/pty_test. Note that we collapse stdout and stderr into a single combined stream.

setsid sh -c 'exec bash --login <> /tmp/pty_test >&0 2>&1'

Replace bash --login with whatever other command you desire to execute.

Now, from the FreeBSD machine, connect the remote TCP port to your local STDIO with socat. Assuming the Debian machine running bash is at 192.168.1.107, execute the following command.

socat STDIO,raw TCP:192.168.1.107:4242

At this point you have a fully interative bash session running on the Debian machine, controlled from the FreeBSD machine.

Determine PID of X11 Window

This note explains how to determine the Process ID (PID) corresponding to a program running in an X11 window, even if the program has locked up.

I occasionally find myself needing to kill an X11 program like my terminal emulator (st) after it locks up, only to be greeted by a list of almost indistinguishable processes.

% ps aux | grep st
ataylor  6358    0.0  0.0   19292    6848  -  Is   18Jan21        0:00.22 st
ataylor 13449    0.0  0.0   18824    6752  -  Is   11Nov20        0:12.00 st
ataylor 15194    0.0  0.0   19208    7416  -  Is    4Aug20        6:22.17 st
ataylor 17303    0.0  0.0   19380    7492  -  Is   16Feb21        0:08.18 st
ataylor 24875    0.0  0.0   18812    8212  -  Is   24Feb21        0:05.34 st
ataylor 25313    0.0  0.0   19388    6928  -  Is   21Sep20        0:04.07 st
ataylor 26013    0.0  0.0   18348    6364  -  Is   29Jun20        0:27.78 st
ataylor 26677    0.0  0.0   20756    9152  -  Is   20Dec20        0:00.86 st
ataylor 27383    0.0  0.0   19152    8552  -  Is   Fri17          0:00.96 st
ataylor 28440    0.0  0.0   18916    5100  -  Is   14Mar20        0:24.59 st
ataylor 28491    0.0  0.0   18320    8528  -  Is   18:22          0:03.22 st
ataylor 31469    0.0  0.0   19280    7000  -  Is   13Feb21        0:10.73 st
ataylor 35707    0.0  0.0   19152    9100  -  Ss   23:45          0:00.08 st
ataylor 39426    0.0  0.0   20980    7900  -  Is   14Mar20        3:11.24 st
ataylor 42211    0.0  0.0   18980    9080  -  Is   17:33          0:02.43 st
ataylor 50065    0.0  0.0   19000    6800  -  Is    3Jan21        0:00.80 st
ataylor 50765    0.0  0.0   18764    6364  -  Is    9Jan21        0:05.97 st
ataylor 50780    0.0  0.0   18896    6656  -  Is   28Oct20        0:01.38 st
ataylor 53637    0.0  0.0   20568    8636  -  Is   26Dec20        0:16.79 st
ataylor 68757    0.0  0.0   19836    8912  -  Is   24Jan21        0:00.56 st
ataylor 69466    0.0  0.0   18980    9012  -  Is   Sun04          0:01.42 st
ataylor 72775    0.0  0.0   19260    7236  -  Is    7Jan21        0:01.10 st
ataylor 73530    0.0  0.0   18764    6912  -  Is    4Nov20        0:17.34 st
ataylor 73701    0.0  0.0   21040    9120  -  Is   20Nov20        0:18.44 st
ataylor 75901    0.0  0.0   18456    7640  -  Is    8Feb21        0:28.57 st
ataylor 80220    0.0  0.0   18884    6756  -  Is   25Dec20        0:04.87 st
ataylor 81521    0.0  0.0   18496    8652  -  Is   01:04          0:12.21 st
ataylor 83818    0.0  0.0   18956    5072  -  Is   10Apr20        0:09.37 st
ataylor 89395    0.0  0.0   18920    4984  -  Is   15Apr20        0:11.99 st

Use xprop to obtain the PID from the window’s various X11-related properties. First, run the command xprop _NET_WM_PID. It will appear to hang, but your mouse cursor will change to crosshairs. Place the crosshairs over the X11 window in question and click. This tells xprop which window you are interested in and xprop then tells you the PID. For example, if I click on one of the st windows from the previous example, we see that it is PID 75901.

% xprop _NET_WM_PID
_NET_WM_PID(CARDINAL) = 75901