Lubuntu 18.04では、lxterminalでシェルを実行しています。その制御端末は現在の疑似端末スレーブです。
$ tty
/dev/pts/2
現在の制御端末/dev/pts/2
と/dev/tty
の関係を教えてください。
/dev/tty
は、現在の制御端末のように機能します/dev/pts/2
:
$ echo hello > /dev/tty
hello
$ cat < /dev/tty
world
world
^C
しかし、それらは一方が他方へのシンボリックリンクまたはハードリンクではなく、無関係なファイルのように見えます。
$ ls -lai /dev/tty /dev/pts/2
5 crw--w---- 1 t tty 136, 2 May 31 16:38 /dev/pts/2
13 crw-rw-rw- 1 root tty 5, 0 May 31 16:36 /dev/tty
異なる制御端末との異なるセッションの場合、/dev/tty
がそれらの制御端末であることが保証されている場合。シンボリックリンクやハードリンクでなくても、どのように異なる制御端末になることができますか?
では、それらの関係と違いは何ですか?どんな助けでも大歓迎です!
この投稿は以前の投稿からのものです コマンド `tty`の出力とファイル`/dev/tty`はどちらも現在のbashプロセスの制御端末を参照していますか?
セクション4のtty
マンページ は次のように主張しています。
ファイル/ dev/ttyは、メジャー番号5およびマイナー番号0の文字ファイルで、通常はモード0666で、owner.group root.ttyです。これは、プロセスの制御端末(存在する場合)の同義語です。
Ttyが参照するデバイスがサポートする
ioctl(2)
リクエストに加えて、ioctl(2)
リクエストTIOCNOTTY
サポートされています。
TIOCNOTTY
制御端末から呼び出しプロセスを切り離します。
プロセスがセッションリーダーである場合、
SIGHUP
およびSIGCONT
シグナルがフォアグラウンドプロセスグループに送信され、現在のセッションのすべてのプロセスが制御ttyを失います。この
ioctl(2)
呼び出しは、/ dev/ttyに接続されたファイル記述子でのみ機能します。端末でユーザーが呼び出すときにデーモンプロセスによって使用されます。プロセスは/ dev/ttyを開こうとします。オープンが成功した場合は、TIOCNOTTY
を使用してターミナルからデタッチしますが、オープンが失敗した場合は、ターミナルにアタッチされていないため、デタッチする必要はありません。
これは、/dev/tty
が制御端末へのシンボリックリンクではない理由を部分的に説明します。追加のioctl
をサポートし、制御端末がない可能性があります(ただし、プロセスは常にアクセスを試みることができます) /dev/tty
)。ただし、ドキュメントは正しくありません。追加のioctl
には、via/dev/tty
だけでアクセスできません( mosvyの回答 を参照)。 /dev/tty
)の性質について、より賢明な説明も提供します。
/dev/tty
は、リンクではなく、さまざまな制御端末を表すことができます。これを実装するドライバーは、呼び出しプロセスの制御端末がある場合、それを決定するためです。
これは/dev/tty
が制御端末であり、制御端末にのみ意味のある機能を提供していると考えることができますが、/dev/pts/2
などはプレーンな端末であり、その1つが制御端末である可能性があります指定されたプロセスのターミナル。
/dev/tty
は「魔法の」文字デバイスであり、開くと現在の端末にハンドルが返されます。
制御端末が/dev/pts/1
であると仮定すると、/dev/pts/1
を介して開かれたファイル記述子と/dev/tty
を介して開かれたファイル記述子は同じデバイスを参照します。書き込み、読み取り、またはその他のファイル操作は、どちらでも同じように機能します。
特に、それらは同じioctlのセットを受け入れます。TIOCNOTTY
は、/dev/tty
を介してのみ使用可能な追加のioctlではありません。
ioctl(fd, TIOCNOTTY)
は、それを呼び出すプロセスの制御端末である限り、端末を参照するすべてのファイル記述子で同じように機能します。
/dev/tty
、/dev/pts/1
、/dev/ptmx
を開いて記述子を取得したかどうかは関係ありません(この場合、ioctlは対応するslaveで動作します)、または最近では、ioctl(master, TIOCGPTPEER, flags)
を呼び出しています。
例:
$ cat <<'EOT' >tiocnotty.c
#include <sys/ioctl.h>
#include <unistd.h>
#include <err.h>
int main(int ac, char **av){
if(ioctl(0, TIOCNOTTY)) err(1, "io(TIOCNOTTY)");
if(ac < 2) return 0;
execvp(av[1], av + 1);
err(1, "execvp %s", av[1]);
}
EOT
$ cc -W -Wall tiocnotty.c -o tiocnotty
$ ./tiocnotty
$ ./tiocnotty </dev/tty
$ tty
/dev/pts/0
$ ./tiocnotty </dev/pts/0
また、現在のプロセスをttyから実際に「切り離す」ことはありません。プロセスは引き続きそれから読み取ることができ、端末の^C
はそれを強制終了します。セッションリーダーでないプロセスへの唯一の影響は、ttyが/dev/tty
を介してアクセスできなくなり、 /proc/PID/stat
で制御ttyとしてリストに表示されなくなりました。
$ ./tiocnotty cat
^C
$ ./tiocnotty cat
^Z
[2]+ Stopped ./tiocnotty cat
$ ./tiocnotty cat
foo
foo
^D
$ ./tiocnotty cat /dev/tty
cat: /dev/tty: No such device or address
$ ./tiocnotty awk '{print$7}' /proc/self/stat
0
[/proc/<pid>/stat
の7番目のフィールドは、制御しているttyのデバイスIDです。proc(5)
を参照してください]
それを呼び出すプロセスがセッションリーダーである場合、それは実際にセッションをttyから切り離し、SIGHUP
/SIGCONT
ペアをセッションからフォアグラウンドプロセスグループに送信します。しかし、それでも、ターミナルはnotを閉じ、プロセスがSIGHUP
を生き延びた場合でも、それから読み取ることができます。
$ script /dev/null -c 'trap "" HUP; exec ./tiocnotty cat'
Script started, file is /dev/null
lol
lol
^C^C^C^C^C # no controlling tty anymore
wtf
wtf
^D # but still reading fine from it
Script done, file is /dev/null
/dev/tty
は、/dev/stdin
=> /dev/fd/0
=> /proc/self/fd/0
=> /dev/pts/0
のようなシンボリックリンクではありません。これは、procfsのような仮想動的ファイルシステムのずっと前に(そして一般的にシンボリックリンクのずっと前に)発明されたためです。そして、多くのプログラムはその特定のセマンティクスに依存するようになりました(たとえば、制御端末にアクセスできないときに/dev/tty
がENODEV
で失敗する)。