I'm writing a C program that outputs to stdout
and errors to stderr
. The program takes a command such as:
./myprogram function_to_run file_to_read
My program can either output to stdout
or be directed to output a file, but it must not be redirected to /dev/null
. For example:
./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
I tried to use isatty(1)
, but it only can detect if stdout
is outputting to a terminal. Therefore, it fails for the case where stdout
is redirected to a file, which is acceptable in my case
Is there a way to check for this in C? If not, any suggestion how I could check for the /dev/null scenario?
If you are only interested in *nix systems then one solution is to check what /proc/self/fd/1
is linked to. Below is a sample program that does that (error checking omitted for brevity).
#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] = '\0';
if (!strcmp(link, "/dev/null")) {
assert(!"Redirect to /dev/null not allowed!");
} else {
printf("All OK\n");
}
return 0;
}
Sample test runs:
$ ./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)
$
A quick way to check that standard output is redirected to /dev/null
is to check that STDOUT_FILENO
and /dev/null
are both devices with the same 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;
}
Checking the inodes is portable to all Unix-like systems:
$ ./a.out
All OK
$ ./a.out | cat
All OK
$ ./a.out > /dev/null
Redirect to /dev/null not allowed!
We should not rely on /proc/self/fd/1
. It is not supported by all Unix-like systems, notably Mac OS X Darwin and some BSD variants.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With