-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdaemon.c
More file actions
145 lines (126 loc) · 4.34 KB
/
daemon.c
File metadata and controls
145 lines (126 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "daemon.h"
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
static int WATCHDOG_EXIT; /**< Flag for exiting the respawn-loop */
static pid_t SERVICE_PID; /**< Currently active pid for the service */
/** Signal handler for the watchdog. Forwards bound signals. If a SIGTERM
* is passed, the WATCHDOG_EXIT flag is flipped so that we stop
* respawning.
* \param sig The signal to deliver.
*/
void watchdog_sighandler (int sig) {
if (sig == SIGTERM) WATCHDOG_EXIT=1;
kill (SERVICE_PID, sig);
signal (sig, watchdog_sighandler);
}
/** Implementation of the watchdog process, responsible for spawning,
* and respawning, of the actual service process, and for forwarding
* relevant signals sent to its pid (which is what ends up in the
* pidfile).
* \param argc The libc argc
* \param argv The libc argv
* \param call The main function to run the service.
*/
void watchdog_main (int argc, const char *argv[], main_f call) {
WATCHDOG_EXIT = 0;
SERVICE_PID = 0;
pid_t pid;
int retval;
do {
switch (pid = fork()) {
case -1:
sleep (60); /* nothing sane to do here */
continue;
case 0:
signal (SIGTERM, SIG_DFL);
signal (SIGHUP, SIG_DFL);
signal (SIGUSR1, SIG_DFL);
exit (call (argc, argv));
return;
default:
signal (SIGTERM, watchdog_sighandler);
signal (SIGHUP, watchdog_sighandler);
signal (SIGUSR1, watchdog_sighandler);
SERVICE_PID = pid;
break;
}
sleep (1); /* Prevent a respawn bomb */
while (wait (&retval) != SERVICE_PID) {
if (WATCHDOG_EXIT) break;
}
} while (! WATCHDOG_EXIT);
}
/** Fork the process into the background, with a watchdog guarding its
* execution. If the --foreground flag is provided in argv[1], no
* daemonization will take place, and execution will be switched to
* the main function directly. Signals intended for the service
* process should be sent to the watchdog, which will forward the
* signal (and recuse itself from respawning in case of SIGTERM).
* \param pidfilepath Path and filename of the pidfile to save.
* \param argc The libc argc
* \param argv The libc argv
* \param call The main function to run the service.
* \return 0 on failure, 1 on success (caller should exit).
*/
int daemonize (const char *pidfilepath, int argc,
const char *argv[], main_f call, int foreground) {
pid_t pwatchdog;
pid_t pwrapper;
FILE *pidfile;
char pidbuf[128];
if (foreground) {
(void) call (argc, argv);
return 1;
}
/* Make sure we're not already running */
pidfile = fopen (pidfilepath, "r");
if (pidfile != NULL) {
fread (pidbuf, 128, 1, pidfile);
fclose (pidfile);
pidbuf[127] = 0;
pwatchdog = atoi (pidbuf);
if (pwatchdog && (kill (pwatchdog, 0) == 0)) {
fprintf (stderr, "Already running\n");
return 0;
}
}
/* Create an outer fork that allows us to detach from the group */
switch (pwrapper = fork()) {
case -1:
fprintf (stderr, "Fork failed\n");
break;
case 0:
/* Sever ties to active terminals */
close (0);
close (1);
close (2);
open ("/dev/null", O_RDONLY);
open ("/dev/null", O_WRONLY);
open ("/dev/null", O_WRONLY);
/* Fork off the watchdog process */
switch (pwatchdog = fork()) {
case -1:
exit (1);
case 0:
watchdog_main (argc, argv, call);
unlink (pidfilepath);
exit (0);
break;
default:
pidfile = fopen (pidfilepath, "w");
fprintf (pidfile, "%i", pwatchdog);
fclose (pidfile);
break;
}
break;
default:
return 1;
}
return 0;
}