
En Lubuntu 18.04, ejecuto un shell en lxterminal. Su terminal de control es el pseudoterminal esclavo actual:
$ tty
/dev/pts/2
Me gustaría saber qué relaciones hay entre mi terminal de control actual /dev/pts/2
y /dev/tty
.
/dev/tty
actúa como mi terminal de control actual/dev/pts/2
:$ echo hello > /dev/tty hello $ cat < /dev/tty world world ^C
Pero parecen ser archivos no relacionados, en lugar de que uno sea un enlace simbólico o un enlace físico al otro:
$ 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 diferentes sesiones con diferentes terminales de control, se
/dev/tty
garantiza que serán sus terminales de control. ¿Cómo pueden ser diferentes terminales de control, sin ser un enlace simbólico o un enlace físico?
¿Cuáles son entonces sus relaciones y diferencias? ¡Cualquier ayuda es muy apreciada!
Esta publicación se originó a partir de una anterior.¿La salida del comando `tty` y el archivo `/dev/tty` se refieren a la terminal de control del proceso bash actual?
Respuesta1
La tty
página de manual en la sección 4afirma lo siguiente:
El archivo/desarrollo/ttyes un archivo de caracteres con número mayor 5 y número menor 0, generalmente de modo 0666 y propietario.grupo raíz.tty. Es sinónimo de terminal controlador de un proceso, si lo hay.
Además de
ioctl(2)
solicitudes admitidas por el dispositivo al que se refiere tty, elioctl(2)
TIOCNOTTY
Se admite la solicitud .
TIOCNOTTY
Separe el proceso de llamada de su terminal de control.
Si el proceso es el líder de la sesión, entonces se
SIGHUP
envíanSIGCONT
señales al grupo de procesos de primer plano y todos los procesos en la sesión actual pierden su tty de control.Este
ioctl(2)
La llamada funciona solo en descriptores de archivos conectados a /desarrollo/tty. Lo utilizan los procesos demonio cuando son invocados por un usuario en una terminal. El proceso intenta abrir/desarrollo/tty. Si la apertura tiene éxito, se desconecta del terminal usandoTIOCNOTTY
, mientras que si la apertura falla, obviamente no está conectado a un terminal y no necesita desconectarse.
Esto explicaría en parte por qué /dev/tty
no hay un enlace simbólico al terminal de control: admitiría un ioctl
, y podría no haber un terminal de control (pero un proceso siempre puede intentar acceder /dev/tty
). Sin embargo, la documentación es incorrecta: ioctl
no solo se puede acceder al adicionala través de /dev/tty
(verla respuesta de mosvy, que también da una explicación más sensata de la naturaleza de /dev/tty
).
/dev/tty
puede representar diferentes terminales de control, sin ser un enlace, porque el controlador que lo implementa determina cuál es el terminal de control del proceso que llama, si lo hay.
Puede pensar en esto como /dev/tty
si fuera el terminal de control y, por lo tanto, ofrece una funcionalidad que solo tiene sentido para un terminal de control, mientras que /dev/pts/2
etc. son terminales simples, uno de los cuales podría ser el terminal de control de un proceso determinado.
Respuesta2
/dev/tty
es un dispositivo de carácter "mágico" que, cuando se abre, devolverá un identificador al terminal actual.
Suponiendo que el terminal de control es /dev/pts/1
, un descriptor de archivo abierto mediante /dev/pts/1
y uno abierto mediante /dev/tty
se referirán al mismo dispositivo; cualquier operación de escritura, lectura u otra operación de archivo funcionará igual en cualquiera de ellos.
En particular, aceptarán el mismo conjunto de ioctls y TIOCNOTTY
no es un ioctl adicional que solo esté disponible a través de/dev/tty
.
ioctl(fd, TIOCNOTTY)
funciona igual en cualquier descriptor de archivo que haga referencia a una terminal, siempre que sea la terminal controladora del proceso que lo llama.
No importa si el descriptor se obtuvo abriendo /dev/tty
, /dev/pts/1
, /dev/ptmx
(en cuyo caso el ioctl actuará sobre su correspondienteesclavo), o más recientemente, mediante una llamada a ioctl(master, TIOCGPTPEER, flags)
.
Ejemplo:
$ 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
Además, en realidad no "separará" el proceso actual del tty; el proceso aún podrá leerlo, un botón ^C
en el terminal lo eliminará, etc. Su único efecto en un proceso que no es líder de sesión es que ya no se podrá acceder al tty a través de /dev/tty
, y ya no será aparece como el tty controlador en /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
[el séptimo campo /proc/<pid>/stat
es la identificación del dispositivo del tty controlador, consulte proc(5)
]
Si el proceso que lo llama es el líder de la sesión, realmente separará la sesión del tty y enviará un par SIGHUP
/ SIGCONT
al grupo de procesos de primer plano de la sesión. Pero incluso entonces, el terminalnose cerrará y el proceso aún podrá leerlo, si sobrevive a 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
no es un enlace simbólico como /dev/stdin
=> /dev/fd/0
=> /proc/self/fd/0
=> /dev/pts/0
porque se inventó mucho antes que los sistemas de archivos dinámicos virtuales como procfs (y mucho antes que los enlaces simbólicos en general). Y muchos programas han llegado a depender de su semántica particular (por ejemplo, /dev/tty
fallar ENODEV
cuando el terminal de control no es accesible).