Quais são as responsabilidades de cada componente do pseudo-terminal (PTY) (software, lado mestre, lado escravo)?

59

Estou tentando descobrir como um tty funciona 1 (o fluxo de trabalho e as responsabilidades de cada elemento). Eu li vários artigos interessantes sobre isso, mas ainda existem algumas áreas embaçadas.

Isto é o que eu entendo até agora:

  • O terminal emulado faz chamadas diferentes do sistema para /dev/ptmxa parte principal do pseudo-terminal.
  • A parte principal do pseudo terminal aloca um arquivo /dev/pts/[0-N], correspondente à porta serial obsoleta, e "anexa" um pseudo terminal escravo a ela.
  • O pseudo terminal escravo mantém informações como ID da sessão, trabalho em primeiro plano, tamanho da tela.

Aqui estão as minhas perguntas:

  1. O ptmx tem algum objetivo além de alocar a parte escrava? Ele fornece algum tipo de "inteligência" , ou o terminal emulado (xterm por exemplo) tem toda a inteligência de se comportar como um terminal?
  2. Por que o xterm precisa interagir com a parte principal, pois apenas encaminha o stdout e o stdin da parte escrava? Por que ele não pode escrever e ler diretamente do arquivo pts ?
  3. Um ID de sessão está sempre anexado a um arquivo de pts e vice-versa? Eu poderia digitar um comando ps e encontrei 2 sessionId para o mesmo / dev / pts / X ?
  4. Que outras informações a ptsloja guarda? O Xterm atualiza todos os campos sozinho ou ptmadiciona alguma "inteligência" a ele?

1. Baseei meu entendimento no TTY desmistificado por Linus Akesson e no Linux Kernel por Andries Brouwer , como em várias outras perguntas nesses sites

Pierre-Jean
fonte

Respostas:

58

Emuladores de terminal

O lado mestre substitui a linha (o par de fios TX / RX) que vai para o terminal.

O terminal exibe os caracteres que recebe em um dos fios (alguns são caracteres de controle e o fazem fazer coisas como mover o cursor, mudar de cor ...) e envia em outro fio os caracteres correspondentes às teclas digitadas.

Emuladores de terminal como o xterm não são diferentes, exceto que, em vez de enviar e receber caracteres nos fios, eles lêem e escrevem caracteres no descritor de arquivo para o lado mestre. Uma vez que eles geraram o terminal escravo, e iniciaram seu shell nisso, eles não tocam mais nisso. Além de emular o par de fios, o xterm também pode alterar algumas das propriedades da disciplina de linha por meio do descritor de arquivo para o lado mestre. Por exemplo, eles podem atualizar os atributos de tamanho para que um SIGWINCH seja enviado aos aplicativos que interagem com o escravo para notificá-los sobre um tamanho alterado.

Fora isso, há pouca inteligência no terminal / emulador de terminal.

O que você escreve em um dispositivo terminal (como o escravo pty) é o que você quer que seja exibido lá, o que você lê nele é o que você digitou lá, portanto, não faz sentido que o emulador de terminal leia ou grave nele . Eles são os que estão do outro lado.


A disciplina tty line

Uma boa parte da inteligência está na disciplina linha tty . A disciplina de linha é um módulo de software (residente no driver, no kernel) colocado em cima de um dispositivo serial / pty que fica entre esse dispositivo e a linha / fio (o lado principal de um pty).

Uma linha serial pode ter um terminal na outra extremidade, mas também um mouse ou outro computador para conexão em rede. Você pode anexar uma disciplina de linha SLIP, por exemplo, para obter uma interface de rede em cima de um dispositivo serial (ou dispositivo pty), ou pode ter uma disciplina de linha tty . A disciplina de linha tty é a disciplina de linha padrão, pelo menos no Linux, para dispositivos seriais e pty. No Linux, você pode alterar a disciplina da linha com ldattach.

Você pode ver o efeito de desabilitar a disciplina de linha tty emitindo stty raw -echo(observe que o prompt do bash ou outros aplicativos interativos, como vio terminal, definem o modo exato de que precisam, portanto, você deseja usar um aplicativo idiota que gosta catde experimentar isso). Então, tudo o que é gravado no dispositivo terminal escravo chega imediatamente ao lado mestre para o xterm ler, e todos os caracteres gravados pelo xterm no lado mestre ficam imediatamente disponíveis para leitura no dispositivo escravo.

