用于检查命令行是否重定向到 /dev/null 的 C 代码
C code to check if command line is redirected to /dev/null
我正在编写一个 C 程序,输出到 stdout
,错误输出到 stderr
。该程序接受如下命令:
./myprogram function_to_run file_to_read
我的程序可以输出到 stdout
或被定向到输出一个文件,但不能被重定向到 /dev/null
。例如:
./myprogram function_to_run file_to_read //OK
./myprogram function_to_run file_to_read > file.txt //OK
./myprogram function_to_run file_to_read > /dev/null // NOT OK, should produce error in stderr
我尝试使用 isatty(1)
,但它只能检测 stdout
是否正在输出到终端。因此,对于 stdout
被重定向到文件的情况,它失败了,这在我的情况下是可以接受的
有没有办法在 C 中检查这个?如果没有,有什么建议可以检查 /dev/null 场景吗?
Is there a way to check for this in C?
不,没有。 stderr
被重定向的文件由运行该程序的 shell 控制。 C 程序对此一无所知。
If not, any suggestion how I could check for the /dev/null scenario?
您可以更改您的程序以接受第二个参数,并使用 freopen
将其用作 stderr
的目标。如果第二个参数是 /dev/null
,你可能会出错。
if ( strcmp(argv[2], "/dev/null") == 0 )
{
// Deal with error.
return EXIT_FAILURE;
}
if (freopen(argv[2], "w", stderr) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
如果您只对 *nix 系统感兴趣,那么一种解决方案是检查 /proc/self/fd/1
链接到什么。下面是一个执行此操作的示例程序(为简洁起见省略了错误检查)。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main (void)
{
char link[256];
ssize_t rval;
rval = readlink("/proc/self/fd/1", link, sizeof(link));
link[rval] = '[=10=]';
if (!strcmp(link, "/dev/null")) {
assert(!"Redirect to /dev/null not allowed!");
} else {
printf("All OK\n");
}
return 0;
}
样本测试运行:
$ ./a.out
All OK
$ ./a.out > some_file
$ cat some_file
All OK
$ ./a.out > /dev/null
a.out: test.c:14: main: Assertion `!"Redirect to /dev/null not allowed!"' failed.
Aborted (core dumped)
$
检查标准输出是否重定向到 /dev/null
的快速方法是检查 STDOUT_FILENO
和 /dev/null
是否都是具有相同 inode 的设备:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int main()
{
struct stat std_out;
struct stat dev_null;
if (fstat(STDOUT_FILENO, &std_out) == 0 &&
S_ISCHR(std_out.st_mode) &&
stat("/dev/null", &dev_null) == 0 &&
std_out.st_dev == dev_null.st_dev &&
std_out.st_ino == dev_null.st_ino)
{
fprintf(stderr, "Redirect to /dev/null not allowed!\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "All OK\n");
return 0;
}
检查 inode 是否可移植到所有类 Unix 系统:
$ ./a.out
All OK
$ ./a.out | cat
All OK
$ ./a.out > /dev/null
Redirect to /dev/null not allowed!
我们不应该依赖/proc/self/fd/1
。并非所有类 Unix 系统都支持它,特别是 Mac OS X Darwin 和一些 BSD 变体。
我正在编写一个 C 程序,输出到 stdout
,错误输出到 stderr
。该程序接受如下命令:
./myprogram function_to_run file_to_read
我的程序可以输出到 stdout
或被定向到输出一个文件,但不能被重定向到 /dev/null
。例如:
./myprogram function_to_run file_to_read //OK
./myprogram function_to_run file_to_read > file.txt //OK
./myprogram function_to_run file_to_read > /dev/null // NOT OK, should produce error in stderr
我尝试使用 isatty(1)
,但它只能检测 stdout
是否正在输出到终端。因此,对于 stdout
被重定向到文件的情况,它失败了,这在我的情况下是可以接受的
有没有办法在 C 中检查这个?如果没有,有什么建议可以检查 /dev/null 场景吗?
Is there a way to check for this in C?
不,没有。 stderr
被重定向的文件由运行该程序的 shell 控制。 C 程序对此一无所知。
If not, any suggestion how I could check for the /dev/null scenario?
您可以更改您的程序以接受第二个参数,并使用 freopen
将其用作 stderr
的目标。如果第二个参数是 /dev/null
,你可能会出错。
if ( strcmp(argv[2], "/dev/null") == 0 )
{
// Deal with error.
return EXIT_FAILURE;
}
if (freopen(argv[2], "w", stderr) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
如果您只对 *nix 系统感兴趣,那么一种解决方案是检查 /proc/self/fd/1
链接到什么。下面是一个执行此操作的示例程序(为简洁起见省略了错误检查)。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main (void)
{
char link[256];
ssize_t rval;
rval = readlink("/proc/self/fd/1", link, sizeof(link));
link[rval] = '[=10=]';
if (!strcmp(link, "/dev/null")) {
assert(!"Redirect to /dev/null not allowed!");
} else {
printf("All OK\n");
}
return 0;
}
样本测试运行:
$ ./a.out
All OK
$ ./a.out > some_file
$ cat some_file
All OK
$ ./a.out > /dev/null
a.out: test.c:14: main: Assertion `!"Redirect to /dev/null not allowed!"' failed.
Aborted (core dumped)
$
检查标准输出是否重定向到 /dev/null
的快速方法是检查 STDOUT_FILENO
和 /dev/null
是否都是具有相同 inode 的设备:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int main()
{
struct stat std_out;
struct stat dev_null;
if (fstat(STDOUT_FILENO, &std_out) == 0 &&
S_ISCHR(std_out.st_mode) &&
stat("/dev/null", &dev_null) == 0 &&
std_out.st_dev == dev_null.st_dev &&
std_out.st_ino == dev_null.st_ino)
{
fprintf(stderr, "Redirect to /dev/null not allowed!\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "All OK\n");
return 0;
}
检查 inode 是否可移植到所有类 Unix 系统:
$ ./a.out
All OK
$ ./a.out | cat
All OK
$ ./a.out > /dev/null
Redirect to /dev/null not allowed!
我们不应该依赖/proc/self/fd/1
。并非所有类 Unix 系统都支持它,特别是 Mac OS X Darwin 和一些 BSD 变体。