鉴于一个简单的程序:
/* 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
是一个特殊的过程
您可以将其视为类似于以下 shell 脚本:
$ x=$(ttyname 2>&1)
$ echo $x
Inappropriate ioctl for device
这是通过/dev/console
设备完成的; init 进程的 stdin/stdout/stderr 由内核附加到此。对该设备的写入由内核处理并发送到当前控制台设备,该设备可能是当前的 vty 或串行端口或其他地方。
答案2
问题是ttyname
当 stderr 不是终端时总是会失败。因此,如果 stderr 可能是启动期间的套接字,则 ttyname 会失败,但您可以毫无问题地写入 stderr,这就是 fprintf 工作的原因。
您可以通过执行 ttyname 的操作来获取套接字名称,该名称位于readlink
/proc/self/fd/FD 上,其中“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);