Как установить close-on-exec по умолчанию

Я реализую библиотеку для запуска команд. Библиотека C, в Linux.

В настоящее время выполняется вызов popen() для запуска команды и получения вывода. Проблема в том, что команда наследует все обработчики открытых файлов в настоящее время.

Если я сделал fork/exec, я мог явно закрыть обработчики в дочернем элементе. Но это означает повторное внедрение popen().

Можно ли установить close-on-exec на всех обработчиках, не перебирая их один за другим?

Можно ли установить close-on-exec по умолчанию для процесса?

Спасибо!

Ответы

Ответ 1

Нет и нет.

Вам просто нужно быть осторожным и устанавливать close-on-exec во всех файловых дескрипторах, о которых вы заботитесь.

Настройка легко:

#include <fcntl.h>
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

#include <unistd.h>
/* please don't do this */
for (i = getdtablesize(); i --> 3;) {
    if ((flags = fcntl(i, F_GETFD)) != -1)
        fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}

Если вы используете Linux kernel & ge; 2.6.23 и glibc & ge; 2.7, open (наряду с другими подобными системными вызовами) принимает новый флаг O_CLOEXEC:

#include <unistd.h>
fd = open("...", ... | O_CLOEXEC);

Если вы используете Linux kernel & ge; 2.6.24 и glibc & ge; 2.7, fcntl принимает новый аргумент F_DUPFD_CLOEXEC:

#include <fcntl.h>
newfd = fcntl(oldfd, F_DUPFD_CLOEXEC);

Если вы используете Linux kernel & ge; 2.6.27 и glibc & ge; 2.9, появляются новые syscalls pipe2, dup3 и т.д., а многие другие системные вызовы получают новые флаги *_CLOEXEC:

#define _GNU_SOURCE
#include <unistd.h>
pipe2(pipefds, O_CLOEXEC);
dup3(oldfd, newfd, O_CLOEXEC);

Обратите внимание, что POSIX указывает, что

Функция popen() должна гарантировать, что любые потоки из предыдущих popen() вызовов, которые остаются открытыми в родительском процессе, закрываются в новом дочернем процессе.

так что если вы беспокоитесь об этой утечке, не делайте этого.

Ответ 2

Расскажите о старом вопросе, но как насчет использования getpid() в child после fork(), затем загляните в каталог /proc/PID/fd/ и просто закройте все дескрипторы, которые вы там найдете (кроме 0, 1, 2 и тот, который вы получаете от opendir()), а затем execve()?