Изучая Си. Первая программа.

Мне повезло, у меня была конкертная задача. На реализацию я потратил ~4 дней. Что слишком долго для задачи, но.. Это моя первая программа.

Задача: написать генератор конфигурационных файлов для связки бекенд(nginx)-фронтенд(apache22) которые работают на одном сервере.

У нас уже была реализация этой системы. Работает это так. В БД mysql через вебинтерфейс заносится информация о домене. Хранится

  • document_root
  • domain
  • aliases — через перенос строки
  • server — номер сервера
  • updated
  • updated_nginx

updated и updated_nginx устанавляиваются в 1 когда происходит обновление или добавление домена.

Конфигурация виртуальных хостов типичная и является шаблоном.

В общем задача

  • Принять и обработать аргументы командной строки. При этом число обязательных аргументов должно быть минимально.
  • Прочитать конфигурацию соеденения с mysql сервером. Она хранится в файле. Там-же хранится номер сервера.
  • Получить из БД mysql все домены которые нужно обновить и сложить в структуру.
  • Пройтись по этим доменам циклом. Сгенерить для каждого конфигурацию по шаблону. Обновить поля updated дабы показать что мы сделали конфигурацию.
  • Пройтись по директории содержащий конфиги и сгенерить конфигурационный файл содержащий include со всеми файлами в директории.
  • Перезагрузить вебсервер, дабы тот подхватил новую конфигурацию.

Строки и стандартные функции

Во-первых я не сразу понял как принято работать со строками в Си. Для конкатенации строк я использовал функции из библиотеки libstrfunc. Выглядит это уродливо

sbuf_add(selectQueryWhere, "server=");
sbuf_add(selectQueryWhere, server->buf);
if (isApache) {
if (isUpdateAll==0)
sbuf_add(selectQueryWhere, " and updated=1");

Вместо таких замудрений можно было использовать подстановку через
sprintf();

Либо копирование в строковой буфер с проверкой длины через функции стандартной библиотеки strcpy, strcat..

char b_aliases[BSIZE];
// Clean \r\n from alias
strcpy(b_aliases, replace(domain.aliases, "\r\n", " "));

Действительно для чего полезна библиотека libstrfunc это функция replace.

О длине кол-ве элементов в массиве

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

Тут есть такой момент.. Здесь про **указатель указателей с примером кода.

Об обработки параметров через getopt_long

Муторное это занятие доложу я вам. Т.е. само то сделать приём аргументов не вопрос. А вот сделать что-бы оно работало по принципу
Если есть соответствующий аргумент, использвать его, в противном случае значение по-умолчанию.
Кроме того я сделал так что обязательным для программы является один параметр режим. Он может быть —nginx или —apache. Об остальном программа может догадаться сама.


static char* usageStr =
"Usage: %s [OPTION]... [--nginx | --apache]\n"
" -h, --help This screen\n"
" -v, --verbose Show debug messages\n"
"\n"
" -n, --nginx Use nginx configuration\n"
" -a, --apache Use apache configuration\n"
//" -d, --pid Override path to PID file\n"
" -r, --cmd_restart Command for restarting webserver\n"
"\n"
" -t, --vhost_templ Override path to vhost template\n"
" -p, --vhosts_path
Override path to vhosts configuration files\n"
" -i, --vhosts_index Override path to vhosts configuration index file\n"
"\n"
" -c, --config Override domenka config file\n"
" -l, --update_all Ignore updated status\n"
" -s, --server Override domenka serverId domenka\n"
"\n";


const char* DEFAULT_VHOSTS_TEMPL_APACHE = "/usr/local/etc/domenka/apache.templ";
const char* DEFAULT_VHOSTS_TEMPL_NGINX = "/usr/local/etc/domenka/nginx.templ";
//
const char* DEFAULT_VHOST_INDEX_APACHE = "/usr/local/etc/apache22/hosting.conf";
const char* DEFAULT_VHOST_INDEX_NGINX = "/usr/local/etc/nginx/hosting.conf";
//
const char* DEFAULT_VHOSTS_PATH_APACHE = "/usr/local/etc/apache22/hosting";
const char* DEFAULT_VHOSTS_PATH_NGINX = "/usr/local/etc/nginx/hosting";
//
/*
const char* DEFAULT_PID_APACHE = "/var/run/httpd.pid";
const char* DEFAULT_PID_NGINX = "/var/run/nginx.pid";
*/
//
const char* DEFAULT_CMD_RESTART_APACHE = "/usr/local/etc/rc.d/apache22 restart";
const char* DEFAULT_CMD_RESTART_NGINX = "/usr/local/etc/rc.d/nginx restart";
//
const char* DEFAULT_CONFIG = "/usr/local/etc/domenka/hosting.conf";

О перезагрузке сервера

Сервер перегружать через передачу сигнала HUP по id получается только один раз. Я хотел получать PID через правильные файлы, /var/run/httpd.pid, /var/run/nginx.pid, но после HUP, как и следовало ожидать, pid содержащийся в этих файлах не соответвут реальному.

Есть вариант перегружать по-имени процесса. Но для nginx это не катит потому как нужно гасить только мастер процесс.

Я сделал с использованием стартовых скриптов etc/rc.d/

Об ошибках и отладке

Программа умеет делать —verbose сообщая откуда она планирует брать шаблоны, конфиг, складывать конфигурацию виртуальных хостов, генерировать индексный файл и какой сервер использовать для получения информации по доменам.

Кроме того на все вещи вроде файл или директория не найдены, выдаётся вменяемая ошибка.

А на отсутвие обязательного параметра режим, выдаётся хелп ключей и соответвующее поясняющее сообщение.

Чего не хватает
Инсталлятора не хватает. Нужно освоить Make, autoconf. Так-же пакеты и порты во FreeBSD. :)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *