I have tried using pipes and redirections to have (C program or scripts) output end up on the input buffer, the way printf "\033[6n" does, but no positive results.

Does anyone know how this is possible as:

  1. a command line
  2. in a shell script
  3. C code

Piping output _cmd_ > /dev/stdin and C code fprintf(stdin, "blah\n"); have no measurable effect.

Note: I don't want to "pipe" the input out to another command, I want to "inject" characters into the "keyboard buffer" (as it were).

  • I finally found the process by which the kernel outputs to input buffer (via respond_string in src/drivers/tty/vt/vt.c), but atm it is of no help. it uses a buffer to a (tty) port, but I cant decipher it. – Paul Wratt Nov 24 '17 at 8:11
  • output to fd 0 (even on another tty) does NOT put it in the "input buffer". I've read this, but cant find any answers either. – Paul Wratt Nov 24 '17 at 9:05
  • Look for TIOCSTI e.g. in man ioctl_tty, or unix.stackexchange.com/a/238232/53656, or everywhere else on the Internet. Is this what you're looking for? – egmont Nov 24 '17 at 9:20
  • On a broader scale: OpenBSD has recently removed this option due to security concerns, see undeadly.org/cgi?action=article&sid=20170701132619. What's your bigger picture? Probably you should redesign the architecture of your software not to require this hack, but properly send the data to its standard input. – egmont Nov 24 '17 at 9:47
  • after much looking, deciphering and whatnot, see the end of the answer I posted, and it works from a shell or script too - bonus – Paul Wratt Nov 25 '17 at 0:13

Edit: The short answer was /dev/uinput, now its TIOCSTI (see end of post)

This is the answer so far, and to address the comments:

man ioctl_tty I dont have, but a lookup of TIOCSTI on the kernel source (via FreeElectrons ) will show tiocsti "fake input character", which uses a tty_struct context.

The application in question is running all the time, interactively, so pipes and redirects cant be used. It can shell out for scripting, however, unlike a lot of other similar apps, it does not, nor allows for, capture the results, only allowing stdin & stdout to do their thing as per normal.

For the foreseeable future there is no chance of changing this, its not my application. However I was able to cut the results of "\033[6n", which have been injected into the keyboard buffer by the kernel through tty_insert_flip_char & tty_schedule_flip in src/drivers/tty/tty_buffer.c, which uses a tty_port context.

If memory serves, before the FD file structure was changed, when there was only 4 file descriptors, it may have been possible to achieve this. Nowadays although you can write to /dev/stdin or /proc/self/fd/0, they are connected to /dev/tty# and anything written to to a TTY device will end up on the screen (/dev/stdout). The kernel seems to bypass the file descriptor route when using TTY's, notice the flip functions refer to it as a port.

Any userland app does not have access to either of those kernel functions. Under X-Windows it is possible to use xvkbd and xdotool or xte, but this app is being used on the linux (VT) console.

The (Almost) Real Answer:

Although /dev/uinput does not have user privileges (on most systems), sudo a script that printf all arguments will work.

Alternatively, the keyboard event will also work, as all users have access to it, but it changes per boot and per system (mine is normally /dev/input/event0, but not always).

After further research, neither of these approaches is practical, especially for scripting. The thing we need to understand about what needs to be done, is that we just want to present text on the input buffer, not "simulate a keypress" (which is how the above devices work).

The (Most Practical) Real Answer:

An offsite question referred back to an answer on stackexchange, from 2011 (here). It uses TIOCSTI. After reviewing the the Perl example again, it may also be practical for scripting, where an application is not supplied.

perl -le 'require "sys/ioctl.ph";
      ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV
     ' `_cmds_`

However it does echo it to the screen as well. After many hours of further research and experimentation the following is practical in a script or on the command line:

stty -echo; perl -le 'require "sys/ioctl.ph"; ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV ' `_cmds_` ;stty echo

Note: although TIOCSTI has currently been revoked in BSD (Nov 2017), apparently the Linux Kernel developers are of the opposite mind, categorically refusing to revoke it


writevt /dev/tty# text, at least on Linux, maybe BSD and Unix, its currently party of the console-tools package. The user must have write privileges for the VT. Specifically, the full and correct answer to the OP is:

writevt `tty` "`_cmds_`"

This question shows the lack of depth of knowledge about base operating systems by the StackExchange community as a whole. writevt is very old, it is a base command installed on 99% (of Linux) systems. Up until June 2002 there was no man page or maintainer for it in Debian, which may account for why a lot of people don't know about it, even though that was 15 years ago. However, even on Kali Linux (which has everything) it is most often not listed under available commands, even though it has been there since the start.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.