Jakie są obowiązki każdego komponentu Pseudo-Terminal (PTY) (oprogramowanie, strona master, strona slave)?

59

Próbuję dowiedzieć się, jak działa tty 1 (przepływ pracy i obowiązki każdego elementu). Przeczytałem kilka ciekawych artykułów na ten temat, ale wciąż są pewne rozmyte obszary.

Oto co rozumiem do tej pory:

  • Emulowany terminal wykonuje różne wywołania systemowe do /dev/ptmx, głównej części pseudo-terminala.
  • Część główna pseudo terminala przydziela plik /dev/pts/[0-N]odpowiadający przestarzałemu portowi szeregowemu i „dołącza” do niego pseudo terminal podrzędny.
  • Pseudo terminal podrzędny przechowuje takie informacje, jak identyfikator sesji, zadanie na pierwszym planie, rozmiar ekranu.

Oto moje pytania:

  1. Czy ptmx ma jakiś cel poza przydzieleniem części podrzędnej? Czy zapewnia jakąś „inteligencję” , czy emulowany terminal (na przykład xterm) ma całą inteligencję zachowywania się jak terminal?
  2. Dlaczego xterm musi wchodzić w interakcje z częścią główną, ponieważ przesyła tylko standardowe wejście i standardowe wejście części podrzędnej? Dlaczego nie może bezpośrednio pisać i czytać z pliku pts ?
  3. Czy identyfikator sesji jest zawsze dołączany do jednego pliku pts i odwrotnie? Czy mogę wpisać polecenie ps i znaleźć 2 sessionId dla tego samego / dev / pts / X ?
  4. Jakie inne informacje ptsprzechowuje sklep? Czy Xterm samodzielnie aktualizuje wszystkie pola, czy też ptmdodaje trochę „inteligencji”?

1. Opieram swoje zrozumienie na TTY zdemistyfikowanym przez Linusa Akessona i jądrze Linuksa autorstwa postów Andriesa Brouwera , podobnie jak na kilku innych pytaniach na tych stronach

Pierre-Jean
źródło

Odpowiedzi:

58

Emulatory terminali

Strona master zastępuje linię (parę przewodów TX / RX), która przechodzi do terminala.

Terminal wyświetla znaki, które otrzymuje na jednym z drutów (niektóre z nich są znakami kontrolnymi i sprawiają, że robi on takie rzeczy, jak przesuwanie kursora, zmiana koloru ...) i wysyła na innym przewodzie znaki odpowiadające wpisanym klawiszom.

Emulatory terminali, takie jak xterm, nie różnią się, z wyjątkiem tego, że zamiast wysyłać i odbierać znaki na przewodach, odczytują i zapisują znaki ze swojego deskryptora pliku po stronie master. Po tym, jak odrodzili terminal niewolników i uruchomili na nim twoją powłokę, już go nie dotykają. Oprócz emulacji pary przewodów, xterm może również zmienić niektóre właściwości dyscypliny linii za pomocą tego deskryptora pliku na stronę główną. Na przykład mogą zaktualizować atrybuty rozmiaru, aby SIGWINCH został wysłany do aplikacji, które wchodzą w interakcję z urządzeniem slave, aby powiadomić ich o zmianie rozmiaru.

Poza tym w terminalu / emulatorze terminali jest mało inteligencji .

To, co piszesz na urządzeniu końcowym (takim jak pty slave), jest tym, co masz na myśli, aby tam zostać wyświetlone, co odczytujesz z tego, co tam napisałeś, więc emulator terminala nie ma sensu czytać ani pisać na tym urządzeniu . Są tymi na drugim końcu.


Dyscyplina linii tty

Dużo inteligencji jest w tej dyscyplinie linii tty . Dyscyplina liniowa to moduł oprogramowania (rezydujący w sterowniku, w jądrze) wciśnięty na urządzenie szeregowe / pty, które znajduje się między tym urządzeniem a linią / przewodem (strona master dla pty).

Linia szeregowa może mieć terminal na drugim końcu, ale także mysz lub inny komputer do pracy w sieci. Możesz dołączyć dyscyplinę linii SLIP, na przykład, aby uzyskać interfejs sieciowy na urządzeniu szeregowym (lub urządzeniu pty), lub możesz mieć dyscyplinę linii tty . Dyscyplina linii tty jest domyślną dyscypliną linii przynajmniej w Linuksie dla urządzeń szeregowych i pty. W systemie Linux możesz zmienić dyscyplinę linii ldattach.

