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:
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:
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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>