A disciplina de linha é onde o editor de linha interno do dispositivo de terminal é implementado. Por exemplo, com stty icanon echo(como é o padrão), quando você digita a, xterm grava ano mestre, a disciplina de linha o ecoa de volta (torna adisponível para leitura por xtermpara exibição), mas não disponibiliza nada para leitura no lado escravo . Então, se você digita backspace, xterm envia um ^?ou ^Hcaráter, a disciplina de linha (como que ^?ou ^Hcorresponde à erasedefinição de linha de disciplina) envia de volta no mestre um ^H, spacee ^Hpara xtermapagar aavocê acabou de digitar na tela e ainda não envia nada para o aplicativo lendo do lado escravo, apenas atualiza seu buffer interno do editor de linha para remover o que avocê digitou anteriormente.

Então, quando você pressiona Enter, o xterm envia ^M(CR), que a disciplina de linha converte na entrada para ^ ^ (LF) e envia o que você inseriu até agora para leitura no lado escravo (um aplicativo lendo /dev/pts/xreceberá o que você digitou incluindo o LF, mas não o adesde que o excluiu); enquanto no lado mestre, ele envia um CR e LF para mover o cursor para a próxima linha e o início da tela.

A disciplina de linha também é responsável por enviar o SIGINTsinal para o grupo de processos em primeiro plano do terminal quando recebe um ^Ccaractere no lado mestre etc.

Muitos aplicativos de terminal interativos desativam a maioria dos recursos dessa disciplina de linha para implementá-los. Mas, em qualquer caso, lembre-se de que o terminal ( xterm) tem pouco envolvimento nisso (exceto exibindo o que é solicitado para exibir).

E pode haver apenas uma sessão por processo e por dispositivo terminal. Uma sessão pode ter um terminal de controle conectado a ela, mas não é necessário (todas as sessões começam sem um terminal até abrirem um). xterm, no processo em que você executa a execução de seu shell normalmente criará uma nova sessão (e, portanto, será desconectada do terminal de onde você iniciou xterm), abra a nova /dev/pts/xgerada, conectando esse dispositivo à nova sessão. Ele executará seu shell nesse processo, para que ele se torne o líder da sessão. Seu shell ou qualquer shell interativo nessa sessão normalmente faz malabarismos com grupos de processos e tcsetpgrp(), para definir os trabalhos de primeiro e segundo plano para esse terminal.

Quanto às informações armazenadas por um dispositivo terminal com uma disciplina tty (serial ou pty) , normalmente é o que o sttycomando exibe e modifica. Toda a configuração da disciplina: tamanho da tela do terminal, local, sinalizadores de saída de entrada, configurações para caracteres especiais (como ^ C, ^ Z ...), velocidade de entrada e saída (não relevante para ptys). Isso corresponde às funções tcgetattr()/ tcsetattr()que no Linux são mapeadas para TCGETS/ TCSETSioctls e TIOCGWINSZ/ TIOCSWINSZpara o tamanho da tela. Você pode argumentar que o grupo de processos atual em primeiro plano é outra informação armazenada no dispositivo terminal ( tcsetpgrp()/ tcgetpgrp(), TIOC{G,S}PGRPioctls) ou no buffer de entrada ou saída atual.

Observe que as informações de tamanho de tela armazenadas no dispositivo terminal podem não refletir a realidade. O emulador de terminal normalmente o define (através do mesmo ioctl no tamanho principal) quando sua janela é redimensionada, mas pode ficar fora de sincronia se um aplicativo chamar o ioctl no lado escravo ou quando o redimensionamento não for transmitido (no caso de uma conexão ssh que implica outro pty gerado por sshdse sshignora o, SIGWINCHpor exemplo). Alguns terminais também podem ser consultados em seu tamanho por meio de seqüências de escape, para que um aplicativo possa consultá-lo dessa maneira e atualizar a disciplina de linha com essas informações.

Para mais detalhes, você pode dar uma olhada nas páginas de manual termiose tty_ioctlno Debian, por exemplo.

