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