■ Функция error() сообщает о фатальной ошибке, произошедшей в программе. При этом в поток stderr записывается сообщение об ошибке, и работа программы завершается. Для ошибок, произошедших в системных вызовах или библиотечных функциях, предназначена функция system_error(), которая генерирует сообщение об ошибке на основании значения переменной errno (см. раздел 2.2.3, "Коды ошибок системных вызовов").
■ Функция get_self_executable_directory() определяет каталог, в котором содержится исполняемый файл текущего процесса. Это позволяет программе находить свои внешние компоненты. Функция проверяет содержимое символической ссылки /proc/self/exe (см. раздет 7.2.1, "Файл /proc/self).
В файле common.c определены также две полезные глобальные переменные.
■ Переменная program_name содержит имя выполняемой программы, указанное в списке аргументов командной строки (см. раздел 2.1.1, "Список аргументов").
■ Переменная verbose не равна нулю, если программа работает в режиме выдачи развернутых сообщений. В таком случае многие компоненты будут записывать в поток stdout сообщения о ходе выполнения задачи.
11.2.2. Загрузка серверных модулей
В файле module.c (листинг 11.3) содержится реализация динамически загружаемых серверных модулей. Загруженному модулю соответствует структура типа server_module, который определен в файле server.h.
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "server.h"
char* module_dir;
struct server_module* module_open(const char* module_name) {
char* module_path;
void* handle;
void (*module_generate)(int);
struct server_module* module;
/* Формирование путевого имени библиотеки, в которой содержится
загружаемый модуль. */
module_path =
(char*)xmalloc(strlen(module_dir) +
strlen(module_name) + 2);
sprintf(module_path, "%s/%s", module_dir, module_name);
/* Попытка открыть файл MODULE_PATH как совместно используемую
библиотеку. */
handle = dlopen(module_path, RTLD_NOW);
free (module_path);
if (handle == NULL) {
/* Ошибка: либо путь не существует, либо файл не является
совместно используемой библиотекой. */
return NULL;
}
/* Чтение константы module_generate из библиотеки. */
module_generatе =
(void(*)int))dlsym(handle,
"module_generate");
/* Проверяем, найдена ли константа. */
if (module_generate == NULL) {
/* Константа отсутствует в библиотеке. Очевидно, файл не
является серверным модулем. */
dlclose(handle);
return NULL;
}
/* Выделение и инициализация объекта server_module. */
module =
(struct server_module*)xmalloc
(sizeof (struct server_module));
module->handle = handle;
module->name = xstrdup(module_name);
module->generate_function = module_generate;
/* Успешное завершение функции. */
return module;
}
void module_close(struct server_module* module) {
/* Закрытие библиотеки. */
dlclose(module->handle);
/* Удаление строки с именем модуля. */
free((char*)module->name);
/* Удаление объекта module. */
free(module);
}
Каждый модуль содержится в файле совместно используемой библиотеки (см. раздел 2.3.2, "Совместно используемые библиотеки") и должен экспортировать функцию module_generate(). Эта функция генерирует HTML-код Web-страницы и записывает его в сокет, дескриптор которого передан ей в качестве аргумента.
В файле module.c определены две функции.
■ Функция module_open() пытается загрузить серверный модуль с указанным именем. Файл модуля имеет расширение .so, так как это совместно используемая библиотека. Функция открывает библиотеку с помощью функции dlopen() и ищет в библиотеке константу module_generate посредством функции dlsym() (описаны в разделе 2.3.6, "Динамическая загрузка и выгрузка"). Если библиотеку не удалось открыть или в ней не обнаружена экспортируемая константа module_generate, возвращается значение NULL. В противном случае выделяется и возвращается объект module.