Welche Beziehungen bestehen zwischen meinem aktuellen Controlling-Terminal und `/ dev / tty`?

7

Auf Lubuntu 18.04 starte ich eine Shell in lxterminal. Sein steuerndes Terminal ist der aktuelle Pseudoterminal-Slave:

$ tty
/dev/pts/2

Ich würde gerne wissen, welche Beziehungen zwischen meinem aktuellen Controlling-Terminal /dev/pts/2und bestehen /dev/tty.

  1. /dev/ttyverhält sich wie mein aktuelles Steuerterminal /dev/pts/2:

    $ echo hello > /dev/tty
    hello
    
    $ cat < /dev/tty
    world
    world
    ^C
    
  2. Aber es scheint sich um nicht verwandte Dateien zu handeln, anstatt dass ein Symlink oder Hardlink zum anderen ist:

    $ 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
    

Für verschiedene Sitzungen mit verschiedenen Steuerterminals, wenn /dev/ttygarantiert ist, dass es sich um deren Steuerterminals handelt. Wie können es verschiedene steuernde Terminals sein, ohne ein Symlink oder Hardlink zu sein?

Was sind ihre Beziehungen und Unterschiede? Jede Hilfe wird sehr geschätzt!

Dieser Beitrag stammt von einem früheren Beitrag. Beziehen sich die Ausgabe des Befehls `tty` und die Datei` / dev / tty` beide auf das steuernde Terminal des aktuellen Bash-Prozesses?

Tim
quelle
Wie in den Fragen und Antworten erwähnt, auf die Sie verlinken, ttywird das steuernde Terminal nicht gemeldet, aber das Terminal ist auf stdin geöffnet, falls vorhanden. Siehe ps -o tty= -p "$$"für das steuernde Terminal (in der Praxis sind sie an der Eingabeaufforderung einer interaktiven Shell im Allgemeinen gleich).
Stéphane Chazelas
@ StéphaneChazelas Danke. ps -o tty= -p "$$"funktioniert gut! Ist es nicht möglich, das steuernde Terminal der aktuellen Shell abzurufen /dev/tty?
Tim
Es ist möglich, indem man öffnet /dev/tty, anruft ioctl(TIOCGDEV, &dev), um das Maj: Min Devnum der Realität zu erhalten , und dann danach sucht /dev. Dies führt jedoch zu mehrdeutigen Ergebnissen, wenn mehr als ein devpts-Dateisystem bereitgestellt wird.
Mosvy

Antworten:

12

Die ttyManpage in Abschnitt 4 behauptet Folgendes:

Die Datei / dev / tty ist eine Zeichendatei mit der Hauptnummer 5 und der Nebennummer 0, normalerweise im Modus 0666 und der Eigentümergruppe root.tty. Es ist ein Synonym für das steuernde Terminal eines Prozesses, falls vorhanden.

Zusätzlich zu den ioctl(2)Anforderungen, die von dem Gerät unterstützt werden, auf das sich tty bezieht, wird die ioctl(2)Anforderung TIOCNOTTYunterstützt.

TIOCNOTTY

Trennen Sie den aufrufenden Prozess von seinem steuernden Terminal.

Wenn der Prozess der Sitzungsleiter, dann SIGHUPund SIGCONTSignale werden in den Vordergrund Prozessgruppe gesendet und alle Prozesse in der aktuellen Sitzung ihre Controlling tty verlieren.

Dieser ioctl(2)Aufruf funktioniert nur mit Dateideskriptoren, die mit / dev / tty verbunden sind . Es wird von Dämonprozessen verwendet, wenn sie von einem Benutzer an einem Terminal aufgerufen werden. Der Prozess versucht, / dev / tty zu öffnen . Wenn das Öffnen erfolgreich ist, löst es sich mithilfe von vom Terminal. TIOCNOTTYWenn das Öffnen fehlschlägt, ist es offensichtlich nicht an ein Terminal angeschlossen und muss sich nicht trennen.

Dies würde zum Teil erklären, warum /dev/ttykein Symlink zum steuernden Terminal vorhanden ist: Es würde ein zusätzliches unterstützen ioctl, und es gibt möglicherweise kein steuerndes Terminal (aber ein Prozess kann immer versuchen, darauf zuzugreifen /dev/tty). Die Dokumentation ist jedoch falsch: Die zusätzliche ioctlist nicht nur über zugänglich /dev/tty(siehe die Antwort von mosvy , die auch eine vernünftigere Erklärung für die Art von gibt /dev/tty).