Możesz zobaczyć efekt wyłączenia dyscypliny linii tty, wydając stty raw -echo(zauważ, że monit bash lub inne interaktywne aplikacje, takie jak viustaw terminal w dokładnie tym trybie, którego potrzebują, więc chcesz użyć głupiej aplikacji, takiej jak catta). Następnie wszystko, co jest zapisywane w urządzeniu końcowym slave, powoduje, że xterm od razu przechodzi do strony master, a każdy znak zapisany przez xterm do strony master jest natychmiast dostępny do odczytu z urządzenia slave.

W dyscyplinie liniowej jest implementowany wewnętrzny edytor linii urządzenia końcowego . Na przykład za pomocą stty icanon echo(jak jest to ustawienie domyślne), gdy apiszesz, xterm zapisuje ado mastera, a następnie dyscyplina liniowa powtarza go z powrotem ( audostępnia do odczytu xtermdo wyświetlenia), ale nie udostępnia niczego do czytania po stronie slave . Następnie po wpisaniu Backspace, xterm wysyła ^?lub ^Hcharakter, dyscyplinę linii (jako że ^?albo ^Hodpowiada eraseustawieniu dyscypliny linia) wysyła z powrotem na opanować ^H, spacea ^Hdla xtermwymazaćawłaśnie wpisane na swoim ekranie i nadal nie wysyła nic do wniosku czytając od strony Slave, to po prostu aktualizuje swój wewnętrzny bufor edytora linia usunięcie że amasz wpisane wcześniej.

Następnie, gdy naciśniesz Enter, xterm wysyła ^M(CR), które dyscyplina liniowa konwertuje na wejściu do ^ J (LF), i wysyła to, co do tej pory wprowadziłeś do czytania po stronie slave (odczyt aplikacji /dev/pts/xotrzyma to, co wpisałeś w tym LF, ale nie aodkąd go usunąłeś), podczas gdy po stronie wzorcowej wysyła CR i LF, aby przesunąć kursor do następnej linii i początku ekranu.

Dyscyplina liniowa jest również odpowiedzialna za wysyłanie SIGINTsygnału do grupy procesów pierwszego planu terminala, gdy odbiera on ^Cznak po stronie master itp.

Wiele interaktywnych aplikacji terminalowych wyłącza większość funkcji tej dyscypliny liniowej, aby sami ją wdrożyć. Ale w każdym razie strzeż się, że terminal ( xterm) ma niewielki udział w tym (z wyjątkiem wyświetlania tego, co ma wyświetlić).

I może istnieć tylko jedna sesja na proces i na urządzenie końcowe. Sesja może mieć dołączony terminal kontrolny, ale nie musi (wszystkie sesje rozpoczynają się bez terminala, dopóki go nie otworzą). xtermW procesie, że widelce wykonać powłokę zwykle utworzyć nową sesję (a więc odłączyć od terminala, na którym uruchomiono xtermze jeśli występuje), otwórz nowy /dev/pts/xto zrodził, przez które dołączenie tego urządzenia terminala do nowej sesji. Następnie wykona powłokę w tym procesie, dzięki czemu powłoka stanie się liderem sesji. Powłoka lub dowolna powłoka interaktywna w tej sesji zwykle żongluje z grupami procesów oraz tcsetpgrp(), aby ustawić zadania pierwszego planu i tła dla tego terminala.

Jeśli chodzi o to, jakie informacje są przechowywane przez urządzenie końcowe z dyscypliną tty (szeregową lub pty) , zazwyczaj to sttypolecenie wyświetla i modyfikuje. Konfiguracja wszystkich dyscyplin: rozmiar ekranu terminala, lokalny, flagi wyjściowe, ustawienia znaków specjalnych (takich jak ^ C, ^ Z ...), prędkość wejściowa i wyjściowa (nie dotyczy ptys). Odpowiada to funkcjom tcgetattr()/, tcsetattr()które w Linuksie mapują na TCGETS/ TCSETSioctls i TIOCGWINSZ/ TIOCSWINSZdla rozmiaru ekranu. Możesz argumentować, że bieżąca grupa procesów pierwszego planu jest inną informacją przechowywaną w urządzeniu końcowym ( tcsetpgrp()/ tcgetpgrp(), TIOC{G,S}PGRPioctls) lub w bieżącym buforze wejściowym lub wyjściowym.

