Inner workings of TTY under Linux - tty

I've been trying to figure out how TTY drivers works for a while now (with full understanding each kernel's implementation may be different), and came across a nice article: The TTY demystified
I notice however that it claims xterm does not have a stdin, stdout or stderr. How does xterm and other terminal emulators get the input from bash and other child processes so it can print to the window? Does the terminal emulator have a connection to a TTY driver at all?

I don't believe the claim that xterm(1) has no stdin, stdout, or stderr makes much sense. And, just skimming that article, I think they were left blank on the diagram because they didn't figure much into what he was describing.
You can check your own terminals' file descriptors easily enough. The urxvt(1) terminals that I normally use look like this:
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 0 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 1 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 2 -> /home/sarnold/.xsession-errors
An xterm(1) I started from one of those urxvt(1) terminals looks like this:
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 0 -> /dev/pts/1
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 1 -> /dev/pts/1
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 2 -> /dev/pts/1
And an xterm(1) I started using my window manager's dmenu(1) launcher looks like this:
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 0 -> /dev/null
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 1 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 2 -> /home/sarnold/.xsession-errors
The important part to remember about stdin, stdout, and stderr is that they are completely unrelated to the graphical display that the terminal emulators offer. If your terminal program needs to write an error to stderr, say via perror(3), its output might go to the terminal where you started it or to a session error log such as ~/.xsession-errors. If you log in via ssh(1) and start your xterm(1) like this:
DISPLAY=:1 xterm -e 'echo hello ; sleep 10`
You'll see it start up and display hello. (Assuming your DISPLAY matches mine.) If you change the command to:
DISPLAY=:1 xterm -fn fiddly -e 'echo hello ; sleep 10'
You'll see that the error message about the incorrect font is sent to the terminal where you started xterm(1) -- not to its own graphical interface. (This is a bit funny, because if you change SHELL to something that doesn't exist, or attempt to execute something that doesn't exist, the error message will be printed within the graphical window instead of to the standard error.)
A file that is also open in my terminal emulators is ptmx(4):
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 0 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 1 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 2 -> /home/sarnold/.xsession-errors
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 3 -> anon_inode:[eventpoll]
lr-x------ 1 sarnold sarnold 64 2011-11-10 21:33 4 -> pipe:[16398]
l-wx------ 1 sarnold sarnold 64 2011-11-10 21:33 5 -> pipe:[16398]
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 6 -> socket:[16399]
lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 7 -> /dev/ptmx
Opening the ptmx(4) device gives the terminal emulator the pipe connections for the PTY master and slave. It is to these pipes that the terminal emulator software communicates with the clients and the kernel.
I can't do the tty layer justice; I strongly recommend reading the pty section from Advanced Programming in the Unix Environment, 2nd edition for full details. The book (and source code include writing your own pty driver which can be used to implement script(1)-like functionality or tricking the standard C IO streams into using line-buffering rather than block-buffering when the program doesn't provide any command line options to control this natively.

Related

How docker interacts with your terminal

I'm curious about how dockerized processes interact with the terminal from which you run docker run.
From some research I done, I found that when you run a container without -t or -i, the file descriptors of the process are:
// the PID of the containerized process is 16198
~$ sudo ls -l /proc/16198/fd
total 0
lrwx------ 1 root root 64 Jan 18 09:28 0 -> /dev/null
l-wx------ 1 root root 64 Jan 18 09:28 1 -> 'pipe:[242758]'
l-wx------ 1 root root 64 Jan 18 09:28 2 -> 'pipe:[242759]'
I see that the other ends of those pipes are of the containerd-shim process that spawned the containerized process. We know that once that process will write something to its STDOUT, it will show up on the terminal from which you ran docker run. Further, when you run a container with -t and look at the open FDs of the process:
~$ sudo ls -l /proc/17317/fd
total 0
lrwx------ 1 root root 64 Jan 18 09:45 0 -> /dev/pts/0
lrwx------ 1 root root 64 Jan 18 09:45 1 -> /dev/pts/0
lrwx------ 1 root root 64 Jan 18 09:45 2 -> /dev/pts/0
So now the container has a pseudo-tty slave as STDIN, STDOUT and STDERR. Who has the master side of that slave? Listing the FDs of the parent containerd-shim we can now see that it has a /dev/ptmx open:
$ sudo ls -l /proc/17299/fd
total 0
lr-x------ 1 root root 64 Jan 18 09:50 0 -> /dev/null
l-wx------ 1 root root 64 Jan 18 09:50 1 -> /dev/null
lrwx------ 1 root root 64 Jan 18 09:50 10 -> 'socket:[331340]'
l--------- 1 root root 64 Jan 18 09:50 12 -> /run/docker/containerd/afb8b7a1573c8da16943adb6f482764bb27c0973cf4f51279db895c6c6003cff/init-stdin
l--------- 1 root root 64 Jan 18 09:50 13 -> /run/docker/containerd/afb8b7a1573c8da16943adb6f482764bb27c0973cf4f51279db895c6c6003cff/init-stdin
lrwx------ 1 root root 64 Jan 18 09:50 14 -> /dev/pts/ptmx
...
So I suppose that the containerd-shim process interacts with the container process using this pseudo-terminal system. By the way, even in this case you can't interact with the process, since I didn't ran the container with -i.
So one question is: what difference does it make if containerd-shim interacts with the process using a pipe or using a pseudo-terminal subsystem?
Another question is, how do containerd-shim rolls this data to the terminal from which I ran docker run

