[core] calloc plugin_config for consistent init
[lighttpd.git] / src / lighttpd-angel.c
blob2b88e554e65a25fda16df24403efc5d396c41404
1 #include "first.h"
3 /**
4 * angel process for lighttpd
6 * the purpose is the run as root all the time and handle:
7 * - restart on crash
8 * - spawn on HUP to allow graceful restart
9 * - ...
11 * it has to stay safe and small to be trustable
14 #include <sys/wait.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <time.h>
22 #include <signal.h>
24 #define BINPATH SBIN_DIR"/lighttpd"
26 static siginfo_t last_sigterm_info;
27 static siginfo_t last_sighup_info;
29 static volatile sig_atomic_t start_process = 1;
30 static volatile pid_t pid = -1;
32 #define UNUSED(x) ( (void)(x) )
34 static void sigaction_handler(int sig, siginfo_t *si, void *context) {
35 int exitcode;
37 UNUSED(context);
38 switch (sig) {
39 case SIGINT:
40 case SIGTERM:
41 case SIGUSR1:
42 if (pid <= 0) break;
43 memcpy(&last_sigterm_info, si, sizeof(*si));
45 /** forward the sig to the child */
46 kill(pid, sig);
47 break;
48 case SIGHUP: /** do a graceful restart */
49 if (pid <= 0) break;
50 memcpy(&last_sighup_info, si, sizeof(*si));
52 /** do a graceful shutdown on the main process and start a new child */
53 kill(pid, SIGINT);
55 usleep(5 * 1000); /** wait 5 microsec */
57 start_process = 1;
58 break;
59 case SIGCHLD:
60 /** a child died, de-combie it */
61 wait(&exitcode);
62 break;
66 int main(int argc, char **argv) {
67 int is_shutdown = 0;
68 struct sigaction act;
70 UNUSED(argc);
72 /**
73 * we are running as root BEWARE
76 memset(&act, 0, sizeof(act));
77 act.sa_handler = SIG_IGN;
78 sigaction(SIGPIPE, &act, NULL);
79 sigaction(SIGUSR1, &act, NULL);
81 act.sa_sigaction = sigaction_handler;
82 sigemptyset(&act.sa_mask);
83 act.sa_flags = SA_SIGINFO;
85 sigaction(SIGINT, &act, NULL);
86 sigaction(SIGTERM, &act, NULL);
87 sigaction(SIGUSR1, &act, NULL);
88 sigaction(SIGHUP, &act, NULL);
89 sigaction(SIGALRM, &act, NULL);
90 sigaction(SIGCHLD, &act, NULL);
92 /* check that the compiled in path has the right user,
94 * BEWARE: there is a race between the check here and the exec later
97 while (!is_shutdown) {
98 int exitcode = 0;
100 if (start_process) {
101 pid = fork();
103 if (0 == pid) {
104 /* i'm the child */
106 argv[0] = BINPATH;
108 execvp(BINPATH, argv);
110 exit(1);
111 } else if (-1 == pid) {
112 /** error */
114 return -1;
117 /* I'm the angel */
118 start_process = 0;
121 if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) {
122 switch (errno) {
123 case EINTR:
124 /* someone sent a signal ...
125 * do we have to shutdown or restart the process */
126 break;
127 case ECHILD:
128 /**
129 * make sure we are not in a race between the signal handler
130 * and the process restart */
131 if (!start_process) is_shutdown = 1;
132 break;
133 default:
134 break;
136 } else {
137 /** process went away */
139 if (WIFEXITED(exitcode)) {
140 /** normal exit */
142 is_shutdown = 1;
144 fprintf(stderr, "%s.%d: child (pid=%d) exited normally with exitcode: %d\n",
145 __FILE__, __LINE__,
146 pid,
147 WEXITSTATUS(exitcode));
149 } else if (WIFSIGNALED(exitcode)) {
150 /** got a signal */
152 fprintf(stderr, "%s.%d: child (pid=%d) exited unexpectedly with signal %d, restarting\n",
153 __FILE__, __LINE__,
154 pid,
155 WTERMSIG(exitcode));
157 start_process = 1;
162 return 0;