/dev/tty kann verschiedene steuernde Terminals darstellen, ohne eine Verbindung zu sein, da der Treiber, der sie implementiert, bestimmt, was das steuernde Terminal des aufrufenden Prozesses ist, falls vorhanden.

Sie können sich dies als /dev/ttydas steuernde Terminal vorstellen und somit Funktionen anbieten, die nur für ein steuerndes Terminal sinnvoll sind, während /dev/pts/2usw. einfache Terminals sind, von denen eines das steuernde Terminal für einen bestimmten Prozess sein kann.

Stephen Kitt
quelle
Vielen Dank. Wenn ein Prozess kein steuerndes Terminal hat, was bedeutet /dev/ttydas für den Prozess?
Tim
@ Tim Dann kann es nicht geöffnet werden. Bitte lesen Sie die Manpage sorgfältig durch.
22 薯条 德里克
3

/dev/tty ist ein "magisches" Zeichengerät, das beim Öffnen einen Griff zum aktuellen Terminal zurückgibt.

Unter der Annahme, dass sich das steuernde Terminal befindet /dev/pts/1, verweist ein über /dev/pts/1und einer über geöffneter Dateideskriptor /dev/ttyauf dasselbe Gerät. Jeder Schreib-, Lese- oder andere Dateivorgang funktioniert bei beiden gleich.

Insbesondere akzeptieren sie den gleichen Satz von Ioctls und TIOCNOTTYsind kein zusätzliches Ioctl, das nur über verfügbar ist/dev/tty .

ioctl(fd, TIOCNOTTY) funktioniert auf allen Dateideskriptoren, die sich auf ein Terminal beziehen, genauso, vorausgesetzt, es ist das steuernde Terminal des Prozesses, der es aufruft.

Dabei spielt es keine Rolle , ob der Deskriptor durch Öffnen erhalten wurde /dev/tty, /dev/pts/1, /dev/ptmx(in diesem Fall der ioctl auf seinem entsprechenden handeln Slave ), oder in jüngerer Zeit durch einen Aufruf ioctl(master, TIOCGPTPEER, flags).

Beispiel:

$ 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

Außerdem wird der aktuelle Prozess nicht wirklich vom tty "getrennt". Der Prozess kann weiterhin daraus lesen, ein ^Cauf dem Terminal wird ihn töten usw. Die einzige Auswirkung auf einen Prozess, der kein Sitzungsleiter ist, besteht darin, dass auf die tty nicht mehr über zugegriffen werden /dev/ttykann und dies auch nicht mehr der Fall ist aufgeführt als steuernde tty in /proc/PID/stat:

$ ./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

[Das 7. Feld von /proc/<pid>/statist die Geräte-ID des steuernden Tty, siehe proc(5)]

Wenn der Prozess, der ihn aufruft, der Sitzungsleiter ist, trennt er die Sitzung wirklich vom tty und sendet von der Sitzung ein SIGHUP/ SIGCONTpair an die Vordergrundprozessgruppe. Aber selbst dann wird das Terminal nicht geschlossen und der Prozess kann immer noch daraus lesen, wenn er Folgendes überlebt 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/ttyist kein Symlink wie /dev/stdin=> /dev/fd/0=> /proc/self/fd/0=>, /dev/pts/0da er lange vor virtuellen dynamischen Dateisystemen wie procfs (und lange vor Symlinks im Allgemeinen) erfunden wurde. Und viele Programme haben sich auf ihrer besonderen Semantik abhängen (zB. /dev/ttyAndernfalls mit , ENODEVwenn der Steueranschluss ist nicht zugänglich).

Mosvy
quelle
Danke, macht es Ihnen etwas aus, wenn ich einen Patch zur Verdeutlichung der Manpage einreiche?
Stephen Kitt
Das wäre toll. Das früheste System, auf dem ich dies getestet habe, war RedHat 5.1 (Linux 2.0.34) von 21 Jahren. Ich weiß nicht, ob frühere Versionen wirklich wie von dieser Manpage vorgeschlagen funktioniert haben.
Mosvy
Ich glaube nicht, dass die Manpage jemals richtig war, der ttyCode wurde TTIOCNOTTYseit Ewigkeiten generisch behandelt.
Stephen Kitt
Danke für deine Antwort. Das ist süß
Tim
1
@ d9ngle Die Situation ist anders. Die Befehle, mit denen begonnen wurde &(entweder echte Hintergrundjobs oder Background-Lite wie aus Skripten, Shells ohne Jobsteuerung usw.), sind immer noch an das steuernde Terminal "angehängt", sie geben nicht einmal vor, sich davon zu lösen.
Mosvy