summaryrefslogtreecommitdiff
path: root/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c
diff options
context:
space:
mode:
Diffstat (limited to 'data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c')
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c b/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c
new file mode 100644
index 000000000..189c1b92a
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/lighttpd-angel.c
@@ -0,0 +1,167 @@
+#include "first.h"
+
+/**
+ * angel process for lighttpd
+ *
+ * the purpose is the run as root all the time and handle:
+ * - restart on crash
+ * - spawn on HUP to allow graceful restart
+ * - ...
+ *
+ * it has to stay safe and small to be trustable
+ */
+
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+
+#define BINPATH SBIN_DIR"/lighttpd"
+
+static siginfo_t last_sigterm_info;
+static siginfo_t last_sighup_info;
+
+static volatile sig_atomic_t start_process = 1;
+static volatile pid_t pid = -1;
+
+#define UNUSED(x) ( (void)(x) )
+
+static void sigaction_handler(int sig, siginfo_t *si, void *context) {
+ int exitcode;
+
+ UNUSED(context);
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGUSR1:
+ if (pid <= 0) break;
+ memcpy(&last_sigterm_info, si, sizeof(*si));
+
+ /** forward the sig to the child */
+ kill(pid, sig);
+ break;
+ case SIGHUP: /** do a graceful restart */
+ if (pid <= 0) break;
+ memcpy(&last_sighup_info, si, sizeof(*si));
+
+ /** do a graceful shutdown on the main process and start a new child */
+ kill(pid, SIGINT);
+
+ usleep(5 * 1000); /** wait 5 microsec */
+
+ start_process = 1;
+ break;
+ case SIGCHLD:
+ /** a child died, de-combie it */
+ wait(&exitcode);
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ int is_shutdown = 0;
+ struct sigaction act;
+
+ UNUSED(argc);
+ *(const char **)&argv[0] = BINPATH;
+ #ifdef __COVERITY__
+ __coverity_tainted_data_sanitize__(argv);
+ #endif
+
+ /**
+ * we are running as root BEWARE
+ */
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+
+ act.sa_sigaction = sigaction_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+ sigaction(SIGCHLD, &act, NULL);
+
+ /* check that the compiled in path has the right user,
+ *
+ * BEWARE: there is a race between the check here and the exec later
+ */
+
+ while (!is_shutdown) {
+ int exitcode = 0;
+
+ if (start_process) {
+ pid = fork();
+
+ if (0 == pid) {
+ /* i'm the child */
+
+ /* intentionally pass argv params */
+ /* coverity[tainted_string : FALSE] */
+ execvp(argv[0], argv);
+ _exit(1);
+ } else if (-1 == pid) {
+ /** error */
+
+ return -1;
+ }
+
+ /* I'm the angel */
+ start_process = 0;
+ }
+
+ if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) {
+ switch (errno) {
+ case EINTR:
+ /* someone sent a signal ...
+ * do we have to shutdown or restart the process */
+ break;
+ case ECHILD:
+ /**
+ * make sure we are not in a race between the signal handler
+ * and the process restart */
+ if (!start_process) is_shutdown = 1;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /** process went away */
+
+ if (WIFEXITED(exitcode)) {
+ /** normal exit */
+
+ is_shutdown = 1;
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited normally with exitcode: %d\n",
+ __FILE__, __LINE__,
+ pid,
+ WEXITSTATUS(exitcode));
+
+ } else if (WIFSIGNALED(exitcode)) {
+ /** got a signal */
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited unexpectedly with signal %d, restarting\n",
+ __FILE__, __LINE__,
+ pid,
+ WTERMSIG(exitcode));
+
+ start_process = 1;
+ }
+ }
+ }
+
+ return 0;
+}
+