Dado que um programa simples:
/* 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);
}
compile-o como ttyname
e invoque-o como init , o resultado será o seguinte:
Inappropriate ioctl for device
o que significa que o código de erro é ENOTTY
.
Por que o fprintf(stderr, ....) pode ser exibido na tela quando stderr
não se refere a um dispositivo terminal?
Se você está invocando-o como,
init
então você não está obtendo saída para a tela; a saída está sendo enviada para o kernel e o kernel está imprimindo na tela.init
é um processo especialVocê pode pensar nisso como semelhante ao seguinte script de shell:
Isso é feito através do
/dev/console
dispositivo; stdin/stdout/stderr para o processo de inicialização são anexados a isso pelo kernel. As gravações nesse dispositivo são tratadas pelo kernel e enviadas para os dispositivos de console atuais, que podem ser o vty atual ou uma porta serial ou outro lugar.O problema é que
ttyname
sempre vai falhar quando o stderr não for um terminal. Portanto, no caso de stderr ser um soquete como potencialmente durante a inicialização, ttyname falha, mas você pode escrever em stderr sem problemas, e é por isso que o fprintf funciona.Você pode obter o nome do soquete fazendo o que ttyname faz e que está
readlink
em /proc/self/fd/FD com "FD" sendo 2 para stderr normalmente.