간단한 프로그램이 주어지면:
/* 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
문제는 ttyname
stderr이 터미널이 아닐 때 항상 실패한다는 것입니다. 따라서 시작 중에 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);