Faking input with IOCTL/TIOCSTI

Have you ever had a script or program running in the background, with no TTY/console, asking for input to continue running? How do you tell it ‘y’ so it will keep going? By faking input using TIOCSTI! I had this issue when running a long chain of tasks in an ansible playbook, and a command in one of those tasks wanted to know if I was “sure”. I identified the PID that was waiting for input, and wrote this little python script:

import fcntl
import sys
import termios

with open('/proc/<PID GOES HERE>/fd/0', 'w') as fd:
    for char in "y\n":
        fcntl.ioctl(fd, termios.TIOCSTI, char)

When you run this, it will send the letter ‘y‘, followed by newline to the PID, and the process continues to run. What is TIOCSTI? From the man page of ioctl_tty:

IOCTL_TTY(2)               Linux Programmer's Manual              IOCTL_TTY(2)

NAME
       ioctl_tty - ioctls for terminals and serial lines

SYNOPSIS
       #include <termios.h>

       int ioctl(int fd, int cmd, ...);

DESCRIPTION
       The  ioctl(2) call for terminals and serial ports accepts many possible
       command arguments.  Most require a third  argument,  of  varying  type,
       here called argp or arg.

       Use  of  ioctl makes for nonportable programs.  Use the POSIX interface
       described in termios(3) whenever possible.

[...]

   Faking input
       TIOCSTI   const char *argp
              Insert the given byte in the input queue.

[...]

Linux                             2020-06-09                      IOCTL_TTY(2)

When I googled around for a way to solve this, this Stackexchange Q&A was pretty much spot on: https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty and this answer in particular for the Python script: https://unix.stackexchange.com/a/345572/315097