Pamiętaj, że informacje o rozmiarze ekranu przechowywane w urządzeniu końcowym mogą nie odzwierciedlać rzeczywistości. Emulator terminala zwykle ustawia go (za pomocą tego samego ioctl w rozmiarze głównym), gdy jego okno jest zmieniane, ale może się nie zsynchronizować, jeśli aplikacja wywoła ioctl po stronie slave lub gdy zmiana rozmiaru nie zostanie przesłana (w przypadku połączenia ssh, które implikuje inny pty spawnowany przez, sshdjeśli na przykład sshignoruje SIGWINCH). Rozmiar niektórych terminali można również zapytać o sekwencje specjalne, więc aplikacja może w ten sposób zapytać o to i zaktualizować dyscyplinę liniową o te informacje.

Aby uzyskać więcej informacji, możesz na przykład spojrzeć na strony termiosi tty_ioctlman w Debianie.

Aby grać z innymi dyscyplinami liniowymi:

  1. Emuluj mysz za pomocą pseudo-terminala:

    socat pty,link=mouse fifo:fifo
    sudo inputattach -msc mouse # sets the MOUSE line discipline and specifies protocol
    xinput list # see the new mouse there
    exec 3<> fifo
    printf '\207\12\0' >&3 # moves the cursor 10 pixels to the right
    

    Powyżej strona główna pty jest zakończona przez socat na nazwanym potoku ( fifo). Łączymy to fifo z procesem (powłoką), który zapisuje 0x87 0x0a 0x00, co w protokole systemów myszy oznacza no button pressed, delta(x,y) = (10,0). Tutaj my (powłoka) nie emulujemy terminala, ale mysz, 3 bajty, które wysyłamy, nie są odczytywane (potencjalnie przekształcane) przez aplikację z urządzenia końcowego ( mousepowyżej której znajduje się dowiązanie symboliczne socatdo jakiegoś /dev/pts/xurządzenia) , ale należy je interpretować jako zdarzenie wejściowe myszy.

  2. Utwórz interfejs SLIP:

    # on hostA
    socat tcp-listen:12345,reuseaddr pty,link=interface
    # after connection from hostB:
    sudo ldattach SLIP interface
    ifconfig -a # see the new interface there
    sudo ifconfig sl0 192.168.123.1/24
    
    # on hostB
    socat -v -x pty,link=interface tcp:hostA:12345
    sudo ldattach SLIP interface
    sudo ifconfig sl0 192.168.123.2/24
    ping 192.168.123.1 # see the packets on socat output
    

    Powyżej przewód szeregowy jest emulowany socatjako gniazdo TCP pomiędzy hostA a hostB. Dyscyplina linii SLIP interpretuje te bajty wymieniane przez tę linię wirtualną jako pakiety IP w obudowie SLIP do dostarczenia przez sl0interfejs.