Para jogar com outras disciplinas de linha:

  1. Emule um mouse com um pseudo-terminal:

    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
    

    Acima, o lado mestre do pty é finalizado por socat em um pipe nomeado ( fifo). Nós conectamos esse fifo a um processo (o shell) que grava 0x87 0x0a 0x00, o que significa no protocolo dos sistemas de mouse no button pressed, delta(x,y) = (10,0). Aqui, nós (o shell) não estamos emulando um terminal, mas um mouse, os 3 bytes que enviamos não devem ser lidos (potencialmente transformados) por um aplicativo do dispositivo terminal ( mouseacima do qual é um link simbólico feito por socatalgum /dev/pts/xdispositivo) , mas devem ser interpretados como um evento de entrada do mouse.

  2. Crie uma interface 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
    

    Acima, o fio serial é emulado socatcomo um soquete TCP entre o hostA e o hostB. A disciplina de linha SLIP interpreta os bytes trocados nessa linha virtual como pacotes IP encapsulados em SLIP para entrega na sl0interface.

Stéphane Chazelas
fonte
11
Esta é a melhor resposta. Eu o marquei como correto e voto-o. Você pode adicionar a última parte sobre informações que pts armazena? De acordo com esta página (capítulo configurando o dispositivo TTY) , os pts armazenam valores como número de linhas e número de linhas. São outras informações que ele armazena?
Pierre-Jean
@ Pierre-Jean, adicionou mais informações.
Stéphane Chazelas
Embora sua resposta seja muito além da satisfatória, seria interessante ver um exemplo mais simples de como você realmente cria um / dev / pts / M. Eu tentei usar o cat /dev/ptmx &que abre um novo pty, mas não há um processo que eu possa encontrar associado a ele, então como você o usaria? Segundo eu tentei echo "1" >/dev/ptmx, mas isso não fez nada ... Por que estou interessado nisso? Porque muitas vezes quando alguém se conecta remotamente via ssh(por exemplo), você recebe PTY allocation request failedou No controlling tty: open /dev/ttyerro, o que impede o controle do trabalho. Seria bom entender melhor isso.
precisa saber é o seguinte
@ user1147688, como criar um pty seria uma pergunta diferente. Esta já é muitas perguntas de cada vez. Mas veja sua ptypágina de manual para detalhes.
Stéphane Chazelas
@ StéphaneChazelas Pequenos esclarecimentos: 1. Então você está dizendo que o fluxo é como physical term---- tty---- bashnos terminais e pty(m)---- tty---- pty(s)---- bashnos emuladores de terminais? A ttydisciplina também foi responsável pelo eco dos caracteres no terminal físico? 2. É o programa emulador de terminal que se conecta ao teclado / tela para gerenciar as entradas? 3. De acordo com o que entendi, você disse que o buffer de linha dos comandos bash / toda a entrada do terminal é feito por ttydisciplina de linha, em vez de buffers de E / S das funções de CI / O. Isso está correto?
forumulator
29

Edit: Desde esta resposta, escrevi um artigo dedicado no meu blog, para pessoas que estariam interessadas em mais detalhes.


