Наиболее удобным способом является установка флага закрытия после выполнения для каждого файла, который программа оставляет открытым на длительный период времени (включая сокеты и файловые устройства), что предотвращает получение доступа к данным файлам новыми запускаемыми программами. Описание флага закрытия после выполнения можно найти в главе 11.
22.4. Запуск в качестве демона
При разработке программ, создаваемых для работы в качестве системных демонов, нужно очень внимательно проводить их становление как демонов для правильного определения всех деталей. Ниже приведен перечень тех обстоятельств, на которые необходимо обратить внимание.
1. Большинство действий по инициализации должны быть произведены до того, как программа становится фактическим демоном. Это гарантирует, что пользователь при запуске не будет получать сообщения об ошибках, и будет возвращаться значащий код завершения. Этот вид деятельности включает в себя анализ конфигурационных файлов и открытие сокетов.
2. Текущий каталог должен быть изменен на какой-либо подходящий. Это может быть корневой каталог, но никогда не может быть тот каталог, из которого была запущена программа. Если демон этого не сделает, то, возможно, он будет работать соответствующим образом, но это не позволяет удалить тот каталог, из которого он был активизирован, поскольку он остается текущим каталогом программы. Если это возможно, то неплохо применить chroot()
на какой-то каталог. Причины обсуждались ранее в этой главе.
3. Все ненужные файловые дескрипторы должны быть закрыты. Это может показаться очевидным, однако вы легко можете упустить закрытие тех дескрипторов, которые были унаследованы, а не открыты самой программой. Об этом речь шла в предыдущем разделе.
4. Затем программа должна вызвать fork()
, а родительский процесс должен вызвать exit()
, позволяя программе, запустившей демон (чаще всего командному процессору), продолжить работу.
5. Дочерний процесс, продолжающий работу, должен закрыть stdin, stdout и stderr, поскольку он не будет больше использовать терминал. Вместо повторного применения файловых дескрипторов 0, 1 и 2 лучше открывать эти файлы как /dev/null
. Это гарантирует, что ни одна библиотечная функция, передающая отчеты о состоянии ошибок в stdout или stderr, не запишет эти ошибки в другие файлы, открытые демоном. При этом демон сможет запускать внешние программы, не беспокоясь об их выходных данных.
6. Для полного разъединения с терминалом, из которого был запущен демон, он должен вызвать setsid()
, чтобы разместить его в собственной группе процесса. Это предотвращает получение сигналов при закрытии терминала, а также сигналов управления заданиями.
Библиотека С предлагает функцию daemon()
, которая обрабатывает некоторые из перечисленных задач.
int daemon(int nochdir, in tnoclose);
Данная функция сразу осуществляет ветвление, и если оно прошло успешно, родительский процесс вызывает _exit()
с кодом завершения 0. Затем дочерний процесс переходит в корневой каталог, если nochdir
не является нулем, и перенаправляет stdin, stdout и stderr в /dev/null
, если noclose
не равен нулю. Перед возвратом в дочерний процесс она также вызывает setsid()
. При этом унаследованные файловые дескрипторы все равно могут оставаться открытыми, поэтому в программах, использующих daemon()
, необходимо следить за ними. Если возможно, в программе также нужно использовать chroot()
.
Часть IV
Библиотеки для разработки
Глава 23
Сопоставление строк
Осуществлять сравнение строк можно не только с помощью функции strcmp()
или даже strncmp()
. Linux предлагает несколько общих функций сопоставления строк, использование которых позволяет упростить решение задач программирования. Мы рассмотрим сначала самые простые примеры, а затем перейдем к более сложным.
23.1. Универсализация произвольных строк
В главе 14 мы говорили о том, как с помощью функции glob()
производится универсализация имен файлов, однако пользователи, знакомые с возможностями универсализации, нередко пытаются применить их и к другим разновидностям строк. Функция fnmatch()
позволяет применять правила универсализации в отношении произвольных строк:
#include
int fnmatch(const char * pattern, const char * string, int flags);
Предложенный шаблон является стандартным выражением универсализации с четырьмя специальными символами, за которые отвечает аргумент flags
.
Читать дальше