C-код, чтобы проверить, перенаправлена ​​ли командная строка в /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?

2 ответа

Решение

Если вас интересуют только системы *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] = '\0';

    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 оба устройства с одним и тем же индексом:

#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;
}

Проверка inodes переносима на все 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?

Нет, нет Файл где stderr перенаправляется контролируется оболочкой, которая запускает программу. Программа C не знает об этом.

Если нет, какие-либо предложения, как я мог бы проверить для сценария /dev/null?

Вы можете изменить свою программу так, чтобы она принимала второй аргумент и использовала его как пункт назначения stderr с помощью freopen, Если второй аргумент /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;
}
Другие вопросы по тегам