2013-03-07 13 views
3

Есть ли способ итерации через уже открытые дескрипторы файла (открытые родительским процессом) и закрытие их один за другим в дочернем процессе?Закрытие открытых файловых дескрипторов в дочернем процессе

ОС: Unix.

Причина закрытия: предел RLIMIT_NOFILE для setrlimit() ограничивает количество файловых дескрипторов, которые может выделить процесс. Если мы хотим ограничить наш дочерний процесс, установив этот предел, это зависит от уже выделенных файловых дескрипторов.

Попытка установить этот предел в дочернем процессе ограничена, поскольку родительский процесс имеет некоторые открытые файловые дескрипторы, и поэтому мы не можем установить этот предел меньше этого числа.

Пример: Если родительский процесс имеет 10 дескрипторов файлов, и мы хотим ограничить число дескрипторов файла дочернего процесса менее 10 (скажем 3), нам нужно будет закрыть 7 дескрипторов файлов внутри дочернего процесса.

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

+0

* "Если родительский процесс имеет 10 файловых дескрипторов, выделенных ... «*: что означает« выделение »для вас? Поскольку дескрипторы файлов открываются или закрываются. Распределение слов связано с управлением памятью ... – thkala

+0

Исправление: я хотел сказать 10 Открытые файловые дескрипторы родительского процесса, спасибо за исправление thkala – learner

ответ

3

Следующая идиома не редкость (это взято из части С MIMEDefang):

/* Number of file descriptors to close when forking */ 
#define CLOSEFDS 256 
... 

static void 
closefiles(void) 
{ 
    int i; 
    for (i=0; i<CLOSEFDS; i++) { 
     (void) close(i); 
    } 
} 

Это что-то хак (как код MIMEDefang свободно допускает). Во многих случаях более полезно начинать с FD 3 (или STDERR_FILENO+1) вместо 0. close() возвращает EBADF с недопустимым FD, но это обычно не представляет проблем (по крайней мере, не на C, на других языках может быть выбрано исключение).

Так как вы можете определить верхний предел файла дескриптора с getrlimit(RLIMIT_NOFILE,...) который defined как:

RLIMIT_NOFILE

Это номер один больше, чем максимальное значение, которое система может назначить вновь -созданный дескриптор. Если этот предел превышен, функции, которые выделяют файловый дескриптор, должны завершиться ошибкой с установкой errno в значение [EMFILE]. Этот предел ограничивает количество файловых дескрипторов, которые может выделить процесс.

Вы можете использовать это (вычитая 1) в качестве верхнего предела цикла. Вышеуказанные и ulimit -n, getconf OPEN_MAX и sysconf(OPEN_MAX) должны все согласиться.

С open() всегда присваивает самый низкий свободный FD, максимальное количество открытых файлов и самый высокий FD + 1 - это то же самое число.

libslack daemon utility, который использует демонические процессы, также использует этот подход (при условии, что первые три дескриптора сохраняются при использовании под inetd).

В случае, когда ваша программа может отслеживать файловые дескрипторы, это предпочтительнее, или используйте FD_CLOEXEC, если таковые имеются. Однако, если вы хотите защищать код, вы можете предпочесть недоверие к своему родительскому процессу, скажем, при запуске внешнего обработчика/процесса просмотра, запущенного браузером, например. как это 12 15 year old Mozilla bug на Unix.

Для параноидально (вы хотите, чтобы ваш зритель PDF наследовать каждый открытый Firefox FD, включая кэш, и открытые соединения TCP):

#!/bin/bash 
# you might want to use the value of "ulimit -n" instead of picking 255 
for ((fd=3; fd<=255; fd++)); do 
    exec {fd}<&- # close 
done 
exec /usr/local/bin/xpdf "[email protected]" 
+0

Очень информативный ответ. – Grodriguez

0

Насколько я знаю, нет общего способа перебора открытых дескрипторов файлов в Unix/POSIX. Традиционный способ справиться с проблемой, которую вы описываете, - отслеживать их в своем собственном коде, если необходимо, с использованием структуры данных, такой как массив или список, и закрывать их в дочернем процессе после fork(), но до exec().

Некоторые операционные системы, однако, предлагают потенциальное решение, если вы вызываете exec() после создания дочернего процесса. Либо setting the FD_CLOEXEC flag for a file descriptor using fcntl(), либо с флагом O_CLOEXEC для open() операционной системе поручено закрыть этот конкретный файловый дескриптор перед вызовом exec(). Вам нужно будет проконсультироваться с документацией вашей целевой операционной системы, чтобы узнать, поддерживается ли и какой из этих флагов.

+0

Могу ли я пропустить число дескрипторов файла от 0 до MAX ДОПУСКАЕМЫХ файловых дескрипторов и выполнить вызов на выходе функции dup (int fildes)? Поскольку dup(), если не удалось, возвращает '-1'. Это плохой способ, или это еще один грубый способ узнать информацию, которую я ищу? – learner

+0

@ user2136293: в вашем предложении есть * много * допущений, которые могут и будут нарушать ваш код: 1. Вы предполагаете, что можете достоверно узнать, что такое максимальный номер FD. Помимо MAX_INT нет другого надежного предела. 2. Вы предполагаете, что это число будет «разумным». Вы собираетесь исследовать 2^31 ФД? 3. вы предполагаете, что можете вслепую 'закрыть()' любой дескриптор файла, который вам не нравится. Что делать, если одна из ваших библиотек хранит открытый FD по какой-то определенной причине? – thkala

+0

@ user2136293: Что же вы пытаетесь сделать в любом случае? [Какова ваша реальная проблема?] (Http://mywiki.wooledge.org/XyProblem) – thkala

Смежные вопросы