lighttpd 1.4.x
https://www.lighttpd.net/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
3.0 KiB
154 lines
3.0 KiB
/** |
|
* 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 sig_atomic_t graceful_restart = 0; |
|
static volatile pid_t pid = -1; |
|
|
|
static void sigaction_handler(int sig, siginfo_t *si, void *context) { |
|
int exitcode; |
|
|
|
switch (sig) { |
|
case SIGINT: |
|
case SIGTERM: |
|
memcpy(&last_sigterm_info, si, sizeof(*si)); |
|
|
|
/** forward the sig to the child */ |
|
kill(pid, sig); |
|
break; |
|
case SIGHUP: /** do a graceful restart */ |
|
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; |
|
|
|
/** |
|
* 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(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 */ |
|
|
|
argv[0] = BINPATH; |
|
|
|
execvp(BINPATH, 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; |
|
} |
|
|
|
|