Супервизор Systemd
В прошлом задании мы сделали консольное приложение, которое мониторит файлик и реагирует на его изменения.
У нас есть небольшое неудобство, заключающееся в том, что нам приходится запускать наше приложение вручную.
Чтобы полноценно демонизировать процесс его надо подключить к супервизору. Супервизор — это главный процесс в linux который мониторит все процессы, подчищает некорректно удаленные, а также управляет различными сервисами, логирует их исполнение, следит чтобы они перезапускались в случае непредвиденных ситуаций и т.п.
Для управления супервизором есть две основные команды.
- systemctl – для непосредственного управления сервисами (перезапуск, остановка, проверка статусов)
- journalctl – для просмотре логов
Например, можно запустить команду systemctl list-units --type=service
и увидеть список всех сервисов доступных в системе

В крайнем левом столбце видно название сервисов. Каждому сервису как правило сопоставлена некоторая программа, которую супервизор должен запустить
Чтобы супервизор мог понять кого запускать. Есть специальные файлик описывающие сервис. Мы можем быстро посмотреть файлик сопоставленный сервису если напишем команду
sudo systemctl cat ИМЯ_СЕРВИСА
например можно глянуть сервис который ответственен за общение VirtualBox и нашего линукса
sudo systemctl cat vboxadd.service

В выводе видим две наиболее интересных строчки. Первая это путь к файлу, в котором содержится описание сервиса /lib/systemd/system/vboxadd.service
. Скоро мы сделаем свой такой.
И вторая это строчка, начинающаяся с ExecStart которая собственно и указывает которую команду надо запустить при старте сервиса.
Можно глянуть кстати, что лежит в папке /lib/systemd/system
и увидеть, что там действительно есть такой файлик и еще куча других
каждый отвечает за какой-то свой сервис
Мы можем отредактировать каждый файлик либо прямо через, типа
sudo nano /lib/systemd/system/vboxadd.service
либо используя systemctl, вот так
sudo systemctl edit --full vboxadd.service
Регистрация сервиса
И так, чтобы наш сервис подключить к супервизору создадим файлик my_daemon.service
:

и теперь опишем в него сервис
[Unit]
Description=Заклинатель книг # название сервиса
[Service]
User=m # под каким юзером запускать
# рабочая директория, в ней будет искаться config.txt
WorkingDirectory=/home/m/cpp05
# путь к скомпилированному файлу
ExecStart=/home/m/cpp05/main
[Install]
WantedBy=multi-user.target # хотим, чтобы запускалось при запуске системы
обязательно уберите из файлика все комментарии, иначе он не будет работать. Но прежде прочитайте их внимательно, и адаптируйте значения под свою систему. Если вы просто бездумно скопируете, то, внезапно, ничего работать не будет =О
Теперь нам надо подключить этот файлик к супервизору.
Сначала надо положить его в папку /etc/systemd/system
, чтобы проще было редактировать мы просто создадим ссылку на наш файл вот так:
sudo ln -s $PWD/my_daemon.service /etc/systemd/system
когда создаете ссылку на файл очень важно, чтобы путь к исходному файлу был полный.
Переменная $PWD
как раз хранит полный путь текущей папки.
теперь надо перегрузить кеш сервисов
sudo systemctl daemon-reload
у меня старый демон, который папку мониторит, вот с таким кодом
#include <iostream>
#include <sys/inotify.h>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[])
{
int inotify_fd = inotify_init();
int watch_fd = inotify_add_watch(inotify_fd, "/home/m", IN_MODIFY | IN_CREATE | IN_DELETE);
while (true) {
char buffer[10000];
int length = read(inotify_fd, buffer, 10000);
int i = 0;
while (i < length) {
struct inotify_event *event = (struct inotify_event *)&buffer[i];
if (event->mask & IN_MODIFY) {
cout << "изменился" << event->name << endl;
}
else if (event->mask & IN_CREATE) {
cout << "создали файл" << event->name << endl;
}
i += sizeof(struct inotify_event) + event->len;
}
}
inotify_rm_watch(inotify_fd, watch_fd);
close(inotify_fd);
return 0;
}
Момент истины, запускаем наш сервис:
sudo systemctl start my_daemon.service
теперь попробуем узнать статус нашего сервиса
sudo systemctl status my_daemon.service
если увидим такое

значит все работает =)
Давайте теперь протестируем как он работает

смотреть так что происходит в логах очень неудобно, но к счастью есть альтернативный вариант
Journalctl
Утилита journalctl, позволяет смотреть логи по всему что происходит в системе, в том числе и по нашему демону.
Для просмотра журнала по своему демону надо ввести вот такую команду
sudo journalctl -u my_daemon.service
чтобы выйти из лога нажмите q
если хочется смотреть лог в режиме реального времени, то можно добавит флаг -f (--follow)
sudo journalctl -u my_daemon.service -f
работает практически мгновенно

Кстати, чтобы остановить процесс воспользуетесь командой
sudo systemctl stop my_daemon.service

в логе зафиксируется момент и причина остановки.
И еще один важный момент чтобы ваш демон действительно запустился при перезапуске системы надо активировать сервис командой enable
sudo systemctl enable my_daemon.service
можно попробовать перезапустить систему и проверить что сервис действительно перезапустился.