stderr이 터미널 장치를 참조하지 않는 경우 fprintf(stderr, ....)가 화면에 출력될 수 있는 이유는 무엇입니까?

stderr이 터미널 장치를 참조하지 않는 경우 fprintf(stderr, ....)가 화면에 출력될 수 있는 이유는 무엇입니까?

간단한 프로그램이 주어지면:

/* ttyname.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char **argv)
{
  char **tty = NULL;

  tty = ttyname(fileno(stderr));
  if (tty == NULL)
    {
      fprintf(stderr, "%s\n", strerror(errno));
      exit(EXIT_FAILURE);
    }

  printf("%s\n", tty);
  
  exit(EXIT_SUCCESS);
}

다음과 같이 컴파일하고 ttyname다음과 같이 호출합니다.내부에, 결과는 다음과 같습니다.

Inappropriate ioctl for device

이는 오류 코드가 임을 의미합니다 ENOTTY. 터미널 장치가 관련되지 않은 경우
fprintf(stderr, ....)가 stderr화면에 출력될 수 있는 이유는 무엇입니까?

답변1

init이렇게 부르면아니요출력을 화면에 인쇄합니다. 출력은 커널로 전송되어 화면에 인쇄됩니다. init특별한 과정이다

다음 쉘 스크립트와 유사하다고 생각하면 됩니다.

$ x=$(ttyname 2>&1)
$ echo $x
Inappropriate ioctl for device

이는 /dev/console장치를 통해 수행됩니다. init 프로세스의 stdin/stdout/stderr은 커널에 의해 여기에 연결됩니다. 이 장치에 대한 쓰기는 커널에 의해 처리되고 현재 vty 또는 직렬 포트 또는 다른 곳일 수 있는 현재 콘솔 장치로 전송됩니다.

답변2

문제는 ttynamestderr이 터미널이 아닐 때 항상 실패한다는 것입니다. 따라서 시작 중에 stderr이 소켓일 수 있으면 ttyname은 실패하지만 문제 없이 stderr에 쓸 수 있으므로 fprintf가 작동합니다.

/proc/self/fd/FD에 있는 ttyname을 수행하여 소켓 이름을 얻을 수 있습니다. readlink여기서 "FD"는 일반적으로 2(stderr의 경우)입니다.

  char tty[1024];

  ssize_t size = readlink("/proc/self/fd/2", tty, sizeof(tty)-1);
  if (size < 0)
    {
      fprintf(stderr, "%s\n", strerror(errno));
      exit(EXIT_FAILURE);
    }

  tty[size] = 0;

  printf("%s\n", tty);

관련 정보