Это более высокоуровневый способ работы с процессами, более удобный, чем вручную использовать execl() и fork().
Функция system() принимает параметром команду, которую нужно выполнить, также как мы пишем ее в терминале.
Внутри себя она использует:
fork()для создания копии текущего процесса.execl()для замещения этой копии процесса на другую программу.
Находится в заголовке <stdlib.h>.
process_system.c:
Ссылка
Эта простая программа выполняет touch zika.txt в отдельном дочернем процессе, используя функцию system().
Простой вызов system() выполняет внутри себя fork() а потом execl(). Посмотрите еще раз, как с ними работать в предыдущих разделах, и вы поймете ее лаконичность, ограничиваясь только одним вызовом system() он внутри себя делает всю неприятную работу.
int system_result = system("touch zika.txt");
if( system_result == -1)
{
perror("some error in command.");
exit(1);
}
exit(0);При вызове этой программы, произойдет следующее:
- Создется новый, дочерний процесс.
- В этом дочернем отдельном процессе выполнится
touch zika.txt - В итоге мы имеем файл
zika.txt, там, где вызвали нашу программу.
Фоновый процесс, также называемый демоном (daemon). Он запускается в ОС и выполняет какие-то задачи.
Примеры демонов:
- веб-серверы - nginx, apache.
- ssh - сервис, который помогает удаленно управлять ОС, в безопасном режиме.
Демоны уже не делают вручную (!!!)
Далее будет описан примерный план создания своего демона, однако в большинстве систем есть менеджер сервисов, например
systemd.
С этим менеджером можно создавать сервисы и управлять ими. Не нужно возиться сfork'ами, можно делать перезапуск, есть логи и так далее, все удобства.То есть мы только берем программу, создаем из нее сервис c помощью
systemdи все, фоновый сервис готов!
Демон создается через fork() , но "ритуал" создания демона отличается от просто создания дочернего процесса, выглядит он так:
- С помощью функции
setsid(), разрывается связь с управляющим терминалом (tty), чтобы его нельзя было отменить черезCTRL+D. - Делается двойной (double-forking)
fork(), дочерний процесс создает еще один процесс, чтобы демон точно не был лидером сессии. - Все унаследованные дескрипторы закрываются или перенаправляются (STDIN, STDOUT, STDERR и так далее).
- Меняется рабочая директория на основную -
"/", функциейchdir(), чтобы демон не держал точку монтирования. - Сбрасывается маска прав через функцию
umask(0), чтобы не зависеть от родителя.
Итого, чтобы демон стал полностью независимым и автономным, нужно оторвать его от наследований. Процесс становится демоном, когда он вручную "оторван" от:
- Терминала
- Сессии
- Унаследованных дескрипторов
НО! используйте вместо этого systemd !!!
Тот самый главный процесс с идентификатором 1 это systemd !
- Демоны обрабатываются c помощью специальных файлов unit files.
- Логирование обрабатывается с помощью journald
Чтобы увидеть все активные фоновые юниты (units):
systemctlВсе сервисы (юнит-файлы) размещаются в /lib/systemd/system .
Чтобы увидеть журнал логов от сервисов:
sudo journalctlprocess_system_daemon:
Ссылка
Программа каждые 5 секунд пишет в stderr сообщение. Если ее запустить из терминала, то сообщения будут видны в терминале.
Это самый банальный пример процесса-демона, который каждые N секунд что-то делает.
Когда эта программа будет работать как сервис через systemd она будет выводит свои сообщения в файлы логов. И работать в фоне, не завися от терминала.
Такие программы, должны обрабатывать сигналы и ОС, чтобы понять что делать при получении сигнала.
/* .... */
static void on_signal(int sig)
{
/* to supress unsused warning */
(void)sig;
g_stop = 1;
}
/* .... *//* .... */
struct sigaction sa = {0};
sa.sa_handler = on_signal;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
/* .... */В нашем случае, при любом из сигналов SIGINT (прерывание) или SIGTERM (прекращение) , происходит изменение атомарной переменной g_stop, которая сигнализирует о том, что цикл программы (в котором она каждые 5 секунд делает вывод сообщений) нужно остановить:
while(!g_stop)
{
log_line("[my_daemon] XXX tick=%lu", tick);
tick++;
sleep_monotonic(interval);
}Затем программу нужно собрать:
cc -O2 -Wall -Wextra -pedantic process_system_daemon.c -o process_system_daemonИ отправить в /usr/local/bin , чтобы запускать ее из systemd:
cp process_system_daemon /usr/local/bin/process_system_daemonЧтобы systemd понимал что делать с программой, создается юнит-файл, где описывается информация о программе.
touch process_system_daemon.serviceВнутри должны быть минимальные параметры для создания сервиса:
Описание сервиса
[Unit] Description=Simple XXX test daemon
Конфигурация сервиса
Type- тип сервиса.ExecStart- команда для запуска (путь к исполняемому и аргументы).Restart- событие для перезапуска.RestartSec- время перезапуска.StandardOutput- стрим для стандартного вывода (идет в журнал логов!).StandardError- стрим для вывода ошибок (идет в журнал логов!).[Service] Type=simple ExecStart=/usr/local/bin/process_system_daemon 3 Restart=on-failure RestartSec=2s StandardOutput=journal StandardError=journal
Поведение при установке сервиса
При запускеsystemctl enable ...будет создан симлинк для работы сервиса.[Install] WantedBy=multi-user.target
Теперь это файл process_system_daemon.service нужно скопировать в папку с сервисами systemd:
sudo cp process_system_daemon.service /etc/systemd/system/process_system_daemon.serviceТеперь, когда необходимые файлы готовы по путям:
- Исполняемый файл программы -
/usr/local/bin/process_system_daemon - Юнит-файл -
/etc/systemd/system/process_system_daemon.service
Можно запустить сервис:
sudo systemctl daemon-reload
sudo systemctl enable --now process_system_daemon.serviceПроверяем статус:
sudo systemctl status process_system_daemon.serviceВывод о статусе должен содержать active и enabled, означающие что сервис запущен и включен.
Примерно так:
● process_system_daemon.service - Simple XXX test daemon
Loaded: loaded (/etc/systemd/system/process_system_daemon.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/service.d
└─10-timeout-abort.conf
Active: active (running) since Thu 2025-09-25 17:32:51 MSK; 40s ago
Сервис запущен и работает, можно посмотреть на его логи из журнала:
journalctl -u process_system_daemon.serviceВидно те самые логи, которые мы отправляем из демона:
Sep 25 17:32:51 192-168-0-116.local process_system_daemon[7901]: [my_daemon] XXX start pid=7901, interval=3.000 sec
Sep 25 17:32:51 192-168-0-116.local process_system_daemon[7901]: [my_daemon] XXX tick=1
Sep 25 17:32:54 192-168-0-116.local process_system_daemon[7901]: [my_daemon] XXX tick=2
Sep 25 17:32:57 192-168-0-116.local process_system_daemon[7901]: [my_daemon] XXX tick=3
...Перезапуск
sudo systemctl restart process_system_daemon.service
Остановка
sudo systemctl stop process_system_daemon.service
Удаление
sudo systemctl disable --now process_system_daemon.service sudo systemctl stop process_system_daemon.service sudo rm /usr/local/bin/process_system_daemon sudo rm /etc/systemd/system/process_system_daemon.service sudo systemctl reset-failed sudo systemctl daemon-reload