Я пытаюсь управлять программой-демоном C из другой программы пользовательского пространства.
- Простой демон C
Этот демон - просто программа на C, которая демонизирует себя и регистрирует сообщение каждую секунду через syslog.
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
void bye();
int main()
{
printf("Daemon starting ...\n");
openlog("daemon-test", LOG_PID, LOG_DAEMON);
signal(SIGTERM, bye);
if(0 != daemon(0, 0))
{
syslog(LOG_ERR, "Can't daemonize\n");
return EXIT_FAILURE;
}
syslog(LOG_INFO, "Daemon started !\n");
while(1)
{
syslog(LOG_INFO, "Daemon alive\n");
sleep(1);
}
return EXIT_SUCCESS;
}
void bye()
{
syslog(LOG_INFO, "Daemon killed !\n");
exit(EXIT_SUCCESS);
}
- Запуск и уничтожение демона из программы C test
Для целей тестирования я разработал минимальный пример. Я использую popen
для запуска демона, потому что я хочу, чтобы моя программа продолжила выполнение.
Через 5 секунд тестовая программа должна убить демона.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define DAEMON_NAME "daemon-test"
int main()
{
FILE* pipe = NULL;
int i = 0;
printf("Launching '%s' program\n", DAEMON_NAME);
if(NULL == (pipe = popen(DAEMON_NAME, "re")))
{
printf("An error occured launching '%s': %m\n", DAEMON_NAME);
return EXIT_FAILURE;
}
printf("Program '%s' launched\n", DAEMON_NAME);
while(i<5)
{
printf("Program alive !\n");
sleep(1);
i++;
}
if(NULL == (pipe = popen("killall " DAEMON_NAME, "re")))
{
printf("An error occured killing '%s' program: %m\n", DAEMON_NAME);
return EXIT_FAILURE;
}
printf("Program '%s' killed\n", DAEMON_NAME);
return EXIT_SUCCESS;
}
Журнал программы испытаний:
$ ./popenTest
Launching 'daemon-test' program
Program 'daemon-test' launched
Program alive !
Program alive !
Program alive !
Program alive !
Program alive !
Program 'daemon-test' killed
Syslog:
Jun 25 13:58:15 PC325 daemon-test[4445]: Daemon started !
Jun 25 13:58:15 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:16 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:17 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:18 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:19 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:20 PC325 daemon-test[4445]: Daemon alive
Jun 25 13:58:20 PC325 daemon-test[4445]: Daemon killed !
Так что я могу запустить и убить демона из моей программы на C, однако я бы хотел улучшить поведение в некоторых конкретных случаях.
- Обработка аварии демона
В какой-то момент демон может выйти из строя, в этом случае управляющая программа должна быть уведомлена, чтобы ее можно было перезапустить. Моя проблема в том, чтобы обнаружить, что демон остановлен.
Хотя я имею в виду запуск потока, ожидающего завершения демона с помощью вызова pclose
, однако он не будет работать, поскольку демонизация уже закрыла файловые дескрипторы и отсоединила процесс.
Так что я ищу лучший способ уведомления программы о выходе из демона.
Я мог бы опросить с помощью вызовов Linux с exec
семейством (например, pgrep daemon-test
или ps aux | grep daemon-test
), но я думаю, что есть более эффективный способ добиться этого.
- Ошибка обработки тестовой программы
Если тестовая программа убита или дает сбой до того, как она убьет демона, при следующем выполнении два экземпляра демона будут запущены одновременно.
Журнал программы испытаний:
$ ./popenTest
Launching 'daemon-test' program
Program 'daemon-test' launched
Program alive !
Program alive !
Program alive !
^C
$ ./popenTest
Launching 'daemon-test' program
Program 'daemon-test' launched
Program alive !
Program alive !
Program alive !
Program alive !
Program alive !
Program 'daemon-test' killed
Syslog:
Jun 25 14:17:25 PC325 daemon-test[4543]: Daemon started !
Jun 25 14:17:25 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:26 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:27 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:28 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:29 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:29 PC325 daemon-test[4547]: Daemon started !
Jun 25 14:17:29 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:30 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:30 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:31 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:31 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:32 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:32 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:33 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:33 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:34 PC325 daemon-test[4543]: Daemon alive
Jun 25 14:17:34 PC325 daemon-test[4547]: Daemon alive
Jun 25 14:17:34 PC325 daemon-test[4543]: Daemon killed !
Jun 25 14:17:34 PC325 daemon-test[4547]: Daemon killed !
Я хочу избежать этой ситуации, проверив, запущены ли уже экземпляры демонов. Если нет, я могу запустить демон из управляющей программы.
В противном случае, если запущен один или несколько экземпляров демона, я убью их перед запуском нового.
Этого можно достичь, вызвав killall daemon-test
, но вызов этой команды при каждом выполнении меня не удовлетворяет, поскольку в большинстве случаев она бесполезна.
Кроме того, я хотел бы явно регистрировать ситуацию при каждом выполнении, и хотя я хочу точно знать, сколько экземпляров было запущено в этом случае.
Еще раз это можно легко решить с помощью командных вызовов linux, но я ищу наиболее эффективный способ сделать это.
Кто-нибудь знает, как можно реализовать управление процессами демона, не полагаясь на вызовы команд linux?
РЕДАКТИРОВАТЬ: 26 июня 2018
Я должен был уточнить его с самого начала, но моя цель - иметь возможность отслеживать процесс демона без необходимости изменять его код.
Таким образом, демон не записывает свой pid в файл и всегда отсоединяется от вызывающего.