Stéphane Chazelas
źródło
1
To najlepsza odpowiedź. Oznaczam to jako słuszne i głosuję za tym. Czy możesz dodać ostatnią część na temat informacji, które sklepy PTS? Zgodnie z tą stroną (rozdział dotyczący konfiguracji urządzenia TTY) , pts przechowują wartości takie jak liczba wierszy i liczba wierszy. Czy są jakieś inne informacje, które przechowuje?
Pierre-Jean,
@ Pierre-Jean, dodał więcej informacji.
Stéphane Chazelas
Chociaż twoja odpowiedź jest zdecydowanie bardziej niż satysfakcjonująca, byłoby interesujące zobaczyć prostszy przykład tego, jak faktycznie tworzysz / dev / pts / M. Próbowałem użyć, cat /dev/ptmx &który otwiera nowy pty, ale potem nie mogę znaleźć powiązanego z nim procesu, więc jak byś go użył? Po drugie próbowałem echo "1" >/dev/ptmx, ale to nic nie dało ... Dlaczego mnie to interesuje? Ponieważ często zdalnie łączy się za pośrednictwem ssh(na przykład), pojawia się błąd PTY allocation request failedlub No controlling tty: open /dev/ttybłąd, który uniemożliwia kontrolę zadania. Byłoby miło lepiej je zrozumieć.
not2qubit
@ user1147688, jak utworzyć pty byłoby innym pytaniem. To jest już za dużo pytań na raz. Ale zobacz swoją ptystronę podręcznika, by poznać szczegóły.
Stéphane Chazelas
@ StéphaneChazelas Małe wyjaśnienia: 1. Więc mówisz, że przepływ jest jak physical term---- tty---- bashna terminalach i pty(m)---- tty---- pty(s)---- bashna emulatorach terminali? Czy ttydyscyplina odpowiadała za echo znaków na terminalu fizycznym? 2. Czy jest to program emulujący terminal, który łączy się z klawiaturą / ekranem w celu zarządzania danymi wejściowymi? 3. Zgodnie z tym, co zrozumiałem, powiedziałeś, że buforowanie linii poleceń bash / wszystkich danych wejściowych terminala odbywa się według ttydyscypliny linii zamiast buforów I / O funkcji CI / O. Czy to jest poprawne?
forumulator
29

Edycja: Od tej odpowiedzi napisałem na moim blogu dedykowany artykuł dla osób, które byłyby zainteresowane bardziej szczegółowymi informacjami.


Po wielu lekturach właśnie to zrozumiałem.

  • Czy ptmx ma jakiś cel poza przydzieleniem części podrzędnej? Czy zapewnia jakąś „inteligencję”, czy emulowany terminal (na przykład xterm) ma całą inteligencję zachowywania się jak terminal?

    /dev/ptmxnie przydziela części podrzędnej : przydziela „pseudo-terminalową część nadrzędną”. / dev / ptmx nie jest głównym pseudo terminalem : jest pseudo terminalowym multiplekserem głównym . Został stworzony ze standardem PTY Unix98, aby uniknąć warunków wyścigu podczas przydzielania pseudo terminala głównego ( źródła ).

    Część główna (ptm) pseudo terminala nie jest reprezentowana w systemie plików. Jest reprezentowany przez deskryptor pliku.

    Część podrzędna (pts) jest reprezentowana przez plik, w /dev/pts/Nktórym Njest liczbą.

    PTS otrzymano z ptm przez kolejne wezwanie grandpt, unlockpt, ptsname., ( Źródło )

    Ptm zastępuje sterownik AUR dedykowany do komunikacji z urządzeniem oraz edycję linii. Więc nie emuluje w żaden sposób terminala, ale zapewnia funkcję edycji linii oraz zapewnia wizualizację i komunikację z pts. ( Źródło )

    Oto wykres tego, czym był TTY podłączony do urządzenia sprzętowego Komunikacja TTY z AUR

    A oto wykres tty podłączonego do ptm Komunikacja TTY z PTM

    Plik ptm obsługuje inne argumenty Ioctl (ISPTM, UNLKPT, TIOCREMOTE, TIOCSIGNAL) niż pts.

  • Dlaczego xterm musi wchodzić w interakcje z częścią główną, ponieważ przesyła tylko standardowe wejście i standardowe wejście części podrzędnej? Dlaczego nie może bezpośrednio pisać i czytać z pliku pts?

    Procesy współdziałają z urządzeniami poprzez akcje wykonywane na pliku wirtualnym (odczyt, zapis, ioctl ..). Sam plik nie istnieje, a sterownik używa go do wyzwalania akcji po wywołaniu metod odczytu lub zapisu. (Informacje o sterownikach znajdują się w załączniku)

    TTY określa precyzyjny sposób interakcji z nim. Procesy zapisują i odczytują z urządzenia i oczekują tego samego zachowania, niezależnie od tego, jaki rodzaj TTY jest zaimplementowany.

    • Funkcja odczytu służy procesom do odczytywania wpisów z terminala
    • Funkcja write służy procesom do wysyłania danych wyjściowych do terminala

    Pts zachowują się jak sterownik TTY. Jego metoda odczytu i zapisu służy do implementacji zachowania sterownika TTY. Ponieważ nie ma rzeczywistego urządzenia do wysyłania danych, tworzona jest para strumienia, a ptm implementuje funkcję odczytu do odczytu danych wysyłanych przez pts do strumienia oraz funkcję zapisu do wysyłania danych do strumienia, który będzie dostępny kiedy pts to przeczytają.

    Pamiętaj, że plik reprezentujący urządzenie nie jest plikiem klasycznym, a jeśli xtermchcesz zobaczyć, co zostało zapisane do pliku, nie można go po prostu nazwać otwartym i odczytać, ponieważ funkcje te mają tutaj zupełnie inne zachowanie.

  • Czy identyfikator sesji zawsze jest dołączony do jednego pliku pts i odwrotnie? Czy mogę wpisać polecenie ps i znaleźć 2 sessionId dla tego samego / dev / pts / X?

    Nie sądzę, identyfikator sesji jest definiowany przez pierwszy proces, który dołącza pts (ogólnie bash), i nie widzę sposobu, aby utworzyć kolejną sesję i dołączyć ją do tych samych pts. Może takie narzędzie socatmoże to zrobić?

  • Jakie inne informacje przechowują pts? Czy Xterm samodzielnie aktualizuje wszystkie pola, czy też ptm dodaje do niego „inteligencję”?

    Pts przechowują 2 kategorie informacji dotyczących terminala, z którym się komunikuje: the Terminfoi the Termcap. Zwykle wiele emulatorów terminali jest opartych na bibliotece, która zarządza dla nich informacjami termcap (które zapewnią wszystkie wartości możliwości na przykład do emulacji VTX100). Przykładem takiej biblioteki jest libvte . Edycja (patrz komentarz Stazane Chazelas): Funkcje terminalu nie są przechowywane przez pts.

