
No Lubuntu 18.04, executo um shell no lxterminal. Seu terminal de controle é o escravo pseudoterminal atual:
$ tty
/dev/pts/2
Gostaria de saber quais são as relações entre meu terminal de controle atual /dev/pts/2
e o /dev/tty
.
/dev/tty
atua como meu terminal de controle atual/dev/pts/2
:$ echo hello > /dev/tty hello $ cat < /dev/tty world world ^C
Mas eles parecem ser arquivos não relacionados, em vez de um ser um link simbólico ou hardlink para o outro:
$ 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
Para sessões diferentes com terminais de controle diferentes,
/dev/tty
é garantido que sejam seus terminais de controle. Como podem ser diferentes terminais de controle, sem ser um link simbólico ou hardlink?
Então, quais são suas relações e diferenças? Qualquer ajuda é muito apreciada!
Esta postagem é originada de uma anteriorA saída do comando `tty` e o arquivo `/dev/tty` referem-se ao terminal de controle do processo bash atual?
Responder1
A tty
página de manual na seção 4afirma o seguinte:
O arquivo/dev/ttyé um arquivo de caracteres com número maior 5 e número menor 0, geralmente no modo 0666 e proprietário.grupo root.tty. É sinônimo de terminal de controle de um processo, se houver.
Em adição a
ioctl(2)
solicitações suportadas pelo dispositivo ao qual tty se refere, oioctl(2)
solicitaçãoTIOCNOTTY
é suportada.
TIOCNOTTY
Desconecte o processo de chamada de seu terminal de controle.
Se o processo for o líder da sessão, então
SIGHUP
osSIGCONT
sinais serão enviados para o grupo de processos em primeiro plano e todos os processos na sessão atual perderão seu tty de controle.Esse
ioctl(2)
call funciona apenas em descritores de arquivo conectados a /dev/tty. É usado por processos daemon quando são invocados por um usuário em um terminal. O processo tenta abrir/dev/tty. Se a abertura for bem-sucedida, ele se desconecta do terminal usandoTIOCNOTTY
, enquanto se a abertura falhar, obviamente não está conectado a um terminal e não precisa se desconectar.
Isso explicaria em parte por que /dev/tty
não existe um link simbólico para o terminal de controle: ele suportaria um adicional ioctl
e pode não haver um terminal de controle (mas um processo sempre pode tentar acessar /dev/tty
). Mas a documentação está incorreta: o adicional ioctl
não está acessível apenasatravés da /dev/tty
(verresposta de Mosvy, o que também dá uma explicação mais sensata para a natureza de /dev/tty
).
/dev/tty
pode representar diferentes terminais de controle, sem ser um link, pois o driver que o implementa determina qual é o terminal de controle do processo chamador, se houver.
Você pode pensar nisso como /dev/tty
sendo o terminal de controle e, portanto, oferecendo funcionalidades que só fazem sentido para um terminal de controle, enquanto /dev/pts/2
etc. são terminais simples, um dos quais pode ser o terminal de controle para um determinado processo.
Responder2
/dev/tty
é um dispositivo de caracteres "mágico" que, quando aberto, retornará um identificador para o terminal atual.
Supondo que o terminal de controle seja /dev/pts/1
, um descritor de arquivo aberto via /dev/pts/1
e um descritor aberto via /dev/tty
se referirão ao mesmo dispositivo; qualquer operação de gravação, leitura ou outra operação de arquivo funcionará da mesma forma em qualquer um deles.
Em particular, eles aceitarão o mesmo conjunto de ioctls, e TIOCNOTTY
não é um ioctl extra disponível apenas via/dev/tty
.
ioctl(fd, TIOCNOTTY)
funciona da mesma forma em qualquer descritor de arquivo referente a um terminal, desde que seja o terminal controlador do processo que o chama.
Não importa se o descritor foi obtido abrindo /dev/tty
, /dev/pts/1
, /dev/ptmx
(nesse caso o ioctl atuará em seu correspondenteescravo), ou mais recentemente, por uma chamada para ioctl(master, TIOCGPTPEER, flags)
.
Exemplo:
$ 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
Além disso, não "separará" realmente o processo atual do tty; o processo ainda será capaz de lê-lo, um ^C
no terminal irá matá-lo, etc. Seu único efeito em um processo que não é um líder de sessão é que o tty não estará mais acessível via /dev/tty
, e não será mais listado como o tty controlador em /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
[o 7º campo /proc/<pid>/stat
é o ID do dispositivo do tty de controle, consulte proc(5)
]
Se o processo que o chama for o líder da sessão, ele realmente separará a sessão do tty e enviará um par SIGHUP
/ SIGCONT
para o grupo de processos em primeiro plano da sessão. Mas mesmo assim, o terminal iránãoserá fechado e o processo ainda poderá lê-lo, se sobreviver ao 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
não é um link simbólico como /dev/stdin
=> /dev/fd/0
=> /proc/self/fd/0
=> /dev/pts/0
porque foi inventado muito antes dos sistemas de arquivos dinâmicos virtuais como o procfs (e muito antes dos links simbólicos em geral). E muitos programas passaram a depender de sua semântica específica (por exemplo, /dev/tty
falhando ENODEV
quando o terminal de controle não está acessível).