현재 제어 터미널과 `/dev/tty` 사이의 관계는 무엇입니까?

현재 제어 터미널과 `/dev/tty` 사이의 관계는 무엇입니까?

Lubuntu 18.04에서는 lxterminal에서 쉘을 실행합니다. 제어 터미널은 현재 의사 터미널 슬레이브입니다.

$ tty
/dev/pts/2

현재 제어 터미널 /dev/pts/2/dev/tty.

  1. /dev/tty현재 제어 터미널과 같습니다 /dev/pts/2.

    $ echo hello > /dev/tty
    hello
    
    $ cat < /dev/tty
    world
    world
    ^C
    
  2. 그러나 이 파일들은 서로 심볼릭 링크나 하드 링크라기보다는 관련이 없는 파일인 것 같습니다.

    $ 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
    

서로 다른 제어 터미널을 사용하는 서로 다른 세션의 /dev/tty경우 제어 터미널이 보장됩니다. 어떻게 심볼릭 링크나 하드 링크가 아닌 다른 제어 터미널이 될 수 있습니까?

그렇다면 그들의 연관성과 차이점은 무엇입니까? 어떤 도움이라도 대단히 감사하겠습니다!

이 글은 이전 글에서 따왔습니다'tty' 명령의 출력과 '/dev/tty' 파일이 현재 bash 프로세스의 제어 터미널을 가리키나요?

답변1

tty섹션 4의 맨페이지주장은 다음과 같습니다.

문서/dev/tty메이저 장치번호 5번, 마이너 장치번호 0번, 평소 모드는 0666, 소유자는 root.tty인 캐릭터 파일입니다. 이는 프로세스의 제어 터미널(있는 경우)과 동의어입니다.

와는 별개로ioctl(2)tty가 가리키는 장치에서 지원되는 요청ioctl(2)TIOCNOTTY지원 요청.

TIOCNOTTY

제어 터미널에서 호출 프로세스를 분리합니다.

프로세스가 세션 리더인 SIGHUP경우 SIGCONT신호는 전경 프로세스 그룹으로 전송되고 현재 세션의 모든 프로세스는 제어 tty를 잃습니다.

이것ioctl(2)호출은 연결된 파일 설명자에서만 작동합니다. /dev/tty. 사용자가 터미널에서 데몬을 호출할 때 데몬에 의해 사용됩니다. 프로세스가 열려고 시도합니다./dev/tty. 열기에 성공하면 터미널에서 자체적으로 분리되는 데 사용되는 TIOCNOTTY반면, 열기에 실패하면 분명히 터미널에 연결되지 않으며 자체적으로 분리할 필요가 없습니다.

이는 /dev/tty심볼릭 링크가 제어 터미널이 아닌 이유를 부분적으로 설명할 수 있습니다. 첨부 파일을 지원하고 ioctl제어 터미널이 없을 수도 있습니다(그러나 프로세스는 항상 액세스를 시도할 수 있습니다 /dev/tty). 그러나 문서가 올바르지 않습니다. 추가 콘텐츠에 ioctl액세스할 수 있을 뿐만 아니라통과하다 /dev/tty(바라보다Mosvi의 답변, 이는 또한 )의 속성에 대해 보다 합리적인 설명을 제공합니다 /dev/tty.

/dev/tty링크를 구현하는 드라이버가 호출 프로세스의 제어 터미널이 무엇인지 결정하므로 링크와 다른 제어 터미널을 나타낼 수 있습니다.

이를 제어 터미널이라고 생각할 수 있으므로 /dev/tty제어 터미널에만 의미 있는 기능을 제공하는 반면 /dev/pts/2등은 일반 터미널이며 그 중 하나는 주어진 프로세스의 제어 터미널이 될 수 있습니다.

답변2

/dev/tty열릴 때 현재 터미널의 핸들을 반환하는 "마법의" 문자 장치입니다.

제어 터미널이 이라고 가정하면 /dev/pts/1via를 통해 열린 파일 설명자 /dev/pts/1와 via를 통해 열린 파일 설명자는 /dev/tty동일한 장치를 참조합니다. 둘 중 하나에 대한 쓰기, 읽기 또는 기타 파일 작업은 동일한 방식으로 발생합니다.

특히, 그들은 동일한 ioctl 세트를 허용하며, 다음을 TIOCNOTTY통해서만 얻을 수 있는 추가 ioctl을 허용하지 않습니다./dev/tty.

ioctl(fd, TIOCNOTTY)터미널을 호출하는 프로세스의 제어 터미널인 경우 터미널을 참조하는 모든 파일 설명자에서 동일한 방식으로 작동합니다.

/dev/tty설명자를 /dev/pts/1열어서 얻은 것인지 여부는 중요하지 않습니다 /dev/ptmx(이 경우 ioctl은 해당 항목에 대해 작동합니다).노예) 또는 최근에는 ioctl(master, TIOCGPTPEER, flags).

예:

$ 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

또한 tty에서 현재 프로세스를 실제로 "분리"하지 않습니다. 프로세스는 여전히 프로세스에서 데이터를 읽을 수 있으며 ^C터미널에서 프로세스를 종료합니다. 세션 리더가 아닌 프로세스에 미치는 유일한 영향은 tty가 더 이상 액세스할 수 없고 /dev/tty더 이상 제어 tty로 나열되지 않는다는 것입니다 /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

[7번째 필드 /proc/<pid>/stat는 tty를 제어하는 ​​장치 ID입니다. 참조 proc(5)]

이를 호출하는 프로세스가 세션 리더인 경우 실제로는 tty에서 세션을 분리하고 SIGHUP세션의 /pair를 포그라운드 프로세스 그룹으로 보냅니다. SIGCONT하지만 그럼에도 불구하고 터미널은아니요종료되었으며, 프로세스가 남아 있으면 프로세스에서 계속 읽을 수 있습니다 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/dev/stdin=> /dev/fd/0=> => /proc/self/fd/0와 같은 심볼릭 링크 는 아닙니다 /dev/pts/0. 그 발명품은 procfs와 같은 가상 동적 파일 시스템보다 먼저 생성되었기 때문입니다(일반적으로 심볼릭 링크보다 먼저 생성됩니다). 많은 프로그램이 특정 의미에 의존하게 되었습니다(예: 제어 터미널에 액세스할 수 없을 때 실패함 /dev/tty).ENODEV

관련 정보