Aneks

Pierre-Jean
źródło
termcap i terminfo to bazy danych o możliwościach terminalu lub emulatora terminala, nie mają one nic wspólnego z urządzeniami tty lub pty.
Stéphane Chazelas
Ok, zredaguję moją odpowiedź. Dziękuję za komentarz. Czy możesz dodać tę informację o pts do swojej odpowiedzi, jeśli ją znasz (najwyraźniej pts przechowuje na przykład rozmiar ekranu)?
Pierre-Jean,
6
To są ładne zdjęcia. Jakiego oprogramowania użyłeś do ich stworzenia?
Gilles
5
@Gilles Dziękuję. Zrobiłem je za pomocą Inkscape , edytora grafiki wektorowej typu open source. Być może nie jest to najskuteczniejszy sposób tworzenia tego rodzaju grafiki, ale jeśli jesteś zainteresowany, napisałem artykuł na temat tworzenia tego rodzaju rysunków izometrycznych.
Pierre-Jean
Nie sądzę, żebyś kiedykolwiek mógł dołączyć dwie sesje do kontrolującego terminala lub pozwolić, aby jedna sesja miała więcej niż jeden kontrolujący terminal
炸鱼薯条德里克
9

Oto schemat, który stworzyłem jakiś czas temu, jak sshddziała. Nie dotyczy działania dyscypliny liniowej i innych rzeczy, ale dodaje rzeczywistą ilustrację tego, kto wchodzi w interakcje z tym, co:

wprowadź opis zdjęcia tutaj

Boris Burkov
źródło
bardzo ci za to dziękuję. Spędziłem 2 dni próbując to rozgryźć. Zastanawiam się tylko, co się stanie, gdy żadna pty nie zostanie utworzona. stdin nie istnieje, dobrze, ale gdzie jest napisane stdout i stderr?
mały koleś
@ emmasculateur cieszę się, że ci pomógł. Niestety, nie rozumiem, co masz na myśli przez „gdy żadna pty nie jest tworzona”. Czy możesz podać przykład, kiedy pty nie jest tworzone?
Boris Burkov,
1
Przez „brak instancji pty” mam na myśli, kiedy uruchamiasz ssh -T, co, jak mówi mężczyzna, wyłącza alokację pseudo terminala. np ssh -T emasculateur@localhost "sleep 10" następnie ps aux|grep sleeppokazuje to: emasculateur 21826 0.0 0.0 23032 3728 ? Ss 02:49 0:00 zsh -c sleep 10 W takim razie skąd bash zapisu stdouti stderr? Mam nadzieję, że moje pytanie ma sens.
mały koleś
@ emmasculateur hm, to dobre pytanie, ma sens, po prostu o tym wcześniej nie myślałem. Myślę, że w ten sposób zaczynasz proces jako demon na zdalnej maszynie, bez powiązanego terminala. Domyślam się, że jego standardowe wejście / wyjście / błąd po prostu /dev/nullpolubią normalnego demona, ale nie jestem pewien. Zobacz także: serverfault.com/questions/593399/…
Boris Burkov
@ emmasculateur Natknąłem się również na inny przypadek niż twój: jeśli twój proces miał terminal, ale ten terminal był zamknięty, proces odbierałby SIGHUP z jądra po próbie odczytu / zapisu stdout / stdin. To często zabija zadania, uruchomione przez ssh bez nohuplub screen/ tmux.
Boris Burkov,
0

