Перенаправить разветвленный вывод процесса в NULL - PullRequest
4 голосов
/ 27 марта 2012

Мне нужно создать функцию, которая, помимо прочего, порождает дочерний процесс. Я хотел бы передать этой функции дополнительный список файловых дескрипторов, чтобы, в зависимости от потребностей пользователя, ввод / вывод дочернего процесса можно было перенаправить.

Я видел, как десятки людей говорили о том, как сделать это, используя dup2 примерно так:

if( pid < 0 )   // error forking.
{
//...
}
else if( pid != 0 ) // Parent process.
{
    ret = waitpid( pid, &status, 0 );
    return  WEXITSTATUS( status );
}
else    // Child process.
{
    dup2( fd, STDIN_FILENO );   // Clone passed file discriptor.
    close( fd );            // Close the passed one, since we have already cloned.
    execvp( arglist[ 0 ], arglist );
}

Хорошо. Все это есть в интернете. Теперь у меня вопрос: как (или как лучше всего) перенаправить на /dev/null?

Должен ли я заставить пользователя open( /dev/null) и передать его как fd или есть какой-нибудь лучший способ?


EDIT:

Это не так красиво, как мне хотелось, но я не мог найти лучшего способа, поэтому я в итоге передал массив имен файлов туда, куда пользователь мог захотеть перенаправить, соответственно, STDIN, STDOUT и STDERR:

static int  do_exec( arglist_t arglist, const char *fio[ 3 ] )
{
DEBUG__( OSU_DEBUG_LEVEL_1, "fio = %p\n", fio );

    if ( fio )
    {
        if ( fio[ STDIN_FILENO ] )
        {
            int fd = open( fio[ STDIN_FILENO ], O_RDONLY );

            if ( -1 < fd )
            {
                dup2( fd, STDIN_FILENO );
                close( fd );
            }
        }

        if ( fio[ STDOUT_FILENO ] )
        {
            int fd = open( fio[ STDOUT_FILENO ], O_WRONLY | O_CREAT | O_APPEND );

            if ( -1 < fd )
            {
                dup2( fd, STDOUT_FILENO );
                close( fd );
            }
        }

        if ( fio[ STDERR_FILENO ] )
        {
            int fd = open( fio[ STDERR_FILENO ], O_WRONLY | O_CREAT | O_APPEND );

            if ( -1 < fd )
            {
                dup2( fd, STDERR_FILENO );
                close( fd );
            }
        }
    }

    return  execvp( arglist[ 0 ], arglist );
}
  • Я еще не полностью протестировал его, поэтому в нем могут быть некоторые ошибки.

Действительно благодаря @Zack и @ gbulmer.

Ответы [ 2 ]

4 голосов
/ 27 марта 2012

Вы могли бы иметь в качестве соглашения вашего API, что передача -1 для fd означает использование /dev/null и выполнение

// ... same as you have ...

else // Child process
{
    if (stdin_fd == -1)
        stdin_fd = open("/dev/null", O_RDONLY);
    if (stdin_fd == -1)
        _exit(127);
    dup2(stdin_fd, STDIN_FILENO);
    close(stdin_fd);

    // similarly for stdout and stderr

    execvp(arglist[0], arglist);
    _exit(127);
}

(Psst: Каждый раз, когда вы ставите пробелы внутри скобок, Бог убивает котенка.)

1 голос
/ 27 марта 2012

Дочернему процессу необходимо знать, какие fd'ы использовать в качестве oldfd для dup2 и какие fd для dup2.

Например, почему fd будет dup2 для STDIN_FILENO?

Ребенку нужна информация для открытого fd, и для fd, на который он должен быть dup2'd.

Чтобы обобщить, охватить случаи, когда обрабатываются имена файлов, а не только fd,у вас будет возможность сказать «/ dev / null», поскольку это реальное имя файла.

Так что просто получите список struct { int oldfd; char* filename; int newfd; } структур, и задание будет обычным, и / dev / nullэто не частный случай.Когда oldfd равен -1, откройте имя файла в newfd вместо dup2'ing на него.

...