diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-04-20 11:35:45 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-04-20 12:18:41 +0300 |
commit | 44a3ae866bf949b0ca5106ecfb8c5e3fda4b9af8 (patch) | |
tree | 5eb53b9505aba56a58848faf15ea7c2b996f7fb0 | |
parent | e8caefcc1b1a19abfca6a1e0a7dfea4af2761b53 (diff) | |
download | fileserv-44a3ae866bf949b0ca5106ecfb8c5e3fda4b9af8.tar.gz fileserv-44a3ae866bf949b0ca5106ecfb8c5e3fda4b9af8.tar.bz2 |
Start a sentinel process by default.
* src/fileserv.c (http_server)
(http_sentinel): New functions.
(main): New command line option -s (single process).
Start sentinel unless -s is given.
-rw-r--r-- | src/fileserv.c | 200 |
1 files changed, 165 insertions, 35 deletions
diff --git a/src/fileserv.c b/src/fileserv.c index f354460..fece526 100644 --- a/src/fileserv.c +++ b/src/fileserv.c @@ -18,6 +18,8 @@ #include "mimetypes.h" #include <string.h> #include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> #include <sys/select.h> #include <netdb.h> #include <signal.h> @@ -25,7 +27,6 @@ #include <time.h> #include <ctype.h> - #ifndef DEFAULT_ADDRESS # define DEFAULT_ADDRESS "0.0.0.0" #endif @@ -605,15 +606,6 @@ fileserv_error_printer (char const *msg) error("%s", msg); } -int -main(int argc, char **argv) -{ - int c, i; - int fd = -1; - struct MHD_Daemon *mhd; - struct sockaddr *server_addr; - int foreground = 0; - sigset_t sigs; static int fatal_signals[] = { SIGHUP, SIGINT, @@ -622,6 +614,160 @@ main(int argc, char **argv) 0 }; +static void +http_server(int fd, struct sockaddr *server_addr) +{ + struct MHD_Daemon *mhd; + sigset_t sigs; + int i; + + /* Block the 'fatal signals' and SIGPIPE in the handling thread */ + sigemptyset(&sigs); + for (i = 0; fatal_signals[i]; i++) + sigaddset(&sigs, fatal_signals[i]); + sigaddset(&sigs, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &sigs, NULL); + MHD_set_panic_func(fileserv_panic, NULL); + + mhd = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD + | MHD_USE_ERROR_LOG, 0, + fileserv_acl, server_addr, + fileserv_handler, NULL, + MHD_OPTION_LISTEN_SOCKET, fd, + MHD_OPTION_EXTERNAL_LOGGER, fileserv_logger, + NULL, + MHD_OPTION_END); + /* Unblock only the fatal signals */ + sigdelset(&sigs, SIGPIPE); + pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); + /* Wait for signal to arrive */ + sigwait(&sigs, &i); + MHD_stop_daemon(mhd); +} + +enum state { + RUNNING, /* Program is running */ + TERMINATING, /* Program is terminating */ + CHILD_TERM, /* SIGTERM has been sent to the child */ + CHILD_KILL +}; +volatile enum state state; + +static void +sigterm(int sig) +{ + if (state == RUNNING) + state = TERMINATING; +} + +static void +sigalrm(int sig) +{ + if (state == CHILD_TERM) + state = CHILD_KILL; +} + +static void +http_sentinel(int fd, struct sockaddr *server_addr) +{ + pid_t pid = 0; + int i; + struct sigaction act; + + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + act.sa_handler = sigalrm; + sigaction(SIGALRM, &act, NULL); + + for (i = 0; fatal_signals[i]; i++) + sigaddset(&act.sa_mask, fatal_signals[i]); + act.sa_handler = sigterm; + for (i = 0; fatal_signals[i]; i++) + sigaction(fatal_signals[i], &act, NULL); + + while (1) { + int status; + pid_t child_pid; + + if (pid == 0) { + if (state != RUNNING) + break; + pid = fork(); + if (pid == -1) { + error("fork: %s", strerror(errno)); + break; + } + if (pid == 0) { + runas(user, group); + http_server(fd, server_addr); + exit(0); + } + } + + if (child_pid > 0) { + child_pid = 0; + if (WIFEXITED(status)) { + int code = WEXITSTATUS(status); + if (code || verbose > 1) + error("child exited with status %d", + code); + } else if (WIFSIGNALED(status)) { + char const *coremsg = ""; +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + coremsg = " (core dumped)"; +#endif + error("child terminated on signal %d%s", + WTERMSIG(status), coremsg); + } else if (WIFSTOPPED(status)) { + error("child stopped on signal %d", + WSTOPSIG(status)); + continue; + } else { + error("child terminated with unrecognized status %d", status); + } + /* restart the child */ + pid = 0; + continue; + } + + switch (state) { + case RUNNING: + break; + + case TERMINATING: + kill(pid, SIGTERM); + alarm(5); + state = CHILD_TERM; + break; + + case CHILD_TERM: + break; + + case CHILD_KILL: + kill(pid, SIGKILL); + return; + } + + child_pid = wait(&status); + if (child_pid == -1) { + if (errno != EINTR || verbose > 1) + error("wait: %s", strerror(errno)); + } + } +} + +int +main(int argc, char **argv) +{ + int c, i; + int fd = -1; + struct sockaddr *server_addr; + int foreground = 0; + int single_process = 0; + progname = basename(argv[0]); mimetypes_error_printer = fileserv_error_printer; @@ -629,7 +775,7 @@ main(int argc, char **argv) if (!tmpdir) tmpdir = "/tmp"; - while ((c = getopt(argc, argv, "c:fhv")) != EOF) { + while ((c = getopt(argc, argv, "c:fshv")) != EOF) { switch (c) { case 'c': config_file = optarg; @@ -637,6 +783,9 @@ main(int argc, char **argv) case 'f': foreground = 1; break; + case 's': + single_process = 1; + break; case 'h': usage(); exit(0); @@ -658,6 +807,7 @@ main(int argc, char **argv) fd = open_listener(address, &server_addr); + if (single_process) runas(user, group); for (i = optind; i < argc; i++) @@ -669,8 +819,6 @@ main(int argc, char **argv) } if (!foreground) { - int i; - if (daemon(0, 1)) { error("daemon failed: %s", strerror(errno)); exit(1); @@ -681,29 +829,11 @@ main(int argc, char **argv) } pidfile_create(); - /* Block the 'fatal signals' and SIGPIPE in the handling thread */ - sigemptyset(&sigs); - for (i = 0; fatal_signals[i]; i++) - sigaddset(&sigs, fatal_signals[i]); - sigaddset(&sigs, SIGPIPE); - - pthread_sigmask(SIG_BLOCK, &sigs, NULL); - MHD_set_panic_func(fileserv_panic, NULL); + if (single_process) + http_server(fd, server_addr); + else + http_sentinel(fd, server_addr); - mhd = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD - | MHD_USE_ERROR_LOG, 0, - fileserv_acl, server_addr, - fileserv_handler, NULL, - MHD_OPTION_LISTEN_SOCKET, fd, - MHD_OPTION_EXTERNAL_LOGGER, fileserv_logger, - NULL, - MHD_OPTION_END); - /* Unblock only the fatal signals */ - sigdelset(&sigs, SIGPIPE); - pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); - /* Wait for signal to arrive */ - sigwait(&sigs, &c); - MHD_stop_daemon(mhd); pidfile_remove(); return 0; } |