man pts mówi:

Plik / dev / ptmx jest plikiem znakowym o numerze głównym 5 i podrzędnym 2, zwykle w trybie 0666 i właścicielu. Grupa root.root. Służy do tworzenia pseudoterminalnej pary master i slave.

Kiedy proces otwiera / dev / ptmx, otrzymuje deskryptor pliku dla pseudo-terminala master (PTM), a pseudo-terminal slave (PTS) jest tworzony w katalogu / dev / pts. Każdy deskryptor pliku uzyskany przez otwarcie / dev / ptmx jest niezależnym PTM z własnym powiązanym PTS, którego ścieżkę można znaleźć, przekazując deskryptor do ptsname (3).

Przed otwarciem pseudo-terminala slave, musisz przekazać deskryptor pliku master do grantpt (3) i unlockpt (3).

Po otwarciu zarówno pseudo-terminala master, jak i slave, slave zapewnia procesom interfejs identyczny z interfejsem prawdziwego terminala.

Dane zapisane do urządzenia podrzędnego są przedstawiane w deskryptorze głównym jako dane wejściowe. Dane zapisane do urządzenia nadrzędnego są prezentowane do urządzenia podrzędnego jako dane wejściowe.

W praktyce pseudo-terminale są używane do implementacji emulatorów terminali, takich jak xterm (1), w których dane odczytane z pseudo-terminala master są interpretowane przez aplikację w taki sam sposób, jak prawdziwy terminal interpretowałby dane, oraz do implementacji zdalnej -loginy programy, takie jak sshd (8), w których dane odczytane z pseudo-terminala master są wysyłane przez sieć do programu klienckiego podłączonego do terminala lub emulatora terminala.

Pseudo-terminale mogą być również używane do wysyłania danych wejściowych do programów, które normalnie odmawiają odczytu danych wejściowych z potoków (takich jak su (8) i passwd (8)).

O /dev/pts/X indexing :

każdy X to sesja, którą otworzysz, więc niewolnicy muszą indeksować.

O TeteType (/dev/ttyN ):

Prawdziwa konsola została wygenerowana przez Twój system rozruchowy, taki jak sysV .

O tym, dlaczego slave insted of master: http://commons.wikimedia.org/wiki/File:Termios-script-diagram.png

Zatoka Perska
źródło
Przepraszam, ale nie odpowiedziałeś na pytania. Przeczytałem już stronę podręcznika i widzę ten wykres, ale zachowanie nie było jasne. Czy potrafisz, jak sugeruje illuminé, rozszerzyć swoją odpowiedź zgodnie z pytaniami?
Pierre-Jean,
Przepraszam za
Aby korzystać z podsystemu pseudo-TTY, należy zainstalować węzeł dla sterownika nadrzędnego / dev / ptmx i N liczby sterowników podrzędnych (N określa się podczas instalacji). Nazwy urządzeń podrzędnych to / dev / pts / M, gdzie M ma wartości od 0 do N-1. Użytkownik uzyskuje dostęp do urządzenia pseudo-TTY za pośrednictwem urządzenia głównego (zwanego ptm), które z kolei jest dostępne za pośrednictwem sterownika klonowania. Urządzenie główne jest skonfigurowane jako urządzenie klonujące, w którym jego główny numer urządzenia jest główny dla urządzenia klonującego i jego podrzędny numer urządzenia jest głównym sterownikiem ptm.
PersianGulf
tak, czytam stronę pan pan ....!
PersianGulf