I'm trying to control a C daemon program from another userspace program.
- Simple C daemon
This daemon is simply a C program which daemonize itself and log a message every second through 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);
}
- Launching and killing the daemon from a C test program
For test purpose I have developped a minimal example. I'm using popen
to launch the daemon because I want my program to continue its execution.
After 5 seconds, the test program is supposed to kill the daemon.
#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;
}
Test program log:
$ ./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 !
So I'm able to launch and kill the daemon from my C program, however I would like to improve the behaviour in some specific cases.
- Handling daemon crash
The daemon may fail at some point, in that case the control program should be notified so it can be relaunched. My problem is to detect that the daemon has been stopped.
I have though about launching a thread waiting for daemon termination by a call to pclose
, however it won't work as the daemonization has already closed file descriptors and detached the process.
So I'm looking for the best way to have the program notified on daemon exit.
I could poll using linux calls with exec
family (such as pgrep daemon-test
or ps aux | grep daemon-test
) but I think there are more efficient way to achieve that.
- Handling test program error
If the test program is killed or fails before it kills the daemon, at next execution, two instances of the daemon will run at the same time.
Test program log:
$ ./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 !
I want to avoid this situation by checking if there are already daemon instances running. If not I can launch the daemon from control program.
Otherwise if one or several instances of the daemon are running I shall kill them before launching a new one.
This could be achieved by calling killall daemon-test
but calling this command at each execution doesn't satisfy me because it's useless most of the time.
Moreover I would like to explicitly log the situation at each execution and though I want to know exactly how many instances were running in that case.
Once again this can be resolved easilly using linux command calls, but I'm looking for the most efficient way to do it.
Does anybody knows how I could implement daemon process control without having to rely on linux command calls ?
EDIT: June 26th 2018
I should have precised it from the beginning but my aim is to be able to monitor the daemon process without having to modify its code.
So the daemon doesn't write its pid to a file and is always detached from its caller.