Introduction Do you ever want to see other people's terminals on a Linux server? I have.Of course, having the terminal physically shown is one way, but it's a bit of a hassle. You can also use the command, but it is a little more laborious because you have to ask the shower to execute the command. script script So I've created a tool that makes it easy to see the terminals of other users logged in on the server! This tool wraps . It is called . It's incredible simple and very useful. strace ttycopy https://github.com/d-tsuji/ttycopy strace It is well known that command can be used to trace a system call. Before introducing the workings of , let's review how to check a system call with . For example, if the current directory is and there is an empty file named under , the result of stracing is shown below. In other words, the situation is as follows. strace ttycopy strace /tmp sample.txt /tmp [root@localhost tmp]# pwd /tmp [root@localhost tmp]# ls sample.txt We can check with what kind of system call is being called when you call . strace ls [root@localhost tmp]# strace ls execve("/usr/bin/ls", ["ls"], [/* 27 vars */]) = 0 brk(NULL) = 0xaf7000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2afb9f4000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=84100, ...}) = 0 mmap(NULL, 84100, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2afb9df000 close(3) = 0 open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320i\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=155784, ...}) = 0 mmap(NULL, 2255184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2afb5ad000 mprotect(0x7f2afb5d1000, 2093056, PROT_NONE) = 0 mmap(0x7f2afb7d0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0x7f2afb7d0000 mmap(0x7f2afb7d2000, 6480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2afb7d2000 ... mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f288e995000 write(1, "sample.txt\n", 11sample.txt ) = 11 close(1) = 0 munmap(0x7f288e995000, 4096) = 0 close(2) = 0 exit_group(0) = ? Even if we take one operation to get the result of the command as described above, we can see that many system calls are made behind the scenes. ls I would like to tell you how this is being processing. The basic flow of the process is as follows. ttycopy Check the PID of the tty's login process Retrieving read system calls to PID using the strace command Print a formatted string of the read system call output by strace 1.Check the PID of the tty's login process The shell implementation is as follows. pid=`ps fauwwx | grep sshd.*${tty} | grep -v grep | sed -e 's/^[a-zA-Z0-9]\+[ \n\r\f\t]\+\([0-9]\+\).*/\1/'` This captures the PID using a regular expression with a string of the following process tree that can be retrieved when grep is done. You can use regular expressions to make it look neat. [tsuji@localhost ~]$ ps fauwwx | grep sshd. root 1531 0.0 0.1 82568 6236 ? Ss 15:29 0:00 /usr/sbin/sshd -D root 2830 0.0 0.2 149824 8916 ? Ss 15:29 0:01 \_ sshd: root@pts/0 root 13315 0.0 0.2 158980 10280 ? Ss 18:58 0:00 \_ sshd: root@notty root 14956 0.0 0.2 154512 9352 ? Ss 20:10 0:00 \_ sshd: tsuji [priv] tsuji 14959 0.0 0.1 154512 4092 ? S 20:10 0:00 \_ sshd: tsuji@pts/1 tsuji 15012 0.0 0.0 112672 2268 pts/1 S+ 20:11 0:00 \_ grep --color=auto sshd. 2.Retrieving read system calls to PID using the strace command The shell implementation is as follows. strace -e read -s16384 -q -xx -p ${pid} 2>&1 What we're doing is using to retrieve the read system call issued by the PID associated with the tty we just retrieved. Because various other system calls are called besides the read system call, only the read system call is extracted with the option of trace. trace -e read The read system call was the system call defined below, and the results that can be obtained with starce are also as follows. read( fd, *buf, count); # include <unistd.h> ssize_t int void size_t For a user who is logged in at another terminal, execute the command in the directory. ls /tmp straing terminal read(0, "l", 1) = 1 read(0, "s", 1) = 1 read(0, "\r", 1) = 1 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2985, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- # strace -p 14959 -e read We can only get results for read system calls that are being read from the standard input as shown above. The standard input is the file descriptor number 0. The goal is to display the contents of the second argument of the read system call obtained in step 2. The shell implementation is as follows. 3.Print a formatted string of the read system call output by strace sed -une "s/^read([0-9]\+, \"\(.*\)\".*/echo -n \$'\1'/p" | bash First, the first part . It captures the second argument of the read system call in a regular expression and gives it the strings . Therefore, it is possible to restore the commands executed in the scanning terminal in real time. sed -une "s/^read([0-9]\+, \"\(.*\)\".*/echo -n \$'\1'/p" echo -n` and `$'' The string output to the source terminal [tsuji@localhost tmp]$ ls sample.txt [tsuji@localhost tmp]$ Strace the terminal string to be output after processing. echo -n $'\x00\x00\x00\x10\x97\xcb\x9f\x29\xb7\x68\xee\xb5\x30\x84\xee\xad\x9d\x73\x52\x01\x17\x63\x30\x62\xe3\xe2\x7e\x61\x26\x64\x5b\x73\x93\x64\x96\xfd' echo -n $'l' echo -n $'\x00\x00\x00\x10\x70\x94\x30\xff\x6a\xfa\xbf\xfb\x1a\x1c\x23\x95\x85\x7d\x8f\xa4\xb7\x55\x42\xa4\x8e\x6e\x3e\x3e\xcd\xe4\xd1\xf7\xfb\x05\x5c\xb8' echo -n $'s' echo -n $'\x00\x00\x00\x10\x2d\xda\xa7\x40\xa5\xbc\x6a\xf4\x3f\x42\xce\x89\x6d\x3b\x6a\xe1\x16\xe6\x2e\x14\x55\x0d\xdd\x2b\xd8\x9c\xe0\x81\x84\x7d\x8d\x9d' echo -n $'\r\n' echo -n $'sample.txt\r\n' echo -n $'\x1b\x5d\x30\x3b\x74\x73\x75\x6a\x69\x40\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x3a\x2f\x74\x6d\x70\x07\x5b\x74\x73\x75\x6a\x69\x40\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x20\x74\x6d\x70\x5d\x24\x20' The option of is to avoid line breaks when interpreting. the form of Bash has the following effect. excerpt from the Man page -n echo -n $'' Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows: ref: This can be used to expand to the meaning that the string holds. https://linux.die.net/man/1/bash All that's left to do is to let the shell interpret the string with the to display the string. echo | bash Summary I was able to casually share the terminal by retrieving a string of arguments for the read system call with and restoring them in real time. I think is very useful and an educational tool because you can see other people's work in real time. If you want to scan the terminal, you should try it. strace ttycopy Thank you!