Depois de muita leitura, foi o que eu entendi.

  • O ptmx tem algum objetivo além de alocar a parte escrava? Ele fornece algum tipo de "inteligência", ou o terminal emulado (xterm por exemplo) tem toda a inteligência de se comportar como um terminal?

    /dev/ptmxnão aloca a parte escrava : aloca a "parte principal do pseudo terminal". / dev / ptmx não é o pseudo terminal mestre : é um multiplexador mestre de pseudo terminal . Foi criado com o padrão Unix98 PTY para evitar condições de corrida ao alocar pseudo terminal principal ( fonte ).

    A parte principal (ptm) do pseudo terminal não está representada no sistema de arquivos. É representado por um descritor de arquivo.

    A parte escrava (pts) é representada por um arquivo em /dev/pts/Nque Nestá um número.

    Os pts é obtido a partir da PTM por meio da chamada sucessiva de grandpt, unlockpt, ptsname. ( Fonte )

    O ptm substitui o driver AUR dedicado à comunicação com o dispositivo e a edição de linha. Portanto, ele não emula de forma alguma um terminal, mas fornece o recurso de edição de linha e fornece uma maneira de visualizar e se comunicar com pts. ( Fonte )

    Aqui está um gráfico do que era um TTY conectado a um dispositivo de hardware Comunicação TTY com AUR

    E aqui está um gráfico de um tty conectado a um ptm Comunicação TTY com PTM

    O arquivo ptm manipula diferentes argumentos Ioctl (ISPTM, UNLKPT, TIOCREMOTE, TIOCSIGNAL) que os pts.

  • Por que o xterm precisa interagir com a parte principal, pois apenas encaminha o stdout e o stdin da parte escrava? Por que ele não pode escrever e ler diretamente do arquivo pts?

    Os processos interagem com os dispositivos por meio de ações realizadas em um arquivo virtual (leitura, gravação, ioctl ..). O arquivo em si não existe e o driver usa o arquivo para acionar ações quando métodos de leitura ou gravação são chamados. (Consulte o anexo para obter informações sobre drivers)

    Um TTY define uma maneira precisa de interagir com ele. Os processos gravam e leem do dispositivo e esperam o mesmo comportamento, independentemente do tipo de TTY implementado.

    • A função de leitura é usada pelos processos para ler entradas do terminal
    • A função de gravação é usada pelos processos para enviar a saída para o terminal

    Os pts se comportam como um driver TTY. Seu método de leitura e gravação é usado para implementar o comportamento do driver TTY. Como não há um dispositivo real para enviar os dados, um par de fluxos é criado e o ptm implementa uma função de leitura para ler os dados enviados por pontos ao fluxo e uma função de gravação para enviar dados ao fluxo que estarão disponíveis quando os pts irão lê-lo.

    Lembre-se, o arquivo que representa um dispositivo não é um arquivo clássico e, se xtermquiser ver o que foi gravado no arquivo, ele não pode simplesmente ser chamado de aberto e lido, pois essas funções têm um comportamento completamente diferente aqui.

  • Um ID de sessão sempre está anexado a um arquivo de pts e vice-versa? Eu poderia digitar um comando ps e encontrei 2 sessionId para o mesmo / dev / pts / X?

    Acho que não, o ID da sessão é definido pelo primeiro processo que anexa os pontos (bash geralmente), e não vejo uma maneira de criar outra sessão e anexá-los aos mesmos pontos. Talvez uma ferramenta como socatpoderia fazer isso?

  • Que outras informações os pts armazenam? O Xterm atualiza todos os campos sozinho ou o ptm adiciona alguma "inteligência" a ele?

    Os pts armazenam 2 categorias de informações sobre o terminal com o qual está se comunicando: o Terminfoe o Termcap. Geralmente, muitos emuladores de terminal são baseados em bibliotecas que gerenciam informações de termcap para eles (que fornecerão todos os valores de recursos para emular um VTX100, por exemplo). Um exemplo dessa biblioteca é a libvte . Editar (consulte o comentário de Stephane Chazelas): Os recursos do terminal não são armazenados pelos pts.

Anexo

Pierre-Jean
fonte
termcap e terminfo são bancos de dados sobre recursos de terminal ou emulador de terminal, eles não têm nada a ver com dispositivos tty ou pty.
Stéphane Chazelas
Ok, eu vou editar minha resposta. Obrigado pelo comentário. Você pode adicionar essas informações sobre pontos na sua resposta, se souber (aparentemente os pontos armazenam o tamanho da tela, por exemplo)?
Pierre-Jean
6
Essas são imagens legais. Qual software você usou para produzi-los?
Gilles 'SO- stop be evil'
5
@Gilles Obrigado. Fiz com o Inkscape , um editor de gráficos vetoriais de código aberto. Talvez não seja a maneira mais eficiente de fazer esse tipo de gráfico, mas se você estiver interessado, escrevi um artigo sobre como criar esse tipo de desenho isométrico.
Pierre-Jean
Eu acho que você nunca pode assistir a duas sessões em um terminal de controle ou deixar uma sessão ter mais de um terminal de controle
炸鱼 薯条 德里克
9

Aqui está um esquema que fiz há algum tempo sobre como sshdfunciona. Não diz respeito à operação da disciplina de linha e outras coisas, mas adiciona uma ilustração da vida real de quem interage com o que:

insira a descrição da imagem aqui

