0

Suppose I have two shells open, one with PID 1234 and the other - 5678.

I can clear the screen and reset of the other shell via echo $'\033c' > /proc/1234/fd/0 as if reset was typed on the prompt of the terminal itself. However, when I do echo $'\04' > /proc/1234/fd/0 to send EOT character, this doesn't seem to work. How can I achieve the desired effect ?

1 Answers1

8

First of all, a tty, even if it appears a single file object, is actually a pair of pipes/queues -- one for the output and one for the input, the other ends of each being connected either to the TX/RX of some hardware device, or made available to another program in the case of a pseudo-tty. When you're writing anything to the fd linked to a tty, you're writing into the output queue, even if that's the fd 0 (stdin) of your process, and will not be looped back into the input queue.

On most Unix systems (with the notable exception of OpenBSD), there's a special ioctl (TIOCSTI) which allows you to insert a byte into the input queue of a tty, as if it were received from the other end. TIOCSTI will only work as root when not used on the controlling tty of the process calling it.

$ cc -Wall tiocsti.c -o tiocsti

-- as root --

# printf '\04' | ./tiocsti >/proc/5460/fd/0

If your process is running in a pseudo-tty, another way to "fake" input is to connect with a debugger to the process holding the master side of the pseudo-tty, and write(2) your stuff into it from there.

$ gdb -p pid_of_xterm
(gdb) p write(4, "\x04", 1)   # 4 is the fd of the master pty
(gdb) c

Both methods are just overkill. If you want to control a running process, you better attach with a debugger to that very process instead of faking it some input; if you want to instrumentalize an interactive program, you better run it in expect; both will work on any Unix system and don't require extra privileges for that.

Also notice that ^D / \004 will only work as EOF if a) the tty is in canonical mode b) the c_cc[VEOF] special character wasn't changed to something else c) the output queue is empty (otherwise c_cc[VEOF] will have to be sent twice). And of course, it will be the process which is just reading from tty which will get the EOF or those bytes, not necessarily the shell.

tiocsti.c

#include <sys/ioctl.h>
#include <unistd.h>
#include <err.h>

int main(void){
        char c; ssize_t r;
        while((r = read(0, &c, 1)) > 0){
                if(ioctl(1, TIOCSTI, &c)) err(1, "ioctl(TIOCSTI)");
        }
        if(r < 0) err(1, "read");
        return 0;
}
  • https://unix.stackexchange.com/a/566093/5132 has the restrictions and non-portability notes. – JdeBP Feb 24 '20 at 09:14