web-dev-qa-db-ja.com

現在の制御端末と `/ dev / tty`の間にはどのような関係がありますか?

Lubuntu 18.04では、lxterminalでシェルを実行しています。その制御端末は現在の疑似端末スレーブです。

$ tty
/dev/pts/2

現在の制御端末/dev/pts/2/dev/ttyの関係を教えてください。

  1. /dev/ttyは、現在の制御端末のように機能します/dev/pts/2

    $ echo hello > /dev/tty
    hello
    
    $ cat < /dev/tty
    world
    world
    ^C
    
  2. しかし、それらは一方が他方へのシンボリックリンクまたはハードリンクではなく、無関係なファイルのように見えます。

    $ 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プロセスの制御端末を参照していますか?

7
Tim

セクション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つが制御端末である可能性があります指定されたプロセスのターミナル。

12
Stephen Kitt

/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/ttyENODEVで失敗する)。

2
mosvy