Boris Burkov
fonte
muito obrigado por isso. Passei 2 dias tentando descobrir. Só estou imaginando o que acontece quando nenhum pty é instanciado. stdin não existe, tudo bem, mas para onde são gravados stdout e stderr?
31715 little-dude
@emmasculateur feliz por ter ajudado. Desculpe, não consigo entender o que você quer dizer com "quando nenhum pty é instanciado". Você pode dar um exemplo de quando o pty não é instanciado?
Boris Burkov
11
Por "nenhum pty é instanciado", quero dizer quando você executa o ssh com o -Tqual o homem diz que desabilita a alocação de pseudo-terminal. por exemplo: ssh -T emasculateur@localhost "sleep 10" então ps aux|grep sleepmostra o seguinte: emasculateur 21826 0.0 0.0 23032 3728 ? Ss 02:49 0:00 zsh -c sleep 10 Nesse caso, onde o bash escreve stdoute stderr? Espero que minha pergunta faça sentido.
pouco cara
@emmasculateur hm, é uma boa pergunta, faz sentido, eu simplesmente não pensei nisso antes. Acho que é assim que você inicia seu processo como um daemon em uma máquina remota, sem terminal associado. Meu palpite é que sua entrada / saída / erro padrão apenas vai /dev/nullgostar de um daemon normal, mas não tenho certeza. Veja também: serverfault.com/questions/593399/…
Boris Burkov
@emmasculateur Eu também me deparei com um caso diferente do seu: se seu processo costumava ter terminal, mas esse terminal estava fechado, o processo receberia o SIGHUP do kernel na tentativa de leitura / gravação para stdout / stdin. Isso geralmente mata os trabalhos, iniciados via ssh sem nohupou screen/ tmux.
Boris Burkov 01/08/2015
0

man pts diz:

O arquivo / dev / ptmx é um arquivo de caractere com número principal 5 e número menor 2, geralmente no modo 0666 e owner.group de root.root. É usado para criar um par mestre e escravo pseudo-terminal.

Quando um processo abre / dev / ptmx, ele obtém um descritor de arquivo para um pseudo-terminal mestre (PTM), e um dispositivo pseudo-terminal escravo (PTS) é criado no diretório / dev / pts. Cada descritor de arquivo obtido pela abertura de / dev / ptmx é um PTM independente com seu próprio PTS associado, cujo caminho pode ser encontrado passando o descritor para ptsname (3).

Antes de abrir o escravo pseudo-terminal, você deve passar o descritor de arquivo do mestre para conceder (3) e desbloquear (3).

Uma vez que o mestre do pseudo-terminal e o escravo estão abertos, o escravo fornece aos processos uma interface idêntica à de um terminal real.

Os dados gravados no escravo são apresentados no descritor principal como entrada. Os dados gravados no mestre são apresentados ao escravo como entrada.

Na prática, pseudo-terminais são usados ​​para implementar emuladores de terminal como o xterm (1), no qual os dados lidos do mestre do pseudo-terminal são interpretados pelo aplicativo da mesma maneira que um terminal real interpretaria os dados e para implementar remotamente programas de logon como o sshd (8), no qual os dados lidos do mestre do pseudo-terminal são enviados pela rede para um programa cliente conectado a um terminal ou emulador de terminal.

Pseudo-terminais também podem ser usados ​​para enviar entradas para programas que normalmente se recusam a ler entradas de pipes (como su (8) e passwd (8)).

Sobre /dev/pts/X indexing:

cada X é uma sessão que você abre, então os escravos precisam indexar.

Sobre TeteType (/dev/ttyN):

Seu console real foi gerado pelo seu sistema de inicialização, como sysV.

Sobre Por que o escravo instalado no mestre: http://commons.wikimedia.org/wiki/File:Termios-script-diagram.png

PersianGulf
fonte
Sinto muito, mas você não respondeu às perguntas. Eu já li a página de manual e vi este gráfico, mas o comportamento não era claro. Você pode, como sugere o illuminÉ, estender sua resposta de acordo com as perguntas?
Pierre-Jean
Desculpe pela
demora
Para usar o subsistema pseudo-TTY, um nó para o driver do lado mestre / dev / ptmx e N número de drivers escravos (N é determinado na instalação) deve ser instalado. Os nomes dos dispositivos escravos são / dev / pts / M, em que M possui os valores de 0 a N-1. Um usuário acessa um dispositivo pseudo-TTY através do dispositivo principal (chamado ptm), que por sua vez é acessado através do driver clone. número menor de dispositivo é o principal do driver ptm.
Golfo Pérsico
sim eu li man pan page ....!
PersianGulf 17/03/2014