Check if a already running process has the stdin redirected on Linux?

Given the PID of a process, is there a way to find out if this process has the stdin or stdout redirected?
I have one application that reads from the stdin. For convenience, I usually launch this application with stdin redirected from file, like this:
app < input1.txt
The problem is that sometimes I launch the application and forget what was the input file that I used. Is there a way to find out which file has been used to redirect the stdin?
Using ps -aux | grep PID allow me to see the command line used. But does not give me any information about the stdin or stdout.
I have also tried to look in top, as well as in /proc/PID/* but haven't found anything.
I am using CentOS 7, if that helps.
You should just be able to look at /proc/<PID>/fd for this information. For example, if I redirect stdin for a command from a file:
sleep inf < somefile.txt
Then I fill find in the corresponding /proc directory:
$ ls -l /proc/12345/fd
lr-x------. 1 lars lars 64 Nov 4 21:43 0 -> /home/lars/somefile.txt
lrwx------. 1 lars lars 64 Nov 4 21:43 1 -> /dev/pts/5
lrwx------. 1 lars lars 64 Nov 4 21:43 2 -> /dev/pts/5
The same thing works when redirecting stdout to a file. If I run:
sleep inf > somefile.txt
Then I see:
$ ls -l /proc/23456/fd
lrwx------. 1 lars lars 64 Nov 4 21:45 0 -> /dev/pts/5
l-wx------. 1 lars lars 64 Nov 4 21:45 1 -> /home/lars/somefile.txt
lrwx------. 1 lars lars 64 Nov 4 21:45 2 -> /dev/pts/5

Is there a real file for stream i/o in linux?

I confused in concept of i/o stream in the linux.
There is 3 types of stream: standard input. standard output and standard error.
Is there a real file in the ram or hard disk for stdin, stdout and stderr?
For example: kernel writes all keyboard inputs to a stdin file? and then bash(for example) read this file?
And if this true, that's mean any software can read this file in any time?
Every process has (at least initially) the standard stdin/stdout/stderr file handles opened for it. Every process also has a representation in /proc, which is a virtual file system created by the kernel to access all kinds of stuff about the processes. So...
marc#panic:~$ ps
PID TTY TIME CMD
4367 pts/0 00:00:00 bash <--- my bash process
4394 pts/0 00:00:00 ps
marc#panic:~$ cd /proc/4367/fd <---my bash processes's /proc file descriptors
marc#panic:/proc/4367/fd$ ls -l
total 0
lrwx------ 1 marc marc 64 Nov 17 11:17 0 -> /dev/pts/0
lrwx------ 1 marc marc 64 Nov 17 11:17 1 -> /dev/pts/0
lrwx------ 1 marc marc 64 Nov 17 11:17 2 -> /dev/pts/0
lrwx------ 1 marc marc 64 Nov 17 11:18 255 -> /dev/pts/0
files 0, 1, 2 correspond to stdin, stdout, stderr, and they're simply symlinks to the particular pseudo terminal my login session is using.
I wouldn't call these real files, but:
You can use /dev/stdout etc on Linux.

How to see which file are in use in Linux

I have a question how can I see which file are in use in linux. To be honest this OS is not the normal version of linux it is very crippled so for example there is no command like "lsof". I found command "strace" but this is no what I looking for. I hear that I can list this file with hacking kernel?
I want to see which file are in use because on this machine is a little free space and I want to delete file which are no in use when the program is running.
I'm sorry for my weak english.
You can inspect the open files by process by walking the /proc virtual filesystem
Every process running has an entry in /proc/PID. There's a directory in each process directory called 'fd', that represents the processes currently opened file descriptors. These appear as links to the actual resources.
e.g. on a VM I have running
root#wvm:/proc/1213/fd# pidof dhclient
1213
root#wvm:/proc/1213/fd# cd /proc/1213/fd
root#wvm:/proc/1213/fd# ls -l
total 0
lrwx------ 1 root root 64 Apr 8 09:11 0 -> /dev/null
lrwx------ 1 root root 64 Apr 8 09:11 1 -> /dev/null
lrwx------ 1 root root 64 Apr 8 09:11 2 -> /dev/null
lrwx------ 1 root root 64 Apr 8 09:11 20 -> socket:[4687]
lrwx------ 1 root root 64 Apr 8 09:11 21 -> socket:[4688]
l-wx------ 1 root root 64 Apr 8 09:11 3 -> /var/lib/dhcp/dhclient.eth0.leases
lrwx------ 1 root root 64 Apr 8 09:11 4 -> socket:[4694]
lrwx------ 1 root root 64 Apr 8 09:11 5 -> socket:[4698]
root#wvm:/proc/1213/fd#
Looking at the kernel process information for 'dhclient' - I find its pid, and then look in the fd subdirectory for this process id. It has a small set of open descriptors - stdin, stdout and stderr ( 0,1,2 ) have all been attached to /dev/null , there's four sockets open, but file descriptor 3 is attached to a data file /var/lib/dhcp/dhclient.eth0.leases
So you could duplicate the functionality of lsof using shell tools to walk /proc and filter out the file names from these links.
Are you able to use "top" command? if so then this should show you the list of all the top OS utilizing operations running on linux. You can do
ps -ef|grep <process_no>
this would give the details of it. Either can stop that process or kill it using
kill -9 <process no>
Use the lsof command to list all open files by process.

How to reroute stdout, stderr back to /dev/tty

I just ssh-ed to some remote server and found that stdout and stderr of all commands/processes I am trying to run in bash is redirected to somewhere.
So, I got following questions
How to detect:
1) Which file stdout, stderr is beeing rerouted in Linux?
and
2) And how reroute by default stdout and stderr back to /dev/tty?
Thank you in advance.
A command that should do literally what you asked for in (2) is
exec >/dev/tty 2>&1
But I suspect that your analysis of the problem is incorrect. It would be useful to see the output of ssh -v ... (where ... is whatever arguments you typed in your original ssh command).
The command:
ls -l /proc/$$/fd/{1,2}
will show you which files are open as stdout (file descriptor 1) and stderr (file descriptor 2).
An answer to your first question could be found in /proc/self/fd. It contains symlinks to the files (or other things, pipes, sockets, etc) that your bash instance is connected to.
root#mammon:~# ls -l /proc/self/fd
total 0
lrwx------ 1 root root 64 May 21 02:18 0 -> /dev/pts/3
lrwx------ 1 root root 64 May 21 02:18 1 -> /dev/pts/3
lrwx------ 1 root root 64 May 21 02:18 2 -> /dev/pts/3
lr-x------ 1 root root 64 May 21 02:18 3 -> /proc/15529/fd/
root#mammon:~# ls -l /proc/self/fd < /dev/null
total 0
lr-x------ 1 root root 64 May 21 02:18 0 -> /dev/null
lrwx------ 1 root root 64 May 21 02:18 1 -> /dev/pts/3
lrwx------ 1 root root 64 May 21 02:18 2 -> /dev/pts/3
lr-x------ 1 root root 64 May 21 02:18 3 -> /proc/15536/fd/
root#mammon:~# ls -l /proc/self/fd | cat
total 0
lrwx------ 1 root root 64 May 21 02:18 0 -> /dev/pts/3
l-wx------ 1 root root 64 May 21 02:18 1 -> pipe:[497711]
lrwx------ 1 root root 64 May 21 02:18 2 -> /dev/pts/3
lr-x------ 1 root root 64 May 21 02:18 3 -> /proc/15537/fd/
root#mammon:~#
In the first example, you can see the first 3 file descriptors (which are the standard output, input, and error, respectively) all point to my pseudo-terminal /dev/pts/3. In the second example I've redirected the input to /dev/null, so the standard input file descriptor points to /dev/null. And in the final example I've sent the output of ls to cat through a pipe, and the standard input file descriptor reflects this. As far as I know there is no way to find which process has the other end of the pipe. In all examples there is the fourth file descriptor that represents the handle that ls has for reading /proc/self/fd. In this case it says /proc/15537 because /proc/self is in fact a symlink to /proc/pid where pid is the PID of the process accessing /proc/self.
It can only be done if your longing shell is started with a pipe to tee command with another console as a parameter.
Let me explain.
If you are logging in /dev/tty1 and someone else is logging in /dev/tty2. If you start your shell (bash) by following command all the STDOUT/STDERR will be rerouted/copied to another shell (/dev/tty2 in this case).
bash 2>&1 | tee /dev/tty2
So, someone sitting in /dev/tty2 will see all of your activity.
If someone logins shell is /bin/bash 2>&1 | tee /dev/tty2 instead of /bin/bash It'll happen every time he logs in. But I am not sure login shell can be set that way.
If someone reroutes all the output of your shell this way you can check it just by checking if any tee is running in background.
ps ax | grep tee
This will output something like
tee /dev/tty2

Resources