xref: /lighttpd1.4/src/lighttpd-angel.c (revision e1e713c5)
1 #include "first.h"
2 
3 /**
4  * angel process for lighttpd
5  *
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  * - ...
10  *
11  * it has to stay safe and small to be trustable
12  */
13 
14 #include <sys/wait.h>
15 
16 #include <stdio.h>
17 #include <errno.h>
18 #include <signal.h>
19 #include <unistd.h>     /* _exit() execvp() fork() */
20 
21 #define BINPATH SBIN_DIR"/lighttpd"
22 
23 static volatile sig_atomic_t restart = 0;
24 static pid_t pid = -1;
25 
26 __attribute_cold__
signal_handler(int sig)27 static void signal_handler (int sig)
28 {
29     if (pid <= 0) return;
30 
31     if (sig == SIGHUP) {
32         /* trigger graceful shutdown of lighttpd, then restart lighttpd */
33         sig = SIGINT;
34         restart = -1;
35     }
36 
37     /* forward signal to the child */
38     kill(pid, sig);
39 }
40 
41 __attribute_cold__
signal_setup(void)42 static void signal_setup (void)
43 {
44     signal(SIGCHLD, SIG_DFL);
45     signal(SIGALRM, SIG_DFL);
46 
47     signal(SIGPIPE, SIG_IGN);
48 
49     signal(SIGINT,  signal_handler);
50     signal(SIGTERM, signal_handler);
51     signal(SIGUSR1, signal_handler);
52     signal(SIGHUP,  signal_handler);
53 }
54 
55 __attribute_cold__
main(int argc,char ** argv)56 int main (int argc, char **argv)
57 {
58     UNUSED(argc);
59     *(const char **)&argv[0] = BINPATH;
60   #ifdef __COVERITY__
61     __coverity_tainted_data_sanitize__(argv);
62   #endif
63 
64     signal_setup();
65 
66     do {
67 
68         if (-1 == pid) {
69             pid = fork();
70             if (-1 == pid) return -1;
71             if (0 == pid) {
72                 /* intentionally pass argv params */
73                 /* coverity[tainted_string : FALSE] */
74                 execvp(argv[0], argv);
75                 _exit(1);
76             }
77         }
78 
79         int exitcode = 0;
80         if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) {
81             if (errno == ECHILD) break; /* child exists; should not happen */
82             continue;
83         }
84 
85         const char *msg = NULL;
86         int code = 0;
87         if (WIFEXITED(exitcode)) {
88             code = WEXITSTATUS(exitcode);
89             msg = "%s.%d: child (pid=%d) exited normally with exitcode: %d\n";
90         }
91         else if (WIFSIGNALED(exitcode)) {
92             code = WTERMSIG(exitcode);
93             msg = "%s.%d: child (pid=%d) exited unexpectedly with signal %d, "
94                   "restarting\n";
95             restart = -1;
96         }
97         if (msg)
98             fprintf(stderr, msg, __FILE__, __LINE__, pid, code);
99 
100         pid = restart; /* -1 for restart, 0 to exit */
101         restart = 0;
102 
103     } while (pid != 0);
104 
105     return